@finesoft/front 0.1.39 → 0.1.42

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.
Files changed (41) hide show
  1. package/dist/app-re7jUCuM.mjs +178 -0
  2. package/dist/app-re7jUCuM.mjs.map +1 -0
  3. package/dist/index.d.mts +1276 -0
  4. package/dist/index.d.mts.map +1 -0
  5. package/dist/index.mjs +2749 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/locale-D2Bu7w47.mjs +27 -0
  8. package/dist/locale-D2Bu7w47.mjs.map +1 -0
  9. package/dist/rolldown-runtime-wcPFST8Q.mjs +13 -0
  10. package/dist/server-peer-modules-BSSsxBaF.d.mts +41 -0
  11. package/dist/server-peer-modules-BSSsxBaF.d.mts.map +1 -0
  12. package/package.json +21 -32
  13. package/README.md +0 -1136
  14. package/dist/app-XEMPAI6H.js +0 -10
  15. package/dist/app-XEMPAI6H.js.map +0 -1
  16. package/dist/browser.cjs +0 -1465
  17. package/dist/browser.cjs.map +0 -1
  18. package/dist/browser.d.cts +0 -904
  19. package/dist/browser.d.ts +0 -904
  20. package/dist/browser.js +0 -115
  21. package/dist/browser.js.map +0 -1
  22. package/dist/chunk-4PPCVAKZ.js +0 -463
  23. package/dist/chunk-4PPCVAKZ.js.map +0 -1
  24. package/dist/chunk-OYTIGVEG.js +0 -193
  25. package/dist/chunk-OYTIGVEG.js.map +0 -1
  26. package/dist/chunk-PSPVIVC2.js +0 -25
  27. package/dist/chunk-PSPVIVC2.js.map +0 -1
  28. package/dist/chunk-SDPWQT2T.js +0 -936
  29. package/dist/chunk-SDPWQT2T.js.map +0 -1
  30. package/dist/chunk-XQ3UWZOS.js +0 -187
  31. package/dist/chunk-XQ3UWZOS.js.map +0 -1
  32. package/dist/index.cjs +0 -3661
  33. package/dist/index.cjs.map +0 -1
  34. package/dist/index.d.cts +0 -582
  35. package/dist/index.d.ts +0 -582
  36. package/dist/index.js +0 -1648
  37. package/dist/index.js.map +0 -1
  38. package/dist/locale-CAZ4INCX.js +0 -7
  39. package/dist/locale-CAZ4INCX.js.map +0 -1
  40. package/dist/src-XNC7QNVI.js +0 -21
  41. package/dist/src-XNC7QNVI.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../core/src/actions/types.ts","../../core/src/actions/dispatcher.ts","../../core/src/intents/dispatcher.ts","../../core/src/dependencies/container.ts","../../core/src/logger/base.ts","../../core/src/logger/local-storage-filter.ts","../../core/src/logger/console.ts","../../core/src/dependencies/make-dependencies.ts","../../core/src/router/router.ts","../../core/src/logger/composite.ts","../../core/src/middleware/pipeline.ts","../../core/src/prefetched-intents/stable-stringify.ts","../../core/src/prefetched-intents/prefetched-intents.ts","../../core/src/framework.ts","../../core/src/http/client.ts","../../core/src/intents/base-controller.ts","../../core/src/data/mapper.ts","../../core/src/bootstrap/define-routes.ts","../../core/src/utils/lru-map.ts","../../core/src/utils/optional.ts","../../core/src/utils/url.ts","../../core/src/utils/uuid.ts","../../core/src/middleware/context.ts","../../core/src/middleware/types.ts","../../browser/src/action-handlers/external-url-action.ts","../../browser/src/utils/try-scroll.ts","../../browser/src/utils/history.ts","../../browser/src/action-handlers/flow-action.ts","../../browser/src/action-handlers/register.ts","../../browser/src/server-data.ts","../../browser/src/start-app.ts","../../ssr/src/render.ts","../../ssr/src/create-render.ts","../../ssr/src/server-data.ts","../../server/src/proxy.ts","../../server/src/adapters/shared.ts","../../server/src/adapters/cloudflare.ts","../../server/src/adapters/netlify.ts","../../server/src/adapters/node.ts","../../server/src/adapters/static.ts","../../server/src/adapters/vercel.ts","../../server/src/adapters/resolve.ts","../../server/src/adapters/auto.ts","../../server/src/runtime.ts","../../server/src/start.ts","../../server/src/create-server.ts","../../server/src/vite-plugin.ts"],"sourcesContent":["/**\n * Action 类型定义\n *\n * FlowAction — SPA 内部导航\n * ExternalUrlAction — 打开外部链接\n * CompoundAction — 组合多个 Action\n */\n\n/** Action Kind 常量 */\nexport const ACTION_KINDS = {\n FLOW: \"flow\" as const,\n EXTERNAL_URL: \"externalUrl\" as const,\n COMPOUND: \"compound\" as const,\n};\n\n/** FlowAction — SPA 导航 */\nexport interface FlowAction {\n kind: typeof ACTION_KINDS.FLOW;\n url: string;\n /** 展示方式: 默认 push,modal 弹窗 */\n presentationContext?: \"default\" | \"modal\";\n}\n\n/** ExternalUrlAction — 外部链接 */\nexport interface ExternalUrlAction {\n kind: typeof ACTION_KINDS.EXTERNAL_URL;\n url: string;\n}\n\n/** CompoundAction — 组合 Action */\nexport interface CompoundAction {\n kind: typeof ACTION_KINDS.COMPOUND;\n actions: Action[];\n}\n\n/** 所有 Action 的联合类型 */\nexport type Action = FlowAction | ExternalUrlAction | CompoundAction;\n\n// ===== Type Guards =====\n\nexport function isFlowAction(action: Action): action is FlowAction {\n return action.kind === ACTION_KINDS.FLOW;\n}\n\nexport function isExternalUrlAction(action: Action): action is ExternalUrlAction {\n return action.kind === ACTION_KINDS.EXTERNAL_URL;\n}\n\nexport function isCompoundAction(action: Action): action is CompoundAction {\n return action.kind === ACTION_KINDS.COMPOUND;\n}\n\n// ===== Factory =====\n\nexport function makeFlowAction(\n url: string,\n presentationContext?: FlowAction[\"presentationContext\"],\n): FlowAction {\n return { kind: ACTION_KINDS.FLOW, url, presentationContext };\n}\n\nexport function makeExternalUrlAction(url: string): ExternalUrlAction {\n return { kind: ACTION_KINDS.EXTERNAL_URL, url };\n}\n","/**\n * ActionDispatcher — Action 分发器\n *\n * 注册不同 kind 的 handler,按类型分发。\n * CompoundAction 自动展开递归执行。\n */\n\nimport type { Action } from \"./types\";\nimport { isCompoundAction } from \"./types\";\n\n/** Action 处理器函数类型 */\nexport type ActionHandler<A extends Action = Action> = (action: A) => Promise<void> | void;\n\nexport class ActionDispatcher {\n private handlers = new Map<string, ActionHandler>();\n private wiredActions = new Set<string>();\n\n /** 注册指定 kind 的 handler(防止重复注册) */\n onAction<A extends Action>(kind: string, handler: ActionHandler<A>): void {\n if (this.wiredActions.has(kind)) {\n console.warn(`[ActionDispatcher] kind=\"${kind}\" already registered, skipping`);\n return;\n }\n this.wiredActions.add(kind);\n this.handlers.set(kind, handler as ActionHandler);\n }\n\n /** 执行一个 Action(CompoundAction 递归展开) */\n async perform(action: Action): Promise<void> {\n if (isCompoundAction(action)) {\n for (const subAction of action.actions) {\n await this.perform(subAction);\n }\n return;\n }\n\n const handler = this.handlers.get(action.kind);\n if (!handler) {\n console.warn(`[ActionDispatcher] No handler for kind=\"${action.kind}\"`);\n return;\n }\n\n await handler(action);\n }\n}\n","/**\n * IntentDispatcher — Intent 分发器\n *\n * 注册 IntentController,按 intentId 分发。\n */\n\nimport type { Container } from \"../dependencies/container\";\nimport type { Intent, IntentController } from \"./types\";\n\nexport class IntentDispatcher {\n private controllers = new Map<string, IntentController>();\n\n /** 注册一个 IntentController */\n register(controller: IntentController): void {\n this.controllers.set(controller.intentId, controller);\n }\n\n /** 分发 Intent 到对应 Controller */\n async dispatch<T>(intent: Intent<T>, container: Container): Promise<T> {\n const controller = this.controllers.get(intent.id);\n if (!controller) {\n throw new Error(\n `[IntentDispatcher] No controller for \"${intent.id}\". ` +\n `Registered: [${Array.from(this.controllers.keys()).join(\", \")}]`,\n );\n }\n return controller.perform(intent, container) as Promise<T>;\n }\n\n /** 检查是否已注册某个 Intent */\n has(intentId: string): boolean {\n return this.controllers.has(intentId);\n }\n}\n","/**\n * Container — 通用的依赖注入容器\n */\n\ntype Factory<T> = () => T;\n\ninterface Registration<T> {\n factory: Factory<T>;\n singleton: boolean;\n instance?: T;\n}\n\nexport class Container {\n private registrations = new Map<string, Registration<unknown>>();\n\n /** 注册依赖(默认单例) */\n register<T>(key: string, factory: Factory<T>, singleton = true): this {\n this.registrations.set(key, { factory, singleton });\n return this;\n }\n\n /** 解析依赖 */\n resolve<T>(key: string): T {\n const reg = this.registrations.get(key);\n if (!reg) {\n throw new Error(`[Container] No registration for key: \"${key}\"`);\n }\n\n if (reg.singleton) {\n if (reg.instance === undefined) {\n reg.instance = reg.factory();\n }\n return reg.instance as T;\n }\n return reg.factory() as T;\n }\n\n /** 检查是否已注册 */\n has(key: string): boolean {\n return this.registrations.has(key);\n }\n\n /** 销毁容器,清除所有缓存 */\n dispose(): void {\n for (const reg of this.registrations.values()) {\n reg.instance = undefined;\n }\n this.registrations.clear();\n }\n}\n","/**\n * BaseLogger — 抽象日志基类\n */\n\nimport type { Logger } from \"./types\";\n\nexport abstract class BaseLogger implements Logger {\n protected category: string;\n\n constructor(category: string) {\n this.category = category;\n }\n\n abstract debug(...args: unknown[]): string;\n abstract info(...args: unknown[]): string;\n abstract warn(...args: unknown[]): string;\n abstract error(...args: unknown[]): string;\n}\n","/**\n * localStorage 日志级别过滤\n *\n * 通过 localStorage.onyxLog 控制日志级别:\n * '*=info' — 全局 info 及以上\n * '*=info,Foo=off' — 全局 info,Foo 静默\n * 'Bar=error,Baz=warn' — Bar 只输出 error,Baz 输出 warn+\n */\n\nimport type { Level } from \"./types\";\n\ntype LevelNum = 4 | 3 | 2 | 1 | 0;\n\nconst LEVEL_TO_NUM: Record<string, LevelNum> = {\n \"*\": 4,\n debug: 4,\n info: 3,\n warn: 2,\n error: 1,\n off: 0,\n \"\": 0,\n};\n\ninterface Rules {\n named?: Record<string, LevelNum>;\n defaultLevel?: LevelNum;\n}\n\nlet cachedRules: Rules | undefined;\nlet cachedRaw: string | undefined;\n\nfunction parseRules(): Rules {\n if (typeof globalThis.localStorage === \"undefined\") {\n return {};\n }\n\n let raw: string | null;\n try {\n raw = globalThis.localStorage.getItem(\"onyxLog\");\n } catch {\n return {};\n }\n\n if (!raw) return {};\n\n if (raw === cachedRaw && cachedRules) return cachedRules;\n cachedRaw = raw;\n\n const rules: Rules = {};\n const parts = raw.split(\",\");\n\n for (const part of parts) {\n const [name, level] = part.trim().split(\"=\");\n if (!name || level === undefined) continue;\n\n const num = LEVEL_TO_NUM[level.toLowerCase()] ?? undefined;\n if (num === undefined) continue;\n\n if (name === \"*\") {\n rules.defaultLevel = num;\n } else {\n rules.named ??= {};\n rules.named[name] = num;\n }\n }\n\n cachedRules = rules;\n return rules;\n}\n\nexport function shouldLog(name: string, level: Level): boolean {\n const rules = parseRules();\n\n if (rules.defaultLevel === undefined && !rules.named) {\n return true;\n }\n\n const currentNum = LEVEL_TO_NUM[level] ?? 4;\n\n if (rules.named?.[name] !== undefined) {\n return currentNum <= rules.named[name];\n }\n\n if (rules.defaultLevel !== undefined) {\n return currentNum <= rules.defaultLevel;\n }\n\n return true;\n}\n\nexport function resetFilterCache(): void {\n cachedRules = undefined;\n cachedRaw = undefined;\n}\n","/**\n * ConsoleLogger — 基于 console 的日志实现\n */\n\nimport { BaseLogger } from \"./base\";\nimport { shouldLog } from \"./local-storage-filter\";\nimport type { Logger, LoggerFactory } from \"./types\";\n\nexport class ConsoleLogger extends BaseLogger {\n debug(...args: unknown[]): string {\n if (shouldLog(this.category, \"debug\")) {\n console.debug(`[${this.category}]`, ...args);\n }\n return \"\";\n }\n\n info(...args: unknown[]): string {\n if (shouldLog(this.category, \"info\")) {\n console.info(`[${this.category}]`, ...args);\n }\n return \"\";\n }\n\n warn(...args: unknown[]): string {\n if (shouldLog(this.category, \"warn\")) {\n console.warn(`[${this.category}]`, ...args);\n }\n return \"\";\n }\n\n error(...args: unknown[]): string {\n console.error(`[${this.category}]`, ...args);\n return \"\";\n }\n}\n\nexport class ConsoleLoggerFactory implements LoggerFactory {\n loggerFor(category: string): Logger {\n return new ConsoleLogger(category);\n }\n}\n","/**\n * 依赖工厂 — 创建所有基础依赖\n */\n\nimport { ConsoleLoggerFactory } from \"../logger/console\";\nimport type { Logger, LoggerFactory } from \"../logger/types\";\nimport { Container } from \"./container\";\n\n// ===== 重新导出 Logger 类型 =====\nexport type { Logger, LoggerFactory };\n\n// ===== 依赖接口 =====\n\n/** 网络请求层 */\nexport interface Net {\n fetch(url: string, options?: RequestInit): Promise<Response>;\n}\n\n/** 多语言状态 */\nexport interface Locale {\n language: string;\n storefront: string;\n setActiveLocale(language: string, storefront: string): void;\n}\n\n/** 存储接口 */\nexport interface Storage {\n get(key: string): string | undefined;\n set(key: string, value: string): void;\n delete(key: string): void;\n}\n\n/** Feature Flags */\nexport interface FeatureFlags {\n isEnabled(key: string): boolean;\n getString(key: string): string | undefined;\n getNumber(key: string): number | undefined;\n}\n\n/** Metrics 记录器 */\nexport interface MetricsRecorder {\n recordPageView(page: string, fields?: Record<string, unknown>): void;\n recordEvent(name: string, fields?: Record<string, unknown>): void;\n}\n\n// ===== 依赖 Key 常量 =====\n\nexport const DEP_KEYS = {\n LOGGER: \"logger\",\n LOGGER_FACTORY: \"loggerFactory\",\n NET: \"net\",\n LOCALE: \"locale\",\n STORAGE: \"storage\",\n FEATURE_FLAGS: \"featureFlags\",\n METRICS: \"metrics\",\n FETCH: \"fetch\",\n} as const;\n\n// ===== 默认实现 =====\n\nclass DefaultLocale implements Locale {\n language = \"en\";\n storefront = \"us\";\n setActiveLocale(language: string, storefront: string) {\n this.language = language;\n this.storefront = storefront;\n }\n}\n\nclass MemoryStorage implements Storage {\n private store = new Map<string, string>();\n get(key: string) {\n return this.store.get(key);\n }\n set(key: string, value: string) {\n this.store.set(key, value);\n }\n delete(key: string) {\n this.store.delete(key);\n }\n}\n\nclass DefaultFeatureFlags implements FeatureFlags {\n private flags: Record<string, boolean | string | number>;\n constructor(flags: Record<string, boolean | string | number> = {}) {\n this.flags = flags;\n }\n isEnabled(key: string) {\n return this.flags[key] === true;\n }\n getString(key: string) {\n const v = this.flags[key];\n return typeof v === \"string\" ? v : undefined;\n }\n getNumber(key: string) {\n const v = this.flags[key];\n return typeof v === \"number\" ? v : undefined;\n }\n}\n\nclass ConsoleMetrics implements MetricsRecorder {\n recordPageView(page: string, fields?: Record<string, unknown>) {\n console.info(`[Metrics:PageView] ${page}`, fields ?? \"\");\n }\n recordEvent(name: string, fields?: Record<string, unknown>) {\n console.info(`[Metrics:Event] ${name}`, fields ?? \"\");\n }\n}\n\n// ===== 依赖工厂 =====\n\nexport interface MakeDependenciesOptions {\n fetch?: typeof globalThis.fetch;\n language?: string;\n storefront?: string;\n featureFlags?: Record<string, boolean | string | number>;\n}\n\nexport function makeDependencies(\n container: Container,\n options: MakeDependenciesOptions = {},\n): void {\n const {\n fetch: fetchFn = globalThis.fetch?.bind(globalThis),\n language = \"en\",\n storefront = \"us\",\n featureFlags = {},\n } = options;\n\n const loggerFactory = new ConsoleLoggerFactory();\n container.register<LoggerFactory>(DEP_KEYS.LOGGER_FACTORY, () => loggerFactory);\n\n container.register<Logger>(DEP_KEYS.LOGGER, () => loggerFactory.loggerFor(\"framework\"));\n\n container.register<Net>(DEP_KEYS.NET, () => ({\n fetch: (url: string, opts?: RequestInit) => fetchFn(url, opts),\n }));\n\n container.register<Locale>(DEP_KEYS.LOCALE, () => {\n const locale = new DefaultLocale();\n locale.setActiveLocale(language, storefront);\n return locale;\n });\n\n container.register<Storage>(DEP_KEYS.STORAGE, () => new MemoryStorage());\n\n container.register<FeatureFlags>(\n DEP_KEYS.FEATURE_FLAGS,\n () => new DefaultFeatureFlags(featureFlags),\n );\n\n container.register<MetricsRecorder>(DEP_KEYS.METRICS, () => new ConsoleMetrics());\n\n container.register(DEP_KEYS.FETCH, () => fetchFn);\n}\n","/**\n * URL 路由器 — URL pattern → Intent + FlowAction\n */\n\nimport { makeFlowAction, type FlowAction } from \"../actions/types\";\nimport type { Intent } from \"../intents/types\";\nimport type { AfterLoadGuard, BeforeLoadGuard } from \"../middleware/types\";\n\n/** 路由匹配结果 */\nexport interface RouteMatch {\n intent: Intent;\n action: FlowAction;\n renderMode?: string;\n /** 该路由绑定的 beforeLoad 守卫 */\n beforeGuards?: BeforeLoadGuard[];\n /** 该路由绑定的 afterLoad 守卫 */\n afterGuards?: AfterLoadGuard[];\n}\n\n/** 路由添加选项 */\nexport interface RouteAddOptions {\n renderMode?: string;\n beforeGuards?: BeforeLoadGuard[];\n afterGuards?: AfterLoadGuard[];\n}\n\ninterface InternalRouteDefinition {\n pattern: string;\n intentId: string;\n regex: RegExp;\n paramNames: string[];\n renderMode?: string;\n beforeGuards?: BeforeLoadGuard[];\n afterGuards?: AfterLoadGuard[];\n}\n\nexport class Router {\n private routes: InternalRouteDefinition[] = [];\n\n /** 添加路由规则 */\n add(pattern: string, intentId: string, renderModeOrOptions?: string | RouteAddOptions): this {\n const opts: RouteAddOptions =\n typeof renderModeOrOptions === \"string\"\n ? { renderMode: renderModeOrOptions }\n : (renderModeOrOptions ?? {});\n\n const paramNames: string[] = [];\n\n // 将 /:param 和 /:param? 替换为捕获组,其余部分转义正则元字符\n const regexStr = pattern\n .split(/(\\/:[\\w]+\\??)/)\n .map((segment) => {\n const paramMatch = segment.match(/^\\/:(\\w+)(\\?)?$/);\n if (paramMatch) {\n paramNames.push(paramMatch[1]);\n return paramMatch[2] ? \"(?:/([^/]+))?\" : \"/([^/]+)\";\n }\n // 非参数片段:转义所有正则特殊字符\n return segment.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n })\n .join(\"\");\n\n this.routes.push({\n pattern,\n intentId,\n regex: new RegExp(`^${regexStr}/?$`),\n paramNames,\n renderMode: opts.renderMode,\n beforeGuards: opts.beforeGuards,\n afterGuards: opts.afterGuards,\n });\n\n return this;\n }\n\n /** 解析 URL → RouteMatch */\n resolve(urlOrPath: string): RouteMatch | null {\n const path = this.extractPath(urlOrPath);\n const queryParams = this.extractQueryParams(urlOrPath);\n\n for (const route of this.routes) {\n const match = path.match(route.regex);\n if (match) {\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, index) => {\n const value = match[index + 1];\n if (value) params[name] = value;\n });\n for (const [k, v] of Object.entries(queryParams)) {\n if (!(k in params)) params[k] = v;\n }\n\n return {\n intent: { id: route.intentId, params },\n action: makeFlowAction(urlOrPath),\n renderMode: route.renderMode,\n beforeGuards: route.beforeGuards,\n afterGuards: route.afterGuards,\n };\n }\n }\n\n return null;\n }\n\n /** 获取所有已注册的路由 */\n getRoutes(): string[] {\n return this.routes.map((r) => `${r.pattern} → ${r.intentId}`);\n }\n\n private extractPath(url: string): string {\n try {\n const parsed = new URL(url, \"http://localhost\");\n return parsed.pathname;\n } catch {\n return url.split(\"?\")[0].split(\"#\")[0];\n }\n }\n\n private extractQueryParams(url: string): Record<string, string> {\n try {\n const parsed = new URL(url, \"http://localhost\");\n const params: Record<string, string> = {};\n parsed.searchParams.forEach((v, k) => {\n params[k] = v;\n });\n return params;\n } catch {\n return {};\n }\n }\n}\n","/**\n * Composite Logger — 组合日志,广播到多个后端\n */\n\nimport type { Logger, LoggerFactory } from \"./types\";\n\nexport class CompositeLoggerFactory implements LoggerFactory {\n constructor(private readonly factories: LoggerFactory[]) {}\n\n loggerFor(name: string): Logger {\n return new CompositeLogger(this.factories.map((f) => f.loggerFor(name)));\n }\n}\n\nexport class CompositeLogger implements Logger {\n constructor(private readonly loggers: Logger[]) {}\n\n debug(...args: unknown[]): string {\n return this.callAll(\"debug\", args);\n }\n\n info(...args: unknown[]): string {\n return this.callAll(\"info\", args);\n }\n\n warn(...args: unknown[]): string {\n return this.callAll(\"warn\", args);\n }\n\n error(...args: unknown[]): string {\n return this.callAll(\"error\", args);\n }\n\n private callAll(method: \"debug\" | \"info\" | \"warn\" | \"error\", args: unknown[]): string {\n for (const logger of this.loggers) {\n logger[method](...args);\n }\n return \"\";\n }\n}\n","/**\n * Guard Pipeline — 顺序执行守卫链\n *\n * 按注册顺序执行守卫,遇到第一个非 `next` 结果立即短路返回。\n */\n\nimport type {\n AfterLoadGuard,\n BeforeLoadGuard,\n MiddlewareResult,\n NavigationContext,\n PostLoadContext,\n} from \"./types\";\n\n/** 执行 beforeLoad 守卫链 */\nexport async function runBeforeLoadGuards(\n guards: BeforeLoadGuard[],\n ctx: NavigationContext,\n): Promise<MiddlewareResult> {\n for (const guard of guards) {\n const result = await guard(ctx);\n if (result.kind !== \"next\") return result;\n }\n return { kind: \"next\" };\n}\n\n/** 执行 afterLoad 守卫链 */\nexport async function runAfterLoadGuards(\n guards: AfterLoadGuard[],\n ctx: PostLoadContext,\n): Promise<MiddlewareResult> {\n for (const guard of guards) {\n const result = await guard(ctx);\n if (result.kind !== \"next\") return result;\n }\n return { kind: \"next\" };\n}\n","/**\n * stableStringify — 确定性 JSON 序列化(keys 按字母排序)\n *\n * 用作缓存 key:相同内容的对象始终产生相同字符串。\n */\n\nexport function stableStringify(obj: unknown, _seen?: Set<object>): string {\n if (obj === null || obj === undefined) return String(obj);\n if (typeof obj !== \"object\") return JSON.stringify(obj);\n\n const seen = _seen ?? new Set<object>();\n if (seen.has(obj as object)) return '\"[Circular]\"';\n seen.add(obj as object);\n\n if (Array.isArray(obj)) {\n return \"[\" + obj.map((v) => stableStringify(v, seen)).join(\",\") + \"]\";\n }\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n const parts = keys\n .filter((k) => (obj as Record<string, unknown>)[k] !== undefined)\n .map(\n (k) =>\n JSON.stringify(k) +\n \":\" +\n stableStringify((obj as Record<string, unknown>)[k], seen),\n );\n return \"{\" + parts.join(\",\") + \"}\";\n}\n","/**\n * PrefetchedIntents — SSR 数据缓存\n *\n * 服务端渲染时将 Intent→Data 映射序列化嵌入 HTML,\n * 客户端 hydrate 时提取缓存。Framework.dispatch() 优先查缓存,\n * 命中则直接返回,未命中则走 Controller 调度。\n */\n\nimport type { Intent } from \"../intents/types\";\nimport { stableStringify } from \"./stable-stringify\";\n\n/** 预获取的 Intent-Data 对 */\nexport interface PrefetchedIntent {\n intent: Intent;\n data: unknown;\n}\n\nexport class PrefetchedIntents {\n private intents: Map<string, unknown>;\n\n private constructor(intents: Map<string, unknown>) {\n this.intents = intents;\n }\n\n /** 从 PrefetchedIntent 数组创建缓存实例 */\n static fromArray(items: PrefetchedIntent[]): PrefetchedIntents {\n const map = new Map<string, unknown>();\n for (const item of items) {\n if (item.intent && item.data !== undefined) {\n const key = stableStringify(item.intent);\n map.set(key, item.data);\n }\n }\n return new PrefetchedIntents(map);\n }\n\n /** 创建空缓存实例 */\n static empty(): PrefetchedIntents {\n return new PrefetchedIntents(new Map());\n }\n\n /**\n * 获取缓存的 Intent 结果(一次性使用)。\n * 命中后从缓存中删除。\n */\n get<T>(intent: Intent<T>): T | undefined {\n const key = stableStringify(intent);\n const data = this.intents.get(key);\n if (data !== undefined) {\n this.intents.delete(key);\n return data as T;\n }\n return undefined;\n }\n\n /** 检查缓存中是否有某个 Intent 的数据 */\n has(intent: Intent): boolean {\n return this.intents.has(stableStringify(intent));\n }\n\n /** 缓存中的条目数 */\n get size(): number {\n return this.intents.size;\n }\n}\n","/**\n * Framework — 框架核心类\n *\n * 对应原版 Jet 类,统一管理: DI 容器、Intent 分发、Action 分发、路由、Metrics。\n * 纯 TypeScript,不依赖任何 UI 框架。\n */\n\nimport { ActionDispatcher, type ActionHandler } from \"./actions/dispatcher\";\nimport type { Action } from \"./actions/types\";\nimport { Container } from \"./dependencies/container\";\nimport type { MetricsRecorder } from \"./dependencies/make-dependencies\";\nimport {\n DEP_KEYS,\n makeDependencies,\n type MakeDependenciesOptions,\n} from \"./dependencies/make-dependencies\";\nimport { IntentDispatcher } from \"./intents/dispatcher\";\nimport type { Intent, IntentController } from \"./intents/types\";\nimport type { Logger } from \"./logger/types\";\nimport { runAfterLoadGuards, runBeforeLoadGuards } from \"./middleware/pipeline\";\nimport type {\n AfterLoadGuard,\n BeforeLoadGuard,\n MiddlewareResult,\n NavigationContext,\n PostLoadContext,\n} from \"./middleware/types\";\nimport type { BasePage } from \"./models/page\";\nimport { PrefetchedIntents } from \"./prefetched-intents/prefetched-intents\";\nimport { Router, type RouteMatch } from \"./router/router\";\n\n/** Framework 初始化配置 */\nexport interface FrameworkConfig extends MakeDependenciesOptions {\n setupRoutes?: (router: Router) => void;\n prefetchedIntents?: PrefetchedIntents;\n}\n\nexport class Framework {\n readonly container: Container;\n readonly intentDispatcher: IntentDispatcher;\n readonly actionDispatcher: ActionDispatcher;\n readonly router: Router;\n readonly prefetchedIntents: PrefetchedIntents;\n\n private readonly beforeGuards: BeforeLoadGuard[] = [];\n private readonly afterGuards: AfterLoadGuard[] = [];\n\n private constructor(container: Container, prefetchedIntents: PrefetchedIntents) {\n this.container = container;\n this.intentDispatcher = new IntentDispatcher();\n this.actionDispatcher = new ActionDispatcher();\n this.router = new Router();\n this.prefetchedIntents = prefetchedIntents;\n }\n\n /** 创建并初始化 Framework 实例 */\n static create(config: FrameworkConfig = {}): Framework {\n const container = new Container();\n makeDependencies(container, config);\n\n const fw = new Framework(container, config.prefetchedIntents ?? PrefetchedIntents.empty());\n\n config.setupRoutes?.(fw.router);\n\n return fw;\n }\n\n /** 分发 Intent — 获取页面数据 */\n async dispatch<T>(intent: Intent<T>): Promise<T> {\n const logger = this.container.resolve<Logger>(DEP_KEYS.LOGGER);\n\n const cached = this.prefetchedIntents.get(intent);\n if (cached !== undefined) {\n logger.debug(\n `[Framework] re-using prefetched intent response for: ${intent.id}`,\n intent.params,\n );\n return cached;\n }\n\n logger.debug(`[Framework] dispatch intent: ${intent.id}`, intent.params);\n return this.intentDispatcher.dispatch(intent, this.container);\n }\n\n /** 执行 Action — 处理用户交互 */\n async perform(action: Action): Promise<void> {\n const logger = this.container.resolve<Logger>(DEP_KEYS.LOGGER);\n logger.debug(`[Framework] perform action: ${action.kind}`);\n return this.actionDispatcher.perform(action);\n }\n\n /** 路由 URL — 将 URL 解析为 Intent + Action */\n routeUrl(url: string): RouteMatch | null {\n return this.router.resolve(url);\n }\n\n /** 记录页面访问事件 */\n didEnterPage(page: BasePage): void {\n const metrics = this.container.resolve<MetricsRecorder>(DEP_KEYS.METRICS);\n metrics.recordPageView(page.pageType, {\n pageId: page.id,\n title: page.title,\n });\n }\n\n /** 注册 Action 处理器 */\n onAction<A extends Action>(kind: string, handler: ActionHandler<A>): void {\n this.actionDispatcher.onAction(kind, handler);\n }\n\n /** 注册 Intent Controller */\n registerIntent(controller: IntentController): void {\n this.intentDispatcher.register(controller);\n }\n\n // ===== Navigation Middleware =====\n\n /** 注册 beforeLoad 守卫(路由匹配后、数据加载前) */\n beforeLoad(guard: BeforeLoadGuard): void {\n this.beforeGuards.push(guard);\n }\n\n /** 注册 afterLoad 守卫(数据加载后、渲染前) */\n afterLoad(guard: AfterLoadGuard): void {\n this.afterGuards.push(guard);\n }\n\n /** 执行所有 beforeLoad 守卫(全局 → 路由级) */\n runBeforeLoad(\n ctx: NavigationContext,\n routeGuards?: BeforeLoadGuard[],\n ): Promise<MiddlewareResult> {\n const guards = routeGuards?.length\n ? [...this.beforeGuards, ...routeGuards]\n : this.beforeGuards;\n return runBeforeLoadGuards(guards, ctx);\n }\n\n /** 执行所有 afterLoad 守卫(全局 → 路由级) */\n runAfterLoad(ctx: PostLoadContext, routeGuards?: AfterLoadGuard[]): Promise<MiddlewareResult> {\n const guards = routeGuards?.length\n ? [...this.afterGuards, ...routeGuards]\n : this.afterGuards;\n return runAfterLoadGuards(guards, ctx);\n }\n\n /** 销毁 Framework 实例 */\n dispose(): void {\n this.container.dispose();\n }\n}\n","/**\n * HttpClient — 通用 HTTP 客户端基类\n *\n * 为 API Client 提供标准化的 HTTP 请求能力。\n * 子类继承后只需关注业务端点定义,不需要重复实现 fetch / JSON 解析 / 错误处理。\n */\n\n/** HTTP 请求错误 */\nexport class HttpError extends Error {\n constructor(\n public readonly status: number,\n public readonly statusText: string,\n public readonly body?: string,\n ) {\n super(`HTTP ${status}: ${statusText}`);\n this.name = \"HttpError\";\n }\n}\n\n/** HttpClient 构造配置 */\nexport interface HttpClientConfig {\n /** API base URL(如 \"/api\" 或 \"https://example.com/api\") */\n baseUrl: string;\n /** 默认请求头 */\n defaultHeaders?: Record<string, string>;\n /** 自定义 fetch 实现(便于测试或 SSR) */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * 通用 HTTP 客户端基类\n *\n * 使用方式: 创建子类继承 HttpClient,定义业务方法调用 this.get() / this.post() 等。\n *\n * @example\n * ```ts\n * class MyApiClient extends HttpClient {\n * async getUser(id: string) {\n * return this.get<User>(`/users/${id}`);\n * }\n * }\n * ```\n */\nexport abstract class HttpClient {\n protected readonly baseUrl: string;\n protected readonly defaultHeaders: Record<string, string>;\n protected readonly fetchFn: typeof globalThis.fetch;\n\n constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl;\n this.defaultHeaders = config.defaultHeaders ?? {};\n this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** GET 请求,返回解析后的 JSON */\n protected async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"GET\", path, { params });\n }\n\n /** POST 请求,自动序列化 body 为 JSON */\n protected async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>(\"POST\", path, { body, params });\n }\n\n /** PUT 请求 */\n protected async put<T>(\n path: string,\n body?: unknown,\n params?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>(\"PUT\", path, { body, params });\n }\n\n /** DELETE 请求 */\n protected async del<T>(path: string, params?: Record<string, string>): Promise<T> {\n return this.request<T>(\"DELETE\", path, { params });\n }\n\n /**\n * 底层请求方法 — 子类可覆写以自定义行为\n *\n * 自动处理:\n * - URL 拼接 (baseUrl + path + params)\n * - 默认 headers 合并\n * - JSON body 序列化\n * - 响应 JSON 解析\n * - 非 2xx 状态码抛出 HttpError\n */\n protected async request<T>(\n method: string,\n path: string,\n options?: {\n params?: Record<string, string>;\n body?: unknown;\n headers?: Record<string, string>;\n },\n ): Promise<T> {\n const url = this.buildUrl(path, options?.params);\n\n const headers: Record<string, string> = {\n ...this.defaultHeaders,\n ...options?.headers,\n };\n\n const init: RequestInit = { method, headers };\n\n if (options?.body !== undefined) {\n headers[\"Content-Type\"] = headers[\"Content-Type\"] ?? \"application/json\";\n init.body = JSON.stringify(options.body);\n }\n\n const response = await this.fetchFn(url, init);\n\n if (!response.ok) {\n const body = await response.text().catch(() => undefined);\n throw new HttpError(response.status, response.statusText, body);\n }\n\n return response.json();\n }\n\n /** 构建完整 URL — 子类可覆写以自定义 URL 拼接逻辑 */\n protected buildUrl(path: string, params?: Record<string, string>): string {\n const base = this.baseUrl.endsWith(\"/\") ? this.baseUrl.slice(0, -1) : this.baseUrl;\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n const url = new URL(`${base}${normalizedPath}`, \"http://placeholder\");\n\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n url.searchParams.set(k, v);\n }\n }\n\n // 如果 baseUrl 是绝对 URL,返回完整 URL;否则只返回 path + search\n if (this.baseUrl.startsWith(\"http\")) {\n return url.toString();\n }\n return `${url.pathname}${url.search}`;\n }\n}\n","/**\n * BaseController — 抽象 Intent Controller 基类\n *\n * 提供标准化的 try/catch → fallback 模式。\n * 子类只需实现 execute() 和可选的 fallback()。\n */\n\nimport type { Container } from \"../dependencies/container\";\nimport type { Intent, IntentController } from \"./types\";\n\n/**\n * 抽象 Controller 基类\n *\n * 统一处理:\n * - 类型安全的参数提取 (TParams)\n * - 返回类型约束 (TResult)\n * - try/catch 错误处理 + 可选 fallback\n *\n * @example\n * ```ts\n * class ProductController extends BaseController<{ productId: string }, ProductPage> {\n * readonly intentId = \"product-page\";\n *\n * async execute(params: { productId: string }, container: Container) {\n * const api = container.resolve<ApiClient>(\"api\");\n * return api.getProduct(params.productId);\n * }\n *\n * fallback(params: { productId: string }, error: Error) {\n * return getMockProduct(params.productId);\n * }\n * }\n * ```\n */\nexport abstract class BaseController<\n TParams extends Record<string, string | undefined> = Record<string, string>,\n TResult = unknown,\n> implements IntentController<TResult> {\n /** Controller 对应的 Intent ID */\n abstract readonly intentId: string;\n\n /**\n * 执行业务逻辑 — 子类必须实现\n *\n * @param params - Intent 参数(已类型化)\n * @param container - DI 容器\n * @returns 页面数据\n */\n abstract execute(params: TParams, container: Container): Promise<TResult> | TResult;\n\n /**\n * 错误回退 — 子类可选覆写\n *\n * 当 execute() 抛出异常时调用。\n * 默认行为: 重新抛出原始错误。\n *\n * @param params - Intent 参数\n * @param error - execute() 抛出的错误\n * @returns 回退数据\n */\n fallback(params: TParams, error: Error): Promise<TResult> | TResult {\n throw error;\n }\n\n /**\n * IntentController.perform() 实现\n *\n * 自动 try/catch → fallback 模式。\n */\n async perform(intent: Intent<TResult>, container: Container): Promise<TResult> {\n const params = (intent.params ?? {}) as TParams;\n try {\n return await this.execute(params, container);\n } catch (e) {\n return this.fallback(params, e instanceof Error ? e : new Error(String(e)));\n }\n }\n}\n","/**\n * Mapper 类型工具 — 标准化数据转换管线\n *\n * 提供类型约定和组合函数,让 API 响应 → 页面模型 的转换有统一的签名模式。\n */\n\n/** 同步映射函数 */\nexport type Mapper<TInput, TOutput> = (input: TInput) => TOutput;\n\n/** 异步映射函数 */\nexport type AsyncMapper<TInput, TOutput> = (input: TInput) => TOutput | Promise<TOutput>;\n\n/**\n * 组合两个同步 Mapper: A → B → C\n */\nexport function pipe<A, B, C>(m1: Mapper<A, B>, m2: Mapper<B, C>): Mapper<A, C>;\n/**\n * 组合三个同步 Mapper: A → B → C → D\n */\nexport function pipe<A, B, C, D>(\n m1: Mapper<A, B>,\n m2: Mapper<B, C>,\n m3: Mapper<C, D>,\n): Mapper<A, D>;\n/**\n * 组合四个同步 Mapper: A → B → C → D → E\n */\nexport function pipe<A, B, C, D, E>(\n m1: Mapper<A, B>,\n m2: Mapper<B, C>,\n m3: Mapper<C, D>,\n m4: Mapper<D, E>,\n): Mapper<A, E>;\n/**\n * 组合任意数量的同步 Mapper\n */\nexport function pipe(...mappers: Mapper<unknown, unknown>[]): Mapper<unknown, unknown>;\nexport function pipe(...mappers: Mapper<unknown, unknown>[]): Mapper<unknown, unknown> {\n return (input: unknown) => mappers.reduce((acc, mapper) => mapper(acc), input);\n}\n\n/**\n * 组合两个可能异步的 Mapper: A → B → C\n */\nexport function pipeAsync<A, B, C>(m1: AsyncMapper<A, B>, m2: AsyncMapper<B, C>): AsyncMapper<A, C>;\n/**\n * 组合三个可能异步的 Mapper\n */\nexport function pipeAsync<A, B, C, D>(\n m1: AsyncMapper<A, B>,\n m2: AsyncMapper<B, C>,\n m3: AsyncMapper<C, D>,\n): AsyncMapper<A, D>;\nexport function pipeAsync(\n ...mappers: AsyncMapper<unknown, unknown>[]\n): AsyncMapper<unknown, unknown> {\n return async (input: unknown) => {\n let acc = input;\n for (const mapper of mappers) {\n acc = await mapper(acc);\n }\n return acc;\n };\n}\n\n/**\n * 将一个 Mapper 应用到数组的每个元素\n */\nexport function mapEach<TInput, TOutput>(\n mapper: Mapper<TInput, TOutput>,\n): Mapper<TInput[], TOutput[]> {\n return (items) => items.map(mapper);\n}\n","/**\n * defineRoutes — 声明式路由 + Controller 注册\n *\n * 将命令式的路由注册 (20+ 行 framework.router.add / framework.registerIntent)\n * 简化为声明式配置数组。\n */\n\nimport type { Framework } from \"../framework\";\nimport type { IntentController } from \"../intents/types\";\nimport type { AfterLoadGuard, BeforeLoadGuard } from \"../middleware/types\";\n\n/** 渲染模式 */\nexport type RenderMode = \"ssr\" | \"csr\" | \"prerender\";\n\n/** 单条路由定义 */\nexport interface RouteDefinition {\n /** URL pattern (如 \"/product/:productId\") */\n path: string;\n /** Intent ID (如 \"product-page\") */\n intentId: string;\n /**\n * Controller 实例(可选)。\n * 同一个 intentId 的多条路由只需在第一条提供 controller。\n */\n controller?: IntentController;\n /**\n * 渲染模式(可选,默认 \"ssr\")。\n * - \"ssr\": 服务端渲染(默认)\n * - \"csr\": 客户端渲染(返回空壳 HTML,由客户端 JS 渲染)\n * - \"prerender\": 预渲染(构建时生成静态 HTML + ISR 缓存)\n */\n renderMode?: RenderMode;\n /**\n * 路由级 beforeLoad 守卫(可选)。\n * 在全局守卫之后执行,仅对匹配此路由的请求生效。\n */\n beforeLoad?: BeforeLoadGuard[];\n /**\n * 路由级 afterLoad 守卫(可选)。\n * 在全局守卫之后执行,仅对匹配此路由的请求生效。\n */\n afterLoad?: AfterLoadGuard[];\n}\n\n/**\n * 声明式注册路由和 Controller\n *\n * - 自动去重: 同一 intentId 的 controller 只注册一次\n * - 路由和 controller 在同一个配置数组中,方便检查一致性\n *\n * @example\n * ```ts\n * defineRoutes(framework, [\n * { path: \"/\", intentId: \"home\", controller: new HomeController() },\n * { path: \"/product/:id\", intentId: \"product\", controller: new ProductController() },\n * { path: \"/search\", intentId: \"search\", controller: new SearchController() },\n * { path: \"/charts/:type\", intentId: \"charts\", controller: new ChartsController() },\n * { path: \"/charts\", intentId: \"charts\" }, // 同 intentId,不需要重复 controller\n * ]);\n * ```\n */\nexport function defineRoutes(framework: Framework, definitions: RouteDefinition[]): void {\n const registeredIntents = new Set<string>();\n\n for (const def of definitions) {\n // 注册 Controller(每个 intentId 只注册一次)\n if (def.controller && !registeredIntents.has(def.intentId)) {\n framework.registerIntent(def.controller);\n registeredIntents.add(def.intentId);\n }\n\n // 注册路由(含路由级守卫)\n framework.router.add(def.path, def.intentId, {\n renderMode: def.renderMode,\n beforeGuards: def.beforeLoad,\n afterGuards: def.afterLoad,\n });\n }\n}\n","/**\n * LruMap — 固定容量的 LRU 缓存\n */\n\nexport class LruMap<K, V> {\n private map = new Map<K, V>();\n private readonly capacity: number;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n }\n\n get(key: K): V | undefined {\n const value = this.map.get(key);\n if (value !== undefined) {\n // 移到末尾(最近使用)\n this.map.delete(key);\n this.map.set(key, value);\n }\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.map.has(key)) {\n this.map.delete(key);\n } else if (this.map.size >= this.capacity) {\n // 删除最旧的(第一个)\n const oldest = this.map.keys().next().value;\n if (oldest !== undefined) {\n this.map.delete(oldest);\n }\n }\n this.map.set(key, value);\n }\n\n has(key: K): boolean {\n return this.map.has(key);\n }\n\n delete(key: K): boolean {\n return this.map.delete(key);\n }\n\n get size(): number {\n return this.map.size;\n }\n\n clear(): void {\n this.map.clear();\n }\n}\n","/**\n * Optional 类型工具\n */\n\nexport type None = null | undefined;\nexport type Optional<T> = T | None;\n\nexport function isSome<T>(value: Optional<T>): value is T {\n return value !== null && value !== undefined;\n}\n\nexport function isNone<T>(value: Optional<T>): value is None {\n return value === null || value === undefined;\n}\n","/**\n * URL 工具函数\n */\n\n/** 移除 URL scheme (https://, http://) */\nexport function removeScheme(url: string): string {\n return url.replace(/^https?:\\/\\//, \"\");\n}\n\n/** 移除 URL host 部分,保留路径 */\nexport function removeHost(url: string): string {\n try {\n const parsed = new URL(url);\n return parsed.pathname + parsed.search + parsed.hash;\n } catch {\n return url;\n }\n}\n\n/** 移除 query 参数 */\nexport function removeQueryParams(url: string): string {\n return url.split(\"?\")[0];\n}\n\n/** 获取 URL 的基础路径(无 query、hash) */\nexport function getBaseUrl(url: string): string {\n return url.split(\"?\")[0].split(\"#\")[0];\n}\n\n/** 构建 URL(路径 + query 参数) */\nexport function buildUrl(path: string, params?: Record<string, string | undefined>): string {\n if (!params) return path;\n\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n searchParams.set(key, value);\n }\n }\n\n const qs = searchParams.toString();\n return qs ? `${path}?${qs}` : path;\n}\n","/**\n * UUID v4 生成器\n */\n\nexport function generateUuid(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n","/**\n * Navigation Context — 构建器\n *\n * 为 SSR(服务端)和 Browser(客户端)两种环境创建统一的 NavigationContext。\n */\n\nimport type { Container } from \"../dependencies/container\";\nimport type { Intent } from \"../intents/types\";\nimport type { NavigationContext } from \"./types\";\n\n// =====================================================================\n// Cookie 解析\n// =====================================================================\n\nfunction parseCookieString(str: string): Map<string, string> {\n const map = new Map<string, string>();\n if (!str) return map;\n for (const pair of str.split(\";\")) {\n const idx = pair.indexOf(\"=\");\n if (idx === -1) continue;\n const key = pair.slice(0, idx).trim();\n const val = pair.slice(idx + 1).trim();\n if (key) map.set(key, val);\n }\n return map;\n}\n\n// =====================================================================\n// Server Context\n// =====================================================================\n\nexport interface ServerContextOptions {\n url: string;\n intent: Intent;\n container: Container;\n /** 原始 Request 对象(提取 cookie 和 header) */\n request?: Request;\n}\n\n/** 从 Request 对象构建服务端上下文 */\nexport function createServerContext(options: ServerContextOptions): NavigationContext {\n const { url, intent, container, request } = options;\n const parsed = new URL(url, \"http://localhost\");\n\n const cookieHeader = request?.headers.get(\"cookie\") ?? \"\";\n const cookies = parseCookieString(cookieHeader);\n\n return {\n url,\n path: parsed.pathname,\n params: (intent.params as Record<string, string>) ?? {},\n intent,\n isServer: true,\n container,\n getCookie: (name: string) => cookies.get(name),\n getHeader: (name: string) => request?.headers.get(name) ?? undefined,\n };\n}\n\n// =====================================================================\n// Browser Context\n// =====================================================================\n\nexport interface BrowserContextOptions {\n url: string;\n intent: Intent;\n container: Container;\n}\n\n/** 从 document.cookie 构建浏览器端上下文 */\nexport function createBrowserContext(options: BrowserContextOptions): NavigationContext {\n const { url, intent, container } = options;\n const parsed = new URL(url, window.location.origin);\n\n return {\n url,\n path: parsed.pathname,\n params: (intent.params as Record<string, string>) ?? {},\n intent,\n isServer: false,\n container,\n getCookie: (name: string) => parseCookieString(document.cookie).get(name),\n getHeader: () => undefined,\n };\n}\n","/**\n * Navigation Middleware — 类型定义\n *\n * 两阶段导航中间件管线:\n * 1. beforeLoad — 路由匹配后、数据加载前(认证守卫、权限检查、早期重定向)\n * 2. afterLoad — 数据加载后、渲染前(URL 规范化、基于数据的守卫)\n *\n * SSR 和 CSR 共享同一套中间件定义。\n */\n\nimport type { Container } from \"../dependencies/container\";\nimport type { Intent } from \"../intents/types\";\nimport type { BasePage } from \"../models/page\";\n\n// =====================================================================\n// Navigation Context — 中间件上下文\n// =====================================================================\n\n/** 导航上下文(beforeLoad 阶段可用) */\nexport interface NavigationContext {\n /** 完整 URL(path + query) */\n readonly url: string;\n /** 仅路径部分 */\n readonly path: string;\n /** 路由参数 + 查询参数 */\n readonly params: Record<string, string>;\n /** 匹配的 Intent */\n readonly intent: Intent;\n /** 是否在服务端运行 */\n readonly isServer: boolean;\n /** DI 容器(可获取自定义服务) */\n readonly container: Container;\n /** 获取 Cookie 值(两端均可用) */\n getCookie(name: string): string | undefined;\n /** 获取请求头值(仅服务端有值,客户端始终返回 undefined) */\n getHeader(name: string): string | undefined;\n}\n\n/** 后置上下文(afterLoad 阶段,包含页面数据) */\nexport interface PostLoadContext extends NavigationContext {\n /** 控制器返回的页面数据 */\n readonly page: BasePage;\n}\n\n// =====================================================================\n// Middleware Result — 中间件返回值\n// =====================================================================\n\n/** 继续执行下一个中间件 */\nexport interface NextResult {\n readonly kind: \"next\";\n}\n\n/** 重定向(服务端: HTTP 301/302,客户端: 触发新导航) */\nexport interface RedirectResult {\n readonly kind: \"redirect\";\n readonly url: string;\n readonly status: number;\n}\n\n/** URL 重写(服务端: HTTP 301,客户端: replaceState 仅更新地址栏) */\nexport interface RewriteResult {\n readonly kind: \"rewrite\";\n readonly url: string;\n}\n\n/** 拒绝访问 */\nexport interface DenyResult {\n readonly kind: \"deny\";\n readonly status: number;\n readonly message: string;\n}\n\nexport type MiddlewareResult = NextResult | RedirectResult | RewriteResult | DenyResult;\n\n// =====================================================================\n// 便捷工厂函数\n// =====================================================================\n\n/** 继续执行 */\nexport function next(): NextResult {\n return { kind: \"next\" };\n}\n\n/** 重定向到新 URL */\nexport function redirect(url: string, status: 301 | 302 = 302): RedirectResult {\n return { kind: \"redirect\", url, status };\n}\n\n/** URL 重写(不重新加载数据) */\nexport function rewrite(url: string): RewriteResult {\n return { kind: \"rewrite\", url };\n}\n\n/** 拒绝访问 */\nexport function deny(status = 403, message = \"Forbidden\"): DenyResult {\n return { kind: \"deny\", status, message };\n}\n\n// =====================================================================\n// Guard 函数类型\n// =====================================================================\n\n/** beforeLoad 守卫:路由匹配后、数据加载前 */\nexport type BeforeLoadGuard = (\n ctx: NavigationContext,\n) => MiddlewareResult | Promise<MiddlewareResult>;\n\n/** afterLoad 守卫:数据加载后、渲染前 */\nexport type AfterLoadGuard = (ctx: PostLoadContext) => MiddlewareResult | Promise<MiddlewareResult>;\n","/**\n * ExternalUrl Action Handler — 外部链接处理器\n */\n\nimport type { ExternalUrlAction, Framework, Logger } from \"@finesoft/core\";\nimport { ACTION_KINDS } from \"@finesoft/core\";\n\nexport interface ExternalUrlDependencies {\n framework: Framework;\n log: Logger;\n}\n\nexport function registerExternalUrlHandler(deps: ExternalUrlDependencies): void {\n const { framework, log } = deps;\n\n framework.onAction(ACTION_KINDS.EXTERNAL_URL, (action: ExternalUrlAction) => {\n log.debug(`ExternalUrlAction → ${action.url}`);\n window.open(action.url, \"_blank\", \"noopener,noreferrer\");\n });\n}\n","/**\n * tryScroll — 渐进式滚动位置恢复\n *\n * 使用 rAF 循环等待页面高度足够后恢复滚动位置。\n */\n\nimport type { Logger } from \"@finesoft/core\";\n\nconst MAX_TRIES = 100;\nconst FUDGE = 16;\n\nlet pendingFrame: number | null = null;\n\nexport function tryScroll(\n log: Logger,\n getScrollableElement: () => HTMLElement | null,\n scrollY: number,\n): void {\n if (pendingFrame !== null) {\n cancelAnimationFrame(pendingFrame);\n pendingFrame = null;\n }\n\n let tries = 0;\n\n pendingFrame = requestAnimationFrame(function attempt() {\n if (++tries >= MAX_TRIES) {\n log.warn(`tryScroll: gave up after ${MAX_TRIES} frames, target=${scrollY}`);\n pendingFrame = null;\n return;\n }\n\n const el = getScrollableElement();\n if (!el) {\n log.warn(\"could not restore scroll: the scrollable element is missing\");\n return;\n }\n\n const { scrollHeight, offsetHeight } = el;\n const canScroll = scrollY + offsetHeight <= scrollHeight + FUDGE;\n\n if (!canScroll) {\n log.info(\"page is not tall enough for scroll yet\", {\n scrollHeight,\n offsetHeight,\n });\n pendingFrame = requestAnimationFrame(attempt);\n return;\n }\n\n el.scrollTop = scrollY;\n log.info(\"scroll restored to\", scrollY);\n pendingFrame = null;\n });\n}\n","/**\n * History 管理器 — 浏览器历史状态 + 滚动位置\n */\n\nimport type { Logger } from \"@finesoft/core\";\nimport { LruMap, generateUuid } from \"@finesoft/core\";\nimport { tryScroll } from \"./try-scroll\";\n\nconst HISTORY_SIZE_LIMIT = 10;\n\ninterface HistoryEntry<State> {\n state: State;\n scrollY: number;\n}\n\ninterface HistoryOptions {\n getScrollablePageElement: () => HTMLElement | null;\n}\n\nexport class History<State> {\n private readonly entries: LruMap<string, HistoryEntry<State>>;\n private readonly log: Logger;\n private readonly getScrollablePageElement: () => HTMLElement | null;\n private currentStateId: string | undefined;\n\n constructor(log: Logger, options: HistoryOptions, sizeLimit = HISTORY_SIZE_LIMIT) {\n this.entries = new LruMap(sizeLimit);\n this.log = log;\n this.getScrollablePageElement = options.getScrollablePageElement;\n }\n\n replaceState(state: State, url: string): void {\n const id = generateUuid();\n window.history.replaceState({ id }, \"\", url);\n this.currentStateId = id;\n this.entries.set(id, { state, scrollY: 0 });\n this.scrollTop = 0;\n this.log.info(\"replaceState\", state, url, id);\n }\n\n pushState(state: State, url: string): void {\n const id = generateUuid();\n window.history.pushState({ id }, \"\", url);\n this.currentStateId = id;\n this.entries.set(id, { state, scrollY: 0 });\n this.scrollTop = 0;\n this.log.info(\"pushState\", state, url, id);\n }\n\n beforeTransition(): void {\n const { state } = window.history;\n if (!state) return;\n\n const oldEntry = this.entries.get(state.id);\n if (!oldEntry) {\n this.log.info(\"current history state evicted from LRU, not saving scroll position\");\n return;\n }\n\n const { scrollTop } = this;\n this.entries.set(state.id, { ...oldEntry, scrollY: scrollTop });\n this.log.info(\"saving scroll position\", scrollTop);\n }\n\n onPopState(listener: (url: string, state?: State) => void | Promise<void>): void {\n window.addEventListener(\"popstate\", async (event: PopStateEvent) => {\n this.currentStateId = event.state?.id;\n\n if (!this.currentStateId) {\n this.log.warn(\n \"encountered a null event.state.id in onPopState event:\",\n window.location.href,\n );\n }\n\n this.log.info(\"popstate\", this.entries, this.currentStateId);\n\n const entry = this.currentStateId ? this.entries.get(this.currentStateId) : undefined;\n\n await listener(window.location.href, entry?.state);\n\n if (!entry) {\n return;\n }\n\n const { scrollY } = entry;\n this.log.info(\"restoring scroll to\", scrollY);\n tryScroll(this.log, () => this.getScrollablePageElement(), scrollY);\n });\n }\n\n /** 仅推入 URL,不缓存页面状态(用于页面加载失败场景) */\n pushUrl(url: string): void {\n const id = generateUuid();\n window.history.pushState({ id }, \"\", url);\n this.currentStateId = id;\n this.scrollTop = 0;\n this.log.info(\"pushUrl (no state)\", url, id);\n }\n\n /** 仅替换 URL,不缓存页面状态(用于页面加载失败场景) */\n replaceUrl(url: string): void {\n const id = generateUuid();\n window.history.replaceState({ id }, \"\", url);\n this.currentStateId = id;\n this.scrollTop = 0;\n this.log.info(\"replaceUrl (no state)\", url, id);\n }\n\n updateState(update: (current?: State) => State): void {\n if (!this.currentStateId) {\n this.log.warn(\"failed: encountered a null currentStateId inside updateState\");\n return;\n }\n\n const currentState = this.entries.get(this.currentStateId);\n const newState = update(currentState?.state);\n this.log.info(\"updateState\", newState, this.currentStateId);\n this.entries.set(this.currentStateId, {\n ...(currentState as HistoryEntry<State>),\n state: newState,\n });\n }\n\n private get scrollTop(): number {\n return this.getScrollablePageElement()?.scrollTop || 0;\n }\n\n private set scrollTop(scrollTop: number) {\n const element = this.getScrollablePageElement();\n if (element) {\n element.scrollTop = scrollTop;\n }\n }\n}\n","/**\n * FlowAction Handler — 核心 SPA 导航处理器\n *\n * 通过 FlowActionCallbacks 注入 UI 更新回调,\n * 不直接依赖任何 UI 框架的 store。\n */\n\nimport type { BasePage, FlowAction, Framework, Logger, PostLoadContext } from \"@finesoft/core\";\nimport { ACTION_KINDS, createBrowserContext } from \"@finesoft/core\";\nimport { History } from \"../utils/history\";\n\n/** FlowAction handler 的 History state */\ninterface FlowState {\n page: BasePage;\n}\n\n/** UI 框架回调 — 解耦 Svelte store 等依赖 */\nexport interface FlowActionCallbacks {\n /** 导航后更新当前路径(替代 currentPath.set()) */\n onNavigate(pathname: string): void;\n /** 模态页面展示(替代 openModal()) */\n onModal(page: BasePage): void;\n}\n\n/** 注册 FlowAction handler 所需的依赖 */\nexport interface FlowActionDependencies {\n framework: Framework;\n log: Logger;\n callbacks: FlowActionCallbacks;\n /** 更新应用 UI 的回调,page 可以是 Promise */\n updateApp: (props: { page: Promise<BasePage> | BasePage; isFirstPage?: boolean }) => void;\n /** 获取可滚动页面元素,用于滚动位置保存/恢复 */\n getScrollablePageElement?: () => HTMLElement | null;\n}\n\nexport function registerFlowActionHandler(deps: FlowActionDependencies): void {\n const { framework, log, callbacks, updateApp } = deps;\n let isFirstPage = true;\n let navigationId = 0;\n\n /** 重定向循环保护计数器 */\n const MAX_REDIRECTS = 5;\n\n const defaultGetScrollable = (): HTMLElement | null =>\n document.getElementById(\"scrollable-page-override\") ||\n document.getElementById(\"scrollable-page\") ||\n document.documentElement;\n\n const history = new History<FlowState>(log, {\n getScrollablePageElement: deps.getScrollablePageElement ?? defaultGetScrollable,\n });\n\n /**\n * 核心导航逻辑(支持递归重定向)\n * @param redirectCount 当前重定向次数,用于循环保护\n */\n async function navigateTo(url: string, redirectCount: number, thisNav: number): Promise<void> {\n if (redirectCount >= MAX_REDIRECTS) {\n log.error(\n `Navigation redirect loop detected (${MAX_REDIRECTS} redirects), stopping at: ${url}`,\n );\n return;\n }\n\n const shouldReplace =\n isFirstPage || url === window.location.pathname + window.location.search;\n\n const match = framework.routeUrl(url);\n if (!match) {\n log.warn(`FlowAction: no route for ${url}`);\n return;\n }\n\n // ===== beforeLoad 中间件 =====\n const navCtx = createBrowserContext({\n url,\n intent: match.intent,\n container: framework.container,\n });\n const beforeResult = await framework.runBeforeLoad(navCtx, match.beforeGuards);\n\n if (beforeResult.kind === \"redirect\") {\n log.debug(`beforeLoad → redirect to ${beforeResult.url}`);\n await navigateTo(beforeResult.url, redirectCount + 1, thisNav);\n return;\n }\n if (beforeResult.kind === \"deny\") {\n log.warn(`beforeLoad → denied (${beforeResult.status}): ${beforeResult.message}`);\n return;\n }\n // rewrite in beforeLoad: 无数据可言,当作 redirect 处理\n if (beforeResult.kind === \"rewrite\") {\n log.debug(`beforeLoad → rewrite to ${beforeResult.url}`);\n await navigateTo(beforeResult.url, redirectCount + 1, thisNav);\n return;\n }\n\n const pagePromise = framework.dispatch(match.intent) as Promise<BasePage>;\n\n await Promise.race([pagePromise, new Promise((r) => setTimeout(r, 500))]).catch(() => {});\n\n if (thisNav !== navigationId) {\n log.info(\"FlowAction superseded by newer navigation\", url);\n return;\n }\n\n history.beforeTransition();\n\n updateApp({\n page: pagePromise.then(\n async (page: BasePage): Promise<BasePage> => {\n if (thisNav !== navigationId) {\n log.info(\"FlowAction commit superseded\", url);\n return page;\n }\n\n // ===== afterLoad 中间件 =====\n const postCtx: PostLoadContext = {\n ...navCtx,\n page,\n };\n const afterResult = await framework.runAfterLoad(postCtx, match.afterGuards);\n\n if (afterResult.kind === \"redirect\") {\n log.debug(`afterLoad → redirect to ${afterResult.url}`);\n void navigateTo(afterResult.url, redirectCount + 1, thisNav);\n return page;\n }\n\n let canonicalURL = url;\n\n if (afterResult.kind === \"rewrite\") {\n // rewrite: 仅更新地址栏,保留已加载的 page 数据\n canonicalURL = afterResult.url;\n log.debug(`afterLoad → rewrite URL to ${canonicalURL}`);\n }\n\n if (afterResult.kind === \"deny\") {\n log.warn(`afterLoad → denied (${afterResult.status})`);\n return page;\n }\n\n if (shouldReplace) {\n history.replaceState({ page }, canonicalURL);\n } else {\n history.pushState({ page }, canonicalURL);\n }\n\n callbacks.onNavigate(new URL(canonicalURL, window.location.origin).pathname);\n\n didEnterPage(page);\n return page;\n },\n (error: unknown) => {\n // 页面加载失败仍需推入历史记录,确保 back/forward 正常\n if (thisNav === navigationId) {\n const canonicalURL = url;\n if (shouldReplace) {\n history.replaceUrl(canonicalURL);\n } else {\n history.pushUrl(canonicalURL);\n }\n callbacks.onNavigate(\n new URL(canonicalURL, window.location.origin).pathname,\n );\n }\n throw error;\n },\n ),\n isFirstPage,\n });\n\n isFirstPage = false;\n }\n\n // ===== FlowAction handler =====\n framework.onAction(ACTION_KINDS.FLOW, async (action) => {\n const flowAction = action as FlowAction;\n const url = flowAction.url;\n log.debug(`FlowAction → ${url}`);\n\n // 模态展示\n if (flowAction.presentationContext === \"modal\") {\n const match = framework.routeUrl(url);\n if (match) {\n const page = (await framework.dispatch(match.intent)) as BasePage;\n callbacks.onModal(page);\n }\n return;\n }\n\n const thisNav = ++navigationId;\n await navigateTo(url, 0, thisNav);\n });\n\n // ===== popstate handler =====\n history.onPopState(async (url, cachedState) => {\n log.debug(`popstate → ${url}, cached=${!!cachedState}`);\n\n callbacks.onNavigate(new URL(url).pathname);\n\n if (cachedState) {\n const { page } = cachedState;\n didEnterPage(page);\n updateApp({ page, isFirstPage });\n return;\n }\n\n const parsed = new URL(url);\n const routeMatch = framework.routeUrl(parsed.pathname + parsed.search);\n if (!routeMatch) {\n log.error(\"received popstate without data, but URL was unroutable:\", url);\n didEnterPage(null);\n updateApp({\n page: Promise.reject(new Error(\"404\")),\n isFirstPage,\n });\n return;\n }\n\n // ===== beforeLoad 中间件 =====\n const navCtx = createBrowserContext({\n url: parsed.pathname + parsed.search,\n intent: routeMatch.intent,\n container: framework.container,\n });\n const beforeResult = await framework.runBeforeLoad(navCtx, routeMatch.beforeGuards);\n\n if (beforeResult.kind === \"redirect\") {\n log.debug(`popstate beforeLoad → redirect to ${beforeResult.url}`);\n const thisNav = ++navigationId;\n await navigateTo(beforeResult.url, 0, thisNav);\n return;\n }\n if (beforeResult.kind === \"deny\" || beforeResult.kind === \"rewrite\") {\n // popstate 场景下 deny/rewrite 直接触发跳转\n if (beforeResult.kind === \"deny\") {\n log.warn(`popstate beforeLoad → denied`);\n } else {\n const thisNav = ++navigationId;\n await navigateTo(beforeResult.url, 0, thisNav);\n }\n return;\n }\n\n const pagePromise = framework.dispatch(routeMatch.intent) as Promise<BasePage>;\n\n await Promise.race([pagePromise, new Promise((r) => setTimeout(r, 500))]).catch(() => {});\n\n updateApp({\n page: pagePromise.then((page: BasePage): BasePage => {\n didEnterPage(page);\n return page;\n }),\n isFirstPage,\n });\n });\n\n function didEnterPage(page: BasePage | null): void {\n void (async (): Promise<void> => {\n try {\n if (page) {\n framework.didEnterPage(page);\n }\n } catch (e) {\n log.error(\"didEnterPage error:\", e);\n }\n })();\n }\n}\n","/**\n * Action Handler 统一注册入口\n */\n\nimport type { BasePage, Framework, Logger } from \"@finesoft/core\";\nimport { registerExternalUrlHandler } from \"./external-url-action\";\nimport { registerFlowActionHandler, type FlowActionCallbacks } from \"./flow-action\";\n\nexport type { FlowActionCallbacks };\n\nexport interface ActionHandlerDependencies {\n framework: Framework;\n log: Logger;\n callbacks: FlowActionCallbacks;\n updateApp: (props: { page: Promise<BasePage> | BasePage; isFirstPage?: boolean }) => void;\n /** 获取可滚动页面元素,用于滚动位置保存/恢复 */\n getScrollablePageElement?: () => HTMLElement | null;\n}\n\nexport function registerActionHandlers(deps: ActionHandlerDependencies): void {\n const { framework, log, callbacks, updateApp } = deps;\n\n registerFlowActionHandler({\n framework,\n log,\n callbacks,\n updateApp,\n getScrollablePageElement: deps.getScrollablePageElement,\n });\n\n registerExternalUrlHandler({ framework, log });\n}\n","/**\n * Server Data (browser side) — 从 DOM 反序列化服务端嵌入数据\n */\n\nimport { PrefetchedIntents, type PrefetchedIntent } from \"@finesoft/core\";\n\n/** DOM 中嵌入数据的 script 标签 ID */\nexport const SERVER_DATA_ID = \"serialized-server-data\";\n\n/**\n * 从 DOM 反序列化服务端嵌入的数据。\n * 读取 `<script id=\"serialized-server-data\">` 的内容并移除标签。\n */\nexport function deserializeServerData(): PrefetchedIntent[] | undefined {\n const script = document.getElementById(SERVER_DATA_ID);\n if (!script?.textContent) return undefined;\n\n script.parentNode?.removeChild(script);\n\n try {\n return JSON.parse(script.textContent);\n } catch {\n return undefined;\n }\n}\n\n/**\n * 从 DOM 提取 SSR 数据并构建 PrefetchedIntents 实例。\n * 替代原来的 PrefetchedIntents.fromDom()。\n */\nexport function createPrefetchedIntentsFromDom(): PrefetchedIntents {\n const data = deserializeServerData();\n if (!data || !Array.isArray(data)) {\n return PrefetchedIntents.empty();\n }\n return PrefetchedIntents.fromArray(data);\n}\n","/**\n * startBrowserApp — 客户端 hydration 一站式启动\n *\n * 封装:\n * 1. PrefetchedIntents 从 DOM 提取\n * 2. Framework 创建 + 引导\n * 3. 应用层挂载(通过 mount 回调,框架无关)\n * 4. Action handlers 注册\n * 5. 初始页面触发\n */\n\nimport type { BasePage, Logger } from \"@finesoft/core\";\nimport { DEP_KEYS, Framework, type LoggerFactory } from \"@finesoft/core\";\nimport { registerActionHandlers, type FlowActionCallbacks } from \"./action-handlers/register\";\nimport { createPrefetchedIntentsFromDom } from \"./server-data\";\n\nexport interface BrowserAppConfig {\n /** 注册 controllers 和路由的引导函数 */\n bootstrap: (framework: Framework) => void;\n\n /** 默认语言(回退值) */\n defaultLocale?: string;\n\n /** DOM 挂载点 ID(默认 \"app\") */\n mountId?: string;\n\n /** 获取可滚动页面元素,用于滚动位置保存/恢复 */\n getScrollablePageElement?: () => HTMLElement | null;\n\n /**\n * 挂载应用到 DOM\n *\n * 框架无关 — Svelte / React / Vue 均可通过此回调实现。\n *\n * @param target - DOM 挂载点\n * @param context - Framework 实例 + 语言\n * @returns 更新函数,用于后续页面切换\n */\n mount: (\n target: HTMLElement,\n context: { framework: Framework; locale: string },\n ) => (props: { page: Promise<BasePage> | BasePage; isFirstPage?: boolean }) => void;\n\n /** FlowAction / ExternalUrl 回调 */\n callbacks: FlowActionCallbacks;\n}\n\n/**\n * 启动客户端应用\n *\n * 自动执行 hydration 全流程。\n */\nexport async function startBrowserApp(config: BrowserAppConfig): Promise<void> {\n const { bootstrap, defaultLocale = \"en\", mountId = \"app\", mount, callbacks } = config;\n\n // 1. 从 DOM 提取 PrefetchedIntents 缓存\n const prefetchedIntents = createPrefetchedIntentsFromDom();\n\n // 2. 初始化 Framework + 注册 Controllers\n const framework = Framework.create({ prefetchedIntents });\n bootstrap(framework);\n\n const loggerFactory = framework.container.resolve<LoggerFactory>(DEP_KEYS.LOGGER_FACTORY);\n const log: Logger = loggerFactory.loggerFor(\"browser\");\n\n // 3. 路由初始 URL\n const initialAction = framework.routeUrl(window.location.pathname + window.location.search);\n\n // 4. 挂载应用(框架无关)\n const locale = document.documentElement.lang || defaultLocale;\n const target = document.getElementById(mountId)!;\n const updateApp = mount(target, { framework, locale });\n\n // 5. 注册 Action Handlers\n registerActionHandlers({\n framework,\n log,\n callbacks,\n updateApp,\n getScrollablePageElement: config.getScrollablePageElement,\n });\n\n // 6. 触发初始页面\n if (initialAction) {\n await framework.perform(initialAction.action);\n } else {\n updateApp({\n page: Promise.reject(new Error(\"404\")),\n isFirstPage: true,\n });\n }\n}\n","/**\n * ssrRender — 通用 SSR 渲染管线\n *\n * 1. 创建 Framework + 注册 Controllers\n * 2. routeUrl → Intent\n * 3. dispatch → Page 数据\n * 4. 调用应用层提供的渲染函数\n */\n\nimport {\n Framework,\n createServerContext,\n type BasePage,\n type FrameworkConfig,\n type MiddlewareResult,\n type PostLoadContext,\n type PrefetchedIntent,\n} from \"@finesoft/core\";\n\nexport interface SSRRenderOptions {\n /** 请求 URL */\n url: string;\n /** Framework 配置(含路由注册等) */\n frameworkConfig: FrameworkConfig;\n /** 注册 controllers 和路由的引导函数 */\n bootstrap: (framework: Framework) => void;\n /** 获取错误页面 */\n getErrorPage: (status: number, message: string) => BasePage;\n /** 应用层渲染函数(如 Svelte SSR render) */\n renderApp: (page: BasePage, framework: Framework) => SSRAppResult;\n /** 可选的 SSR 请求上下文(如自定义 fetch) */\n ssrContext?: SSRContext;\n}\n\n/** SSR 请求级上下文 */\nexport interface SSRContext {\n /** 自定义 fetch(如 Hono 内部路由回环) */\n fetch?: typeof globalThis.fetch;\n /** 原始 Request 对象(用于中间件读取 cookie/header) */\n request?: Request;\n}\n\nexport interface SSRAppResult {\n html: string;\n head: string;\n css: string;\n}\n\nexport interface SSRRenderResult {\n html: string;\n head: string;\n css: string;\n serverData: PrefetchedIntent[];\n /** 该路由的渲染模式(由 Router 返回) */\n renderMode?: string;\n /** 中间件要求的重定向(服务端应返回 HTTP 301/302) */\n redirect?: { url: string; status: number };\n}\n\nexport async function ssrRender(options: SSRRenderOptions): Promise<SSRRenderResult> {\n const { url, frameworkConfig, bootstrap, getErrorPage, renderApp, ssrContext } = options;\n\n // 将 SSR 上下文中的 fetch 合并到 frameworkConfig,注入 DI 容器\n const mergedConfig: FrameworkConfig = ssrContext?.fetch\n ? { ...frameworkConfig, fetch: ssrContext.fetch }\n : frameworkConfig;\n\n const framework = Framework.create(mergedConfig);\n bootstrap(framework);\n\n try {\n const parsed = new URL(url, \"http://localhost\");\n const fullPath = parsed.pathname + parsed.search;\n const match = framework.routeUrl(fullPath);\n\n // CSR 模式:跳过服务端渲染,返回空内容由客户端 JS 渲染\n if (match?.renderMode === \"csr\") {\n return {\n html: \"\",\n head: \"\",\n css: \"\",\n serverData: [],\n renderMode: \"csr\",\n };\n }\n\n let page: BasePage;\n let serverData: PrefetchedIntent[] = [];\n\n if (match) {\n // ===== beforeLoad 中间件 =====\n const navCtx = createServerContext({\n url: fullPath,\n intent: match.intent,\n container: framework.container,\n request: ssrContext?.request,\n });\n const beforeResult = await framework.runBeforeLoad(navCtx, match.beforeGuards);\n if (beforeResult.kind !== \"next\") {\n const earlyReturn = handleMiddlewareResult(\n beforeResult,\n getErrorPage,\n renderApp,\n framework,\n );\n if (earlyReturn) return earlyReturn;\n }\n\n try {\n page = (await framework.dispatch(match.intent)) as BasePage;\n serverData = [{ intent: match.intent, data: page }];\n } catch (e) {\n console.error(`[SSR] dispatch failed for intent \"${match.intent.id}\":`, e);\n page = getErrorPage(500, \"Internal error\");\n }\n\n // ===== afterLoad 中间件 =====\n const postCtx: PostLoadContext = {\n ...navCtx,\n page,\n };\n const afterResult = await framework.runAfterLoad(postCtx, match.afterGuards);\n if (afterResult.kind !== \"next\") {\n const lateReturn = handleMiddlewareResult(\n afterResult,\n getErrorPage,\n renderApp,\n framework,\n );\n if (lateReturn) return lateReturn;\n }\n } else {\n page = getErrorPage(404, \"Page not found\");\n }\n\n const result = renderApp(page, framework);\n\n return {\n html: result.html,\n head: result.head,\n css: result.css,\n serverData,\n renderMode: match?.renderMode,\n };\n } finally {\n framework.dispose();\n }\n}\n\n/**\n * 将中间件结果转换为 SSRRenderResult(如果需要短路返回)。\n * 返回 null 表示继续正常流程。\n */\nfunction handleMiddlewareResult(\n result: MiddlewareResult,\n getErrorPage: (status: number, message: string) => BasePage,\n renderApp: (page: BasePage, framework: Framework) => SSRAppResult,\n framework: Framework,\n): SSRRenderResult | null {\n switch (result.kind) {\n case \"next\":\n return null;\n case \"redirect\":\n return {\n html: \"\",\n head: \"\",\n css: \"\",\n serverData: [],\n redirect: { url: result.url, status: result.status },\n };\n case \"rewrite\":\n return {\n html: \"\",\n head: \"\",\n css: \"\",\n serverData: [],\n redirect: { url: result.url, status: 301 },\n };\n case \"deny\": {\n const errorPage = getErrorPage(result.status, result.message);\n const rendered = renderApp(errorPage, framework);\n return {\n html: rendered.html,\n head: rendered.head,\n css: rendered.css,\n serverData: [],\n };\n }\n }\n}\n","/**\n * createSSRRender — 工厂函数,返回可直接被 SSR 服务器调用的 render 函数\n *\n * 将一次性配置(bootstrap / getErrorPage / renderApp)绑定后,\n * 返回 `(url, locale) => Promise<SSRRenderResult>` 签名,\n * 与 @finesoft/server 的 SSRModule 接口对齐。\n */\n\nimport type { BasePage, Framework, FrameworkConfig } from \"@finesoft/core\";\nimport { ssrRender, type SSRAppResult, type SSRContext, type SSRRenderResult } from \"./render\";\n\nexport interface SSRRenderConfig {\n /** 注册 controllers 和路由的引导函数 */\n bootstrap: (framework: Framework) => void;\n\n /** 获取错误页面 */\n getErrorPage: (status: number, message: string) => BasePage;\n\n /**\n * 应用层渲染函数\n *\n * @param page - 当前页面数据\n * @param locale - 当前语言\n * @returns SSR 渲染结果 { html, head, css }\n */\n renderApp: (page: BasePage, locale: string) => SSRAppResult;\n\n /** Framework 构造配置(可选) */\n frameworkConfig?: FrameworkConfig;\n}\n\n/**\n * 创建 render 函数\n *\n * @returns `render(url, locale, ssrContext?)` — 供 @finesoft/server SSRModule 使用\n */\nexport function createSSRRender(\n config: SSRRenderConfig,\n): (url: string, locale: string, ssrContext?: SSRContext) => Promise<SSRRenderResult> {\n const { bootstrap, getErrorPage, renderApp, frameworkConfig } = config;\n\n return (url: string, locale: string, ssrContext?: SSRContext) =>\n ssrRender({\n url,\n frameworkConfig: frameworkConfig ?? {},\n bootstrap,\n getErrorPage,\n renderApp: (page) => renderApp(page, locale),\n ssrContext,\n });\n}\n","/**\n * serializeServerData — 将 PrefetchedIntents 数据序列化为安全的 JSON\n *\n * 返回值可安全嵌入 <script> 标签。\n */\n\nimport type { PrefetchedIntent } from \"@finesoft/core\";\n\nconst HTML_REPLACEMENTS: Record<string, string> = {\n \"<\": \"\\\\u003C\",\n \">\": \"\\\\u003E\",\n \"/\": \"\\\\u002F\",\n \"\\u2028\": \"\\\\u2028\",\n \"\\u2029\": \"\\\\u2029\",\n};\n\nconst HTML_ESCAPE_PATTERN = /[<>/\\u2028\\u2029]/g;\n\nexport function serializeServerData(data: PrefetchedIntent[]): string {\n const json = JSON.stringify(data);\n return json.replace(HTML_ESCAPE_PATTERN, (match) => HTML_REPLACEMENTS[match] ?? match);\n}\n","/**\n * 框架级声明式代理路由\n *\n * 将代理路由从业务层手写 Hono 路由,改为框架级配置。\n * 框架统一执行路径校验(SSRF 防护)、Host 限制、错误处理、响应头控制。\n */\n\nimport type { Hono } from \"hono\";\n\n/** 代理路由认证配置 */\nexport interface ProxyAuthConfig {\n /** 认证类型 */\n type: \"bearer\" | \"basic\";\n /** 环境变量名称(运行时从 process.env 读取) */\n envKey: string;\n}\n\n/** 声明式代理路由配置 */\nexport interface ProxyRouteConfig {\n /** URL 前缀,如 \"/api/apple\"(必须以 \"/\" 开头) */\n prefix: string;\n /** 代理目标地址(必须以 \"https://\" 开头) */\n target: string;\n /** HTTP 方法(默认 [\"all\"]) */\n methods?: (\"all\" | \"get\" | \"post\" | \"put\" | \"delete\" | \"patch\")[];\n /** 附加到代理请求的头部 */\n headers?: Record<string, string>;\n /** 认证配置 */\n auth?: ProxyAuthConfig;\n /** Cache-Control 响应头 */\n cache?: string;\n /** 是否跟随重定向(默认 false) */\n followRedirects?: boolean;\n}\n\n/**\n * 校验代理路径,防止 SSRF(协议相对 URL 绕过)。\n * 返回规范化的路径,或 null 表示非法。\n */\nfunction sanitizeProxyPath(raw: string): string | null {\n if (raw.startsWith(\"//\")) return null;\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\n/**\n * 校验代理配置合法性。\n * 在注册时(启动阶段)调用,非法配置直接抛错阻止启动。\n */\nfunction validateConfig(config: ProxyRouteConfig): void {\n if (!config.prefix.startsWith(\"/\")) {\n throw new Error(`[proxy] prefix must start with \"/\": \"${config.prefix}\"`);\n }\n if (!config.target.startsWith(\"https://\")) {\n throw new Error(`[proxy] target must use HTTPS: \"${config.target}\"`);\n }\n}\n\n/**\n * 注册声明式代理路由到 Hono app(运行时使用:dev / preview / createServer)\n */\nexport function registerProxyRoutes(app: Hono, configs: ProxyRouteConfig[]): void {\n for (const config of configs) {\n validateConfig(config);\n\n const methods = config.methods ?? [\"all\"];\n const pattern = `${config.prefix}/*`;\n\n const handler = async (c: any) => {\n const subPath = sanitizeProxyPath(c.req.path.replace(config.prefix, \"\"));\n if (!subPath) return c.text(\"Invalid path\", 400);\n\n const targetUrl = new URL(subPath, config.target);\n\n // 转发 query 参数\n const reqUrl = new URL(c.req.url);\n reqUrl.searchParams.forEach((v, k) => targetUrl.searchParams.set(k, v));\n\n // 构建请求头\n const headers: Record<string, string> = { ...config.headers };\n if (config.auth) {\n const token = process.env[config.auth.envKey] ?? \"\";\n if (token) {\n headers.Authorization =\n config.auth.type === \"bearer\" ? `Bearer ${token}` : `Basic ${token}`;\n }\n }\n\n try {\n const resp = await fetch(targetUrl.toString(), {\n headers,\n redirect: config.followRedirects ? \"follow\" : \"manual\",\n });\n const body = await resp.text();\n const respHeaders: Record<string, string> = {\n \"Content-Type\": resp.headers.get(\"Content-Type\") ?? \"application/json\",\n };\n if (config.cache) {\n respHeaders[\"Cache-Control\"] = config.cache;\n }\n return c.newResponse(body, resp.status as any, respHeaders);\n } catch (e) {\n console.error(`[Proxy ${config.prefix}]`, e);\n return c.json({ error: \"Proxy request failed\" }, 502);\n }\n };\n\n for (const method of methods) {\n (app as any)[method](pattern, handler);\n }\n }\n}\n\n/**\n * 生成代理路由的内联代码(用于 serverless/edge 入口,避免运行时依赖)\n */\nexport function generateProxyCode(configs: ProxyRouteConfig[]): string {\n if (!configs || configs.length === 0) return \"\";\n\n // 运行时也校验一遍\n for (const config of configs) {\n validateConfig(config);\n }\n\n const blocks: string[] = [];\n\n blocks.push(`\n// ─── 框架声明式代理路由 ───\nfunction _sanitizeProxyPath(raw) {\n if (raw.startsWith(\"//\")) return null;\n return raw.startsWith(\"/\") ? raw : \"/\" + raw;\n}\n`);\n\n for (const config of configs) {\n const methods = config.methods ?? [\"all\"];\n const pattern = `\"${config.prefix}/*\"`;\n const headersJson = JSON.stringify(config.headers ?? {});\n const cacheStr = config.cache ? JSON.stringify(config.cache) : \"null\";\n const redirect = config.followRedirects ? '\"follow\"' : '\"manual\"';\n\n let authCode = \"\";\n if (config.auth) {\n const envKey = JSON.stringify(config.auth.envKey);\n const prefix = config.auth.type === \"bearer\" ? \"Bearer \" : \"Basic \";\n authCode = `\n const _token = (typeof process !== \"undefined\" && process.env && process.env[${envKey}]) || \"\";\n if (_token) _headers.Authorization = \"${prefix}\" + _token;`;\n }\n\n const handlerCode = `async (c) => {\n const _sub = _sanitizeProxyPath(c.req.path.replace(${JSON.stringify(config.prefix)}, \"\"));\n if (!_sub) return c.text(\"Invalid path\", 400);\n const _target = new URL(_sub, ${JSON.stringify(config.target)});\n const _reqUrl = new URL(c.req.url);\n _reqUrl.searchParams.forEach((v, k) => _target.searchParams.set(k, v));\n const _headers = ${headersJson};${authCode}\n try {\n const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${redirect} });\n const _body = await _resp.text();\n const _rh = { \"Content-Type\": _resp.headers.get(\"Content-Type\") || \"application/json\" };\n if (${cacheStr}) _rh[\"Cache-Control\"] = ${cacheStr};\n return c.newResponse(_body, _resp.status, _rh);\n } catch (_e) {\n console.error(\"[Proxy ${config.prefix}]\", _e);\n return c.json({ error: \"Proxy request failed\" }, 502);\n }\n}`;\n\n for (const method of methods) {\n blocks.push(`app.${method}(${pattern}, ${handlerCode});`);\n }\n }\n\n return blocks.join(\"\\n\");\n}\n","/**\n * 适配器共享工具函数\n *\n * 提供 generateSSREntry / buildBundle / copyStaticAssets 三个方法,\n * 避免各适配器重复实现相同逻辑。\n */\n\nimport { generateProxyCode } from \"../proxy\";\nimport type {\n AdapterContext,\n BuildBundleOptions,\n CopyStaticAssetsOptions,\n GenerateSSREntryOptions,\n} from \"./types\";\n\nconst BUILD_TOOL_EXTERNALS = [\"vite\", \"esbuild\", \"rollup\", \"fsevents\", \"lightningcss\"];\n\n/**\n * 生成 SSR serverless/edge 入口源码\n *\n * 内联 parseAcceptLanguage / injectSSR 以避免\n * @finesoft/front → @finesoft/server → vite-plugin → import(\"vite\") 依赖链。\n */\nexport function generateSSREntry(ctx: AdapterContext, opts: GenerateSSREntryOptions): string {\n const setupImport = ctx.setupPath ? `import _setupDefault from \"./${ctx.setupPath}\";` : ``;\n const setupCall = ctx.setupPath\n ? `if (typeof _setupDefault === \"function\") await _setupDefault(app);`\n : ``;\n\n const locales = JSON.stringify(ctx.locales);\n const defaultLocale = JSON.stringify(ctx.defaultLocale);\n const renderModes = JSON.stringify(ctx.renderModes ?? {});\n\n // 平台缓存实现:平台自定义 或 内置内存 Map\n const cacheImpl = opts.platformCache\n ? opts.platformCache\n : `\nconst ISR_CACHE_MAX = 1000;\nconst _isrMap = new Map();\nasync function platformCacheGet(url) {\n return _isrMap.get(url) ?? null;\n}\nasync function platformCacheSet(url, html) {\n if (_isrMap.size >= ISR_CACHE_MAX) {\n const first = _isrMap.keys().next().value;\n _isrMap.delete(first);\n }\n _isrMap.set(url, html);\n}`;\n\n return `\nimport { Hono } from \"hono\";\n${opts.platformImport}\nimport { render, serializeServerData } from \"./${ctx.ssrEntry}\";\n${setupImport}\n\nconst TEMPLATE = ${JSON.stringify(ctx.templateHtml)};\nconst LOCALES = ${locales};\nconst DEFAULT_LOCALE = ${defaultLocale};\nconst RENDER_MODES = ${renderModes};\n${cacheImpl}\n\nfunction parseAcceptLanguage(header) {\n if (!header) return DEFAULT_LOCALE;\n const langs = header.split(\",\").map(p => {\n const [l, q] = p.trim().split(\";q=\");\n return { l: l.trim().toLowerCase(), q: q ? (+q || 0) : 1 };\n }).sort((a, b) => b.q - a.q);\n for (const { l } of langs) {\n const prefix = l.split(\"-\")[0];\n if (LOCALES.includes(prefix)) return prefix;\n }\n return DEFAULT_LOCALE;\n}\n\nfunction injectSSR(t, locale, head, css, html, data) {\n return t\n .replace(\"<!--ssr-lang-->\", locale)\n .replace(\"<!--ssr-head-->\", head + \"\\\\n<style>\" + css + \"</style>\")\n .replace(\"<!--ssr-body-->\", html)\n .replace(\"<!--ssr-data-->\", '<script id=\"serialized-server-data\" type=\"application/json\">' + data + \"</script>\");\n}\n\nfunction injectCSRShell(t, locale) {\n return t\n .replace(\"<!--ssr-lang-->\", locale)\n .replace(\"<!--ssr-head-->\", \"\")\n .replace(\"<!--ssr-body-->\", \"\")\n .replace(\"<!--ssr-data-->\", \"\");\n}\n\nfunction matchRenderMode(url) {\n const path = url.split(\"?\")[0];\n if (RENDER_MODES[path]) return RENDER_MODES[path];\n for (const [pattern, mode] of Object.entries(RENDER_MODES)) {\n if (pattern.includes(\"*\")) {\n const escaped = pattern.replace(/[.+?^\\${}()|[\\\\]\\\\\\\\]/g, \"\\\\\\\\$&\");\n const re = new RegExp(\"^\" + escaped.replace(/\\\\*/g, \".*\") + \"$\");\n if (re.test(path)) return mode;\n }\n }\n return null;\n}\n\nconst app = new Hono();\n${generateProxyCode(ctx.proxies ?? [])}\n${setupCall}\n${opts.platformMiddleware ?? \"\"}\n\n// 内部 fetch 回环:SSR 控制器的 fetch 请求直接走 Hono 内存路由\n// 深度通过请求头传递,并发安全且能跨渲染正确追踪递归\nconst _SSR_DEPTH_HEADER = \"x-ssr-depth\";\nconst _MAX_SSR_DEPTH = 5;\n\nfunction _createInternalFetch(depth) {\n return function(input, init) {\n if (typeof input === \"string\" && input.startsWith(\"/\")) {\n const req = new Request(\"http://localhost\" + input, init);\n req.headers.set(_SSR_DEPTH_HEADER, String(depth));\n return app.fetch(req);\n }\n return globalThis.fetch(input, init);\n };\n}\n\napp.get(\"*\", async (c) => {\n // 递归深度保护:从请求头读取 SSR 深度\n const _ssrDepth = parseInt(c.req.header(_SSR_DEPTH_HEADER) || \"0\", 10);\n if (_ssrDepth >= _MAX_SSR_DEPTH) {\n return c.text(\"SSR recursion loop detected\", 508);\n }\n\n const url = c.req.path + (c.req.url.includes(\"?\") ? \"?\" + c.req.url.split(\"?\")[1] : \"\");\n try {\n const locale = parseAcceptLanguage(c.req.header(\"accept-language\"));\n\n // Vite 配置级别覆盖: CSR 直接返回空壳\n const overrideMode = matchRenderMode(url);\n if (overrideMode === \"csr\") {\n return c.html(injectCSRShell(TEMPLATE, locale));\n }\n\n // ISR 缓存命中(key 含 locale,避免跨语言缓存污染)\n const _cacheKey = locale + \":\" + url;\n const cached = await platformCacheGet(_cacheKey);\n if (cached) return c.html(cached);\n\n const { html: appHtml, head, css, serverData, renderMode } = await render(url, locale, { fetch: _createInternalFetch(_ssrDepth + 1) });\n\n // 路由级 CSR\n if (renderMode === \"csr\") {\n return c.html(injectCSRShell(TEMPLATE, locale));\n }\n\n const serializedData = serializeServerData(serverData);\n const finalHtml = injectSSR(TEMPLATE, locale, head, css, appHtml, serializedData);\n\n // Prerender ISR 缓存(包括 Vite 配置覆盖和路由级)\n if (renderMode === \"prerender\" || overrideMode === \"prerender\") {\n await platformCacheSet(_cacheKey, finalHtml);\n ${opts.platformPrerenderResponseHook ?? \"\"}\n }\n\n return c.html(finalHtml);\n } catch (e) {\n console.error(\"[SSR Error]\", e);\n return c.text(\"Internal Server Error\", 500);\n }\n});\n\n${opts.platformExport}\n`;\n}\n\n/** 用 Vite SSR 模式构建 bundle */\nexport async function buildBundle(ctx: AdapterContext, opts: BuildBundleOptions): Promise<void> {\n await ctx.vite.build({\n root: ctx.root,\n build: {\n ssr: opts.entry,\n outDir: opts.outDir,\n emptyOutDir: true,\n target: opts.target ?? \"node18\",\n rollupOptions: {\n output: { entryFileNames: opts.fileName ?? \"index.mjs\" },\n },\n },\n ssr: {\n noExternal: opts.noExternal !== false,\n external: opts.external ?? BUILD_TOOL_EXTERNALS,\n },\n resolve: ctx.resolvedResolve,\n css: ctx.resolvedCss,\n });\n}\n\n/** 复制 dist/client 静态资源到目标目录 */\nexport function copyStaticAssets(\n ctx: AdapterContext,\n destDir: string,\n opts?: CopyStaticAssetsOptions,\n): void {\n const { fs, path } = ctx;\n fs.cpSync(path.resolve(ctx.root, \"dist/client\"), destDir, {\n recursive: true,\n });\n if (opts?.excludeHtml !== false) {\n fs.rmSync(path.join(destDir, \"index.html\"), { force: true });\n }\n}\n\nexport interface PrerenderResult {\n url: string;\n html: string;\n}\n\n/**\n * 构建时预渲染 prerender 路由。\n *\n * 1. 加载路由定义文件,找出 renderMode === \"prerender\" 的路由\n * 2. 合并 ctx.renderModes 配置覆盖\n * 3. 渲染每个 URL × locale\n */\nexport async function prerenderRoutes(ctx: AdapterContext): Promise<PrerenderResult[]> {\n const { fs, path, root, vite } = ctx;\n const { pathToFileURL } = await import(/* @vite-ignore */ \"node:url\");\n\n const routesExport = ctx.bootstrapEntry ?? \"src/lib/bootstrap.ts\";\n\n // ── 1. 尝试构建并加载路由定义(文件不存在则跳过) ──\n let routes: Array<{ path: string; renderMode?: string }> = [];\n const routesFileExists = fs.existsSync(path.resolve(root, routesExport));\n\n if (routesFileExists) {\n await vite.build({\n root,\n build: {\n ssr: routesExport,\n outDir: path.resolve(root, \"dist/server\"),\n emptyOutDir: false,\n rollupOptions: {\n output: { entryFileNames: \"_routes_prerender.mjs\" },\n },\n },\n resolve: ctx.resolvedResolve,\n });\n\n const routesPath = pathToFileURL(\n path.resolve(root, \"dist/server/_routes_prerender.mjs\"),\n ).href;\n const routesMod = await import(/* @vite-ignore */ routesPath);\n routes = routesMod.routes ?? routesMod.default ?? [];\n\n // 清理临时文件\n fs.rmSync(path.resolve(root, \"dist/server/_routes_prerender.mjs\"), {\n force: true,\n });\n }\n\n // ── 2. 收集 prerender 路径 ──\n const prerenderPaths = new Set<string>();\n\n // 路由定义级别\n for (const r of routes) {\n if (r.renderMode === \"prerender\" && r.path && !r.path.includes(\":\")) {\n prerenderPaths.add(r.path);\n }\n }\n\n // Vite 配置覆盖级别\n if (ctx.renderModes) {\n for (const [pattern, mode] of Object.entries(ctx.renderModes)) {\n if (mode === \"prerender\" && !pattern.includes(\"*\") && !pattern.includes(\":\")) {\n prerenderPaths.add(pattern);\n }\n }\n }\n\n if (prerenderPaths.size === 0) return [];\n\n // ── 3. 加载 SSR 模块 ──\n const ssrPath = pathToFileURL(path.resolve(root, \"dist/server/ssr.js\")).href;\n const ssrModule = await import(/* @vite-ignore */ ssrPath);\n\n // ── 4. 渲染每个 URL × locale ──\n const results: PrerenderResult[] = [];\n\n for (const routePath of prerenderPaths) {\n for (const locale of ctx.locales) {\n const url =\n locale === ctx.defaultLocale\n ? routePath\n : `/${locale}${routePath === \"/\" ? \"\" : routePath}`;\n try {\n const {\n html: appHtml,\n head,\n css,\n serverData,\n } = await ssrModule.render(url, locale);\n\n const serializedData = ssrModule.serializeServerData(serverData);\n\n const finalHtml = ctx.templateHtml\n .replace(\"<!--ssr-lang-->\", locale)\n .replace(\"<!--ssr-head-->\", head + \"\\n<style>\" + css + \"</style>\")\n .replace(\"<!--ssr-body-->\", appHtml)\n .replace(\n \"<!--ssr-data-->\",\n '<script id=\"serialized-server-data\" type=\"application/json\">' +\n serializedData +\n \"</script>\",\n );\n\n results.push({ url, html: finalHtml });\n } catch (e) {\n console.warn(` [prerender] Failed to render ${url}:`, e);\n }\n }\n }\n\n if (results.length > 0) {\n console.log(\n ` Pre-rendered ${results.length} pages (${prerenderPaths.size} routes × ${ctx.locales.length} locales)\\n`,\n );\n }\n\n return results;\n}\n","/**\n * Cloudflare Pages 适配器\n *\n * 生成 dist/cloudflare/ 目录:\n * - _worker.js — Workers 入口(Hono 原生支持 CF fetch 接口)\n * - assets/ — 静态资源\n *\n * 注意:Cloudflare Workers 不支持原生 Node.js API。\n * 若 setup 代理使用了 process.env,需在 wrangler.toml 启用 nodejs_compat。\n */\n\nimport { buildBundle, copyStaticAssets, generateSSREntry, prerenderRoutes } from \"./shared\";\nimport type { Adapter } from \"./types\";\n\nexport function cloudflareAdapter(): Adapter {\n return {\n name: \"cloudflare\",\n async build(ctx) {\n const { fs, path, root } = ctx;\n const outputDir = path.resolve(root, \"dist/cloudflare\");\n\n fs.rmSync(outputDir, { recursive: true, force: true });\n\n // Hono 原生支持 CF Workers 的 fetch 接口,直接 export default app\n const entrySource = generateSSREntry(ctx, {\n platformImport: ``,\n platformExport: `export default app;`,\n // Cloudflare Cache API — 持久化 ISR 缓存到 CDN 边缘节点\n platformCache: `\nconst ISR_CACHE_TTL = 3600; // 1 hour\nasync function platformCacheGet(url) {\n try {\n const cache = caches.default;\n const cacheKey = new Request(\"https://isr-cache/\" + encodeURIComponent(url));\n const resp = await cache.match(cacheKey);\n if (resp) return await resp.text();\n } catch {}\n return null;\n}\nasync function platformCacheSet(url, html) {\n try {\n const cache = caches.default;\n const cacheKey = new Request(\"https://isr-cache/\" + encodeURIComponent(url));\n const resp = new Response(html, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"public, max-age=\" + ISR_CACHE_TTL },\n });\n await cache.put(cacheKey, resp);\n } catch {}\n}`,\n });\n\n const tempEntry = path.resolve(root, \".cf-entry.tmp.mjs\");\n fs.writeFileSync(tempEntry, entrySource);\n\n try {\n await buildBundle(ctx, {\n entry: \".cf-entry.tmp.mjs\",\n outDir: outputDir,\n target: \"es2022\",\n fileName: \"_worker.js\",\n // 使用默认 external(vite/esbuild/rollup/fsevents/lightningcss)\n // 这些构建工具运行时不需要,且 fsevents 是 macOS .node 原生二进制无法打包\n });\n\n // 静态资源\n copyStaticAssets(ctx, path.resolve(outputDir, \"assets\"));\n\n // 构建时预渲染\n const prerendered = await prerenderRoutes(ctx);\n for (const { url, html } of prerendered) {\n const filePath =\n url === \"/\"\n ? path.join(outputDir, \"assets\", \"index.html\")\n : path.join(outputDir, \"assets\", url, \"index.html\");\n fs.mkdirSync(path.resolve(filePath, \"..\"), {\n recursive: true,\n });\n fs.writeFileSync(filePath, html);\n }\n } finally {\n fs.rmSync(tempEntry, { force: true });\n }\n\n console.log(\" Cloudflare output → dist/cloudflare/\\n\");\n },\n };\n}\n","/**\n * Netlify 适配器 — Netlify Functions v2\n *\n * 生成:\n * - .netlify/functions-internal/ssr/index.mjs — Serverless Function\n * - dist/client/_redirects — 路由重写规则\n */\n\nimport { buildBundle, generateSSREntry, prerenderRoutes } from \"./shared\";\nimport type { Adapter } from \"./types\";\n\nexport function netlifyAdapter(): Adapter {\n return {\n name: \"netlify\",\n async build(ctx) {\n const { fs, path, root } = ctx;\n const funcDir = path.resolve(root, \".netlify/functions-internal/ssr\");\n\n fs.rmSync(path.resolve(root, \".netlify\"), {\n recursive: true,\n force: true,\n });\n\n const entrySource = generateSSREntry(ctx, {\n platformImport: `import { handle } from \"hono/netlify\";`,\n platformExport: `export default handle(app);\nexport const config = { path: \"/*\", preferStatic: true };`,\n // Netlify CDN 缓存 — 使用 Netlify-CDN-Cache-Control 头做 ISR\n platformCache: `\nconst ISR_SWR_TTL = 3600;\nconst ISR_CACHE_MAX = 1000;\nconst _isrMap = new Map();\nasync function platformCacheGet(url) {\n return _isrMap.get(url) ?? null;\n}\nasync function platformCacheSet(url, html) {\n if (_isrMap.size >= ISR_CACHE_MAX) {\n const first = _isrMap.keys().next().value;\n _isrMap.delete(first);\n }\n _isrMap.set(url, html);\n}`,\n platformPrerenderResponseHook: `c.header(\"Cache-Control\", \"public, max-age=0, must-revalidate\");\n c.header(\"Netlify-CDN-Cache-Control\", \"public, max-age=\" + ISR_SWR_TTL + \", stale-while-revalidate=\" + ISR_SWR_TTL + \", durable\");`,\n });\n\n const tempEntry = path.resolve(root, \".netlify-entry.tmp.mjs\");\n fs.writeFileSync(tempEntry, entrySource);\n\n try {\n await buildBundle(ctx, {\n entry: \".netlify-entry.tmp.mjs\",\n outDir: funcDir,\n target: \"node18\",\n });\n } finally {\n fs.rmSync(tempEntry, { force: true });\n }\n\n // _redirects — 静态文件优先,其余走 SSR function\n const redirects = `/* /.netlify/functions/ssr 200\\n`;\n fs.writeFileSync(path.resolve(root, \"dist/client/_redirects\"), redirects);\n\n // 构建时预渲染\n const prerendered = await prerenderRoutes(ctx);\n const clientDir = path.resolve(root, \"dist/client\");\n for (const { url, html } of prerendered) {\n const filePath =\n url === \"/\"\n ? path.join(clientDir, \"index.html\")\n : path.join(clientDir, url, \"index.html\");\n fs.mkdirSync(path.resolve(filePath, \"..\"), { recursive: true });\n fs.writeFileSync(filePath, html);\n }\n\n console.log(\n \" Netlify output → .netlify/functions-internal/ssr/\\n\" +\n \" Publish dir: dist/client/\\n\",\n );\n },\n };\n}\n","/**\n * Node 适配器 — 独立 HTTP 服务器\n *\n * 生成 dist/server/index.mjs,使用 @hono/node-server 监听端口。\n * 运行:node dist/server/index.mjs\n */\n\nimport { buildBundle, generateSSREntry, prerenderRoutes } from \"./shared\";\nimport type { Adapter } from \"./types\";\n\nexport function nodeAdapter(): Adapter {\n return {\n name: \"node\",\n async build(ctx) {\n const { fs, path, root } = ctx;\n\n const entrySource = generateSSREntry(ctx, {\n platformImport: `import { serve } from \"@hono/node-server\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";`,\n platformMiddleware: `\n// 预渲染文件中间件:检查 dist/prerender/ 下是否有对应的静态 HTML\nconst __entry_dirname = dirname(fileURLToPath(import.meta.url));\nconst prerenderDir = resolve(__entry_dirname, \"../prerender\");\n\napp.use(\"*\", async (c, next) => {\n const urlPath = c.req.path;\n const candidates = [\n resolve(prerenderDir, \".\" + urlPath, \"index.html\"),\n resolve(prerenderDir, \".\" + urlPath + \".html\"),\n ];\n if (urlPath === \"/\") candidates.unshift(resolve(prerenderDir, \"index.html\"));\n for (const f of candidates) {\n if (existsSync(f)) {\n const html = readFileSync(f, \"utf-8\");\n return c.html(html);\n }\n }\n await next();\n});\n`,\n platformExport: `\nconst port = +(process.env.PORT || 3000);\nserve({ fetch: app.fetch, port }, (info) => {\n console.log(\\`Server running at http://localhost:\\${info.port}\\`);\n});\n`,\n });\n\n const tempEntry = path.resolve(root, \".node-entry.tmp.mjs\");\n fs.writeFileSync(tempEntry, entrySource);\n\n try {\n await buildBundle(ctx, {\n entry: \".node-entry.tmp.mjs\",\n outDir: path.resolve(root, \"dist/server\"),\n target: \"node18\",\n });\n } finally {\n fs.rmSync(tempEntry, { force: true });\n }\n\n // 构建时预渲染 prerender 路由\n const prerendered = await prerenderRoutes(ctx);\n if (prerendered.length > 0) {\n const prerenderDir = path.resolve(root, \"dist/prerender\");\n fs.mkdirSync(prerenderDir, { recursive: true });\n for (const { url, html } of prerendered) {\n const filePath =\n url === \"/\"\n ? path.join(prerenderDir, \"index.html\")\n : path.join(prerenderDir, url, \"index.html\");\n fs.mkdirSync(path.resolve(filePath, \"..\"), {\n recursive: true,\n });\n fs.writeFileSync(filePath, html);\n }\n }\n\n console.log(\n \" Node output → dist/server/index.mjs\\n\" + \" Run: node dist/server/index.mjs\\n\",\n );\n },\n };\n}\n","/**\n * Static 适配器 — 构建时预渲染\n *\n * 加载 SSR 模块和路由定义,将无参数路由自动预渲染为静态 HTML。\n * 动态参数路由通过 dynamicRoutes 选项补充具体 URL。\n *\n * 输出:dist/static/ — 纯静态站点,可部署到任何静态托管。\n */\n\nimport type { Adapter, AdapterContext } from \"./types\";\n\nexport interface StaticAdapterOptions {\n /**\n * 导出 routes 数组的文件路径(相对于项目根目录)。\n * 默认 \"src/lib/bootstrap.ts\"。\n * 文件需 export 一个 RouteDefinition[] 类型的 routes 变量。\n */\n routesExport?: string;\n /**\n * 额外的动态路由 URL(带具体参数值),如:\n * [\"/product/123\", \"/list/games\"]\n */\n dynamicRoutes?: string[];\n}\n\nexport function staticAdapter(opts: StaticAdapterOptions = {}): Adapter {\n return {\n name: \"static\",\n async build(ctx) {\n const { fs, path, root } = ctx;\n const outputDir = path.resolve(root, \"dist/static\");\n\n fs.rmSync(outputDir, { recursive: true, force: true });\n fs.mkdirSync(outputDir, { recursive: true });\n\n // 加载 SSR 模块\n const { pathToFileURL } = await import(/* @vite-ignore */ \"node:url\");\n const ssrPath = pathToFileURL(path.resolve(root, \"dist/server/ssr.js\")).href;\n const ssrModule = await import(/* @vite-ignore */ ssrPath);\n\n // 先复制静态资源(JS/CSS 等),排除模板 index.html\n ctx.copyStaticAssets(outputDir, { excludeHtml: true });\n\n // 提取路由列表(含 renderMode)\n const { paths: routePaths, defs: routeDefs } = await extractRoutesWithModes(ctx, opts);\n const allUrls: string[] = [];\n\n // 对每个路由 × 每个 locale 生成 URL\n for (const routePath of routePaths) {\n for (const locale of ctx.locales) {\n const url =\n locale === ctx.defaultLocale\n ? routePath\n : `/${locale}${routePath === \"/\" ? \"\" : routePath}`;\n allUrls.push(url);\n }\n }\n\n console.log(\n ` Pre-rendering ${allUrls.length} pages (${routePaths.length} routes × ${ctx.locales.length} locales)...\\n`,\n );\n\n // 预渲染每个 URL\n for (const url of allUrls) {\n try {\n // 从 URL 推断 locale\n const locale = inferLocale(url, ctx.locales, ctx.defaultLocale);\n\n // 检查渲染模式:路由级 + Vite 配置覆盖\n const routeDef = routeDefs.find(\n (r) => r.path === stripLocalePrefix(url, ctx.locales),\n );\n const mode = resolveRenderMode(\n stripLocalePrefix(url, ctx.locales),\n routeDef?.renderMode,\n ctx.renderModes,\n );\n\n let finalHtml: string;\n\n if (mode === \"csr\") {\n // CSR: 空壳 HTML,客户端 JS 渲染\n finalHtml = injectCSRShellForStatic(ctx.templateHtml, locale);\n } else {\n const {\n html: appHtml,\n head,\n css,\n serverData,\n } = await ssrModule.render(url, locale);\n\n const serializedData = ssrModule.serializeServerData(serverData);\n\n finalHtml = injectSSRForStatic(\n ctx.templateHtml,\n locale,\n head,\n css,\n appHtml,\n serializedData,\n );\n }\n\n // 写入文件:/foo → dist/static/foo/index.html\n const filePath =\n url === \"/\"\n ? path.join(outputDir, \"index.html\")\n : path.join(outputDir, url, \"index.html\");\n\n fs.mkdirSync(path.resolve(filePath, \"..\"), {\n recursive: true,\n });\n fs.writeFileSync(filePath, finalHtml);\n } catch (e) {\n console.warn(` [static] Failed to render ${url}:`, e);\n }\n }\n\n console.log(` Static output → dist/static/\\n`);\n },\n };\n}\n\n/** 从路由文件提取无参数路由 + 合并 dynamicRoutes(含 renderMode) */\nasync function extractRoutesWithModes(\n ctx: AdapterContext,\n opts: StaticAdapterOptions,\n): Promise<{\n paths: string[];\n defs: Array<{ path: string; renderMode?: string }>;\n}> {\n const routesFile = opts.routesExport ?? \"src/lib/bootstrap.ts\";\n const paths: string[] = [];\n const defs: Array<{ path: string; renderMode?: string }> = [];\n\n try {\n // 使用 Vite SSR 构建加载路由文件\n const { pathToFileURL } = await import(/* @vite-ignore */ \"node:url\");\n\n // 先构建路由文件\n await ctx.vite.build({\n root: ctx.root,\n build: {\n ssr: routesFile,\n outDir: ctx.path.resolve(ctx.root, \"dist/server\"),\n emptyOutDir: false,\n rollupOptions: {\n output: { entryFileNames: \"_routes.mjs\" },\n },\n },\n resolve: ctx.resolvedResolve,\n });\n\n const routesPath = pathToFileURL(\n ctx.path.resolve(ctx.root, \"dist/server/_routes.mjs\"),\n ).href;\n const routesMod = await import(/* @vite-ignore */ routesPath);\n\n // 查找导出的 routes 数组\n const routes: Array<{ path: string; renderMode?: string }> =\n routesMod.routes ?? routesMod.default;\n\n if (Array.isArray(routes)) {\n for (const r of routes) {\n if (r.path && !r.path.includes(\":\")) {\n paths.push(r.path);\n defs.push({ path: r.path, renderMode: r.renderMode });\n }\n }\n }\n\n // 清理临时文件\n ctx.fs.rmSync(ctx.path.resolve(ctx.root, \"dist/server/_routes.mjs\"), {\n force: true,\n });\n } catch (e) {\n console.warn(` [static] Could not load routes from \"${routesFile}\". Using \"/\" only.`, e);\n if (paths.length === 0) paths.push(\"/\");\n }\n\n // 合并 dynamicRoutes\n if (opts.dynamicRoutes) {\n for (const r of opts.dynamicRoutes) {\n if (!paths.includes(r)) paths.push(r);\n }\n }\n\n // 至少包含根路径\n if (paths.length === 0) paths.push(\"/\");\n\n return { paths, defs };\n}\n\n/** 从 URL 推断 locale */\nfunction inferLocale(url: string, locales: string[], defaultLocale: string): string {\n const segments = url.split(\"/\").filter(Boolean);\n if (segments.length > 0 && locales.includes(segments[0])) {\n return segments[0];\n }\n return defaultLocale;\n}\n\n/** 内联 SSR 注入(同 shared 中的逻辑) */\nfunction injectSSRForStatic(\n template: string,\n locale: string,\n head: string,\n css: string,\n html: string,\n serializedData: string,\n): string {\n return template\n .replace(\"<!--ssr-lang-->\", locale)\n .replace(\"<!--ssr-head-->\", head + \"\\n<style>\" + css + \"</style>\")\n .replace(\"<!--ssr-body-->\", html)\n .replace(\n \"<!--ssr-data-->\",\n '<script id=\"serialized-server-data\" type=\"application/json\">' +\n serializedData +\n \"</script>\",\n );\n}\n\n/** CSR 空壳注入 */\nfunction injectCSRShellForStatic(template: string, locale: string): string {\n return template\n .replace(\"<!--ssr-lang-->\", locale)\n .replace(\"<!--ssr-head-->\", \"\")\n .replace(\"<!--ssr-body-->\", \"\")\n .replace(\"<!--ssr-data-->\", \"\");\n}\n\n/** 从 URL 去除 locale 前缀,还原路由路径 */\nfunction stripLocalePrefix(url: string, locales: string[]): string {\n const segments = url.split(\"/\").filter(Boolean);\n if (segments.length > 0 && locales.includes(segments[0])) {\n const rest = segments.slice(1).join(\"/\");\n return rest ? `/${rest}` : \"/\";\n }\n return url;\n}\n\n/** 解析最终渲染模式:Vite 配置覆盖 > 路由级 > 默认 \"ssr\" */\nfunction resolveRenderMode(\n routePath: string,\n routeRenderMode?: string,\n renderModes?: Record<string, string>,\n): string {\n // Vite 配置覆盖优先\n if (renderModes) {\n if (renderModes[routePath]) return renderModes[routePath];\n for (const [pattern, mode] of Object.entries(renderModes)) {\n if (pattern.includes(\"*\")) {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(\"^\" + escaped.replace(/\\*/g, \".*\") + \"$\");\n if (re.test(routePath)) return mode;\n }\n }\n }\n return routeRenderMode ?? \"ssr\";\n}\n","/**\n * Vercel 适配器 — Build Output API v3\n *\n * 生成 .vercel/output/ 目录:\n * - config.json — 路由规则\n * - static/ — 静态资源\n * - functions/ssr.func/ — Serverless Function\n */\n\nimport { buildBundle, copyStaticAssets, generateSSREntry, prerenderRoutes } from \"./shared\";\nimport type { Adapter } from \"./types\";\n\nexport function vercelAdapter(): Adapter {\n return {\n name: \"vercel\",\n async build(ctx) {\n const { fs, path, root } = ctx;\n const outputDir = path.resolve(root, \".vercel/output\");\n\n // 清理旧输出\n fs.rmSync(outputDir, { recursive: true, force: true });\n\n // 生成入口源码\n // Vercel Serverless (launcherType: \"Nodejs\") 传入 Node.js IncomingMessage,\n // 必须用 @hono/node-server 转换为 Web Request,而非 hono/vercel 的 handle。\n // 因为 dest 统一重写到 /ssr,req.url 会丢失原始路径,\n // 需要从 Vercel 的 x-now-route-matches 头中恢复实际请求路径。\n const entrySource = generateSSREntry(ctx, {\n platformImport: `import { getRequestListener } from \"@hono/node-server\";`,\n platformExport: [\n `const _listener = getRequestListener(app.fetch);`,\n `export default (req, res) => {`,\n ` const m = req.headers[\"x-now-route-matches\"];`,\n ` if (typeof m === \"string\") {`,\n ` try {`,\n ` const p = new URLSearchParams(m);`,\n ` const c = p.get(\"1\");`,\n ` if (c != null) {`,\n ` const qi = (req.url || \"\").indexOf(\"?\");`,\n ` const qs = qi !== -1 ? req.url.slice(qi) : \"\";`,\n ` req.url = \"/\" + decodeURIComponent(c) + qs;`,\n ` }`,\n ` } catch {}`,\n ` }`,\n ` return _listener(req, res);`,\n `};`,\n ].join(\"\\n\"),\n });\n\n // 写入临时入口文件\n const tempEntry = path.resolve(root, \".vercel-entry.tmp.mjs\");\n fs.writeFileSync(tempEntry, entrySource);\n\n try {\n const funcDir = path.resolve(root, \".vercel/output/functions/ssr.func\");\n\n // 构建 serverless function\n await buildBundle(ctx, {\n entry: \".vercel-entry.tmp.mjs\",\n outDir: funcDir,\n target: \"node18\",\n });\n\n // .vc-config.json\n fs.writeFileSync(\n path.resolve(funcDir, \".vc-config.json\"),\n JSON.stringify(\n {\n runtime: \"nodejs20.x\",\n handler: \"index.mjs\",\n launcherType: \"Nodejs\",\n },\n null,\n 2,\n ),\n );\n\n // 静态资源\n copyStaticAssets(ctx, path.resolve(root, \".vercel/output/static\"));\n\n // 路由配置:静态文件优先,其余全部路由到 /ssr 函数\n // Vercel 会在 x-now-route-matches 头中携带正则捕获组,\n // 入口代码据此恢复原始请求路径\n fs.writeFileSync(\n path.resolve(root, \".vercel/output/config.json\"),\n JSON.stringify(\n {\n version: 3,\n routes: [{ handle: \"filesystem\" }, { src: \"/(.*)\", dest: \"/ssr\" }],\n },\n null,\n 2,\n ),\n );\n } finally {\n fs.rmSync(tempEntry, { force: true });\n }\n // 构建时预渲染 prerender 路由\n const prerendered = await prerenderRoutes(ctx);\n const staticDir = path.resolve(root, \".vercel/output/static\");\n for (const { url, html } of prerendered) {\n const filePath =\n url === \"/\"\n ? path.join(staticDir, \"index.html\")\n : path.join(staticDir, url, \"index.html\");\n fs.mkdirSync(path.resolve(filePath, \"..\"), { recursive: true });\n fs.writeFileSync(filePath, html);\n }\n\n // 为预渲染路由写入 Vercel ISR 配置(overrides)\n if (prerendered.length > 0) {\n const configPath = path.resolve(root, \".vercel/output/config.json\");\n const config = JSON.parse(fs.readFileSync(configPath, \"utf-8\"));\n config.overrides = config.overrides ?? {};\n for (const { url } of prerendered) {\n const key = url === \"/\" ? \"index.html\" : `${url.replace(/^\\//, \"\")}/index.html`;\n config.overrides[key] = {\n path: url === \"/\" ? \"/\" : url,\n contentType: \"text/html; charset=utf-8\",\n };\n }\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n }\n\n console.log(\" Vercel output → .vercel/output/\\n\");\n },\n };\n}\n","/**\n * resolveAdapter — 字符串 → Adapter 映射\n */\n\nimport { autoAdapter } from \"./auto\";\nimport { cloudflareAdapter } from \"./cloudflare\";\nimport { netlifyAdapter } from \"./netlify\";\nimport { nodeAdapter } from \"./node\";\nimport { staticAdapter } from \"./static\";\nimport type { Adapter } from \"./types\";\nimport { vercelAdapter } from \"./vercel\";\n\nexport function resolveAdapter(value: string | Adapter): Adapter {\n if (typeof value !== \"string\") return value;\n\n switch (value) {\n case \"vercel\":\n return vercelAdapter();\n case \"cloudflare\":\n return cloudflareAdapter();\n case \"netlify\":\n return netlifyAdapter();\n case \"node\":\n return nodeAdapter();\n case \"static\":\n return staticAdapter();\n case \"auto\":\n return autoAdapter();\n default:\n throw new Error(\n `[finesoft] Unknown adapter: \"${value}\". ` +\n `Available: vercel, cloudflare, netlify, node, static, auto`,\n );\n }\n}\n","/**\n * Auto 适配器 — 根据环境变量自动选择目标平台\n *\n * 检测顺序:\n * VERCEL → vercel\n * CF_PAGES → cloudflare\n * NETLIFY → netlify\n * (default) → node\n */\n\nimport { resolveAdapter } from \"./resolve\";\nimport type { Adapter } from \"./types\";\n\nexport function autoAdapter(): Adapter {\n return {\n name: \"auto\",\n async build(ctx) {\n const detected = detectPlatform();\n console.log(` [auto] Detected platform: ${detected}\\n`);\n const adapter = resolveAdapter(detected);\n return adapter.build(ctx);\n },\n };\n}\n\nfunction detectPlatform(): string {\n if (process.env.VERCEL) return \"vercel\";\n if (process.env.CF_PAGES) return \"cloudflare\";\n if (process.env.NETLIFY) return \"netlify\";\n return \"node\";\n}\n","/**\n * runtime — 运行时检测 + 项目根路径推导\n */\n\nexport interface RuntimeInfo {\n isDeno: boolean;\n isBun: boolean;\n isVercel: boolean;\n isProduction: boolean;\n}\n\n/** 检测当前运行时环境 */\nexport function detectRuntime(): RuntimeInfo {\n return {\n isDeno: typeof (globalThis as any).Deno !== \"undefined\",\n isBun: typeof (globalThis as any).Bun !== \"undefined\",\n isVercel: !!process.env.VERCEL,\n isProduction: process.env.NODE_ENV === \"production\",\n };\n}\n\n/**\n * 从 `import.meta.url` 推导项目根路径\n *\n * @param importMetaUrl - 调用方的 `import.meta.url`\n * @param levelsUp - 向上移动多少级(默认 0,即调用方所在目录就是项目根)\n */\nexport async function resolveRoot(importMetaUrl: string, levelsUp = 0): Promise<string> {\n const isDeno = typeof (globalThis as any).Deno !== \"undefined\";\n\n if (isDeno) {\n let url = new URL(importMetaUrl);\n for (let i = 0; i < levelsUp; i++) {\n url = new URL(\"..\", url);\n }\n return url.pathname;\n }\n\n const path = await import(/* @vite-ignore */ \"node:path\");\n const { fileURLToPath } = await import(/* @vite-ignore */ \"node:url\");\n let dir = path.normalize(path.dirname(fileURLToPath(importMetaUrl)));\n for (let i = 0; i < levelsUp; i++) {\n dir = path.resolve(dir, \"..\");\n }\n return dir;\n}\n","/**\n * startServer — 多运行时自动启动\n *\n * 支持 Node.js (dev HMR + prod)、Deno、Bun、Vercel。\n */\n\nimport { Hono } from \"hono\";\nimport type { ViteDevServer } from \"vite\";\nimport { detectRuntime, type RuntimeInfo } from \"./runtime\";\n\nexport interface StartServerOptions {\n /** 最终的 Hono app(已包含 SSR + 自定义路由) */\n app: Hono;\n /** 项目根路径 */\n root: string;\n /** 端口号 */\n port?: number;\n /** 是否生产环境 */\n isProduction: boolean;\n /** Vite dev server(仅开发模式传入) */\n vite?: ViteDevServer;\n /** 运行时信息(可选,不传时自动检测) */\n runtime?: RuntimeInfo;\n /** 已注册的路由列表(用于启动日志) */\n routes?: string[];\n /** 支持的语言列表(用于启动日志) */\n locales?: string[];\n /** SSR 入口路径(用于启动日志) */\n ssrEntryPath?: string;\n}\n\nexport async function startServer(options: StartServerOptions): Promise<{ vite?: ViteDevServer }> {\n const { app, root, port = 3000, isProduction, vite, routes, locales, ssrEntryPath } = options;\n\n const { isDeno, isBun, isVercel } = options.runtime ?? detectRuntime();\n\n function printStartupBanner() {\n const lines: string[] = [`\\n Server running at http://localhost:${port}\\n`];\n if (routes && routes.length > 0) {\n lines.push(\" Routes:\");\n for (const r of routes) {\n lines.push(` ${r}`);\n }\n lines.push(\"\");\n }\n if (locales && locales.length > 0) {\n lines.push(` Locales: ${locales.join(\", \")}`);\n }\n if (ssrEntryPath) {\n lines.push(` SSR Entry: ${ssrEntryPath}`);\n }\n if (locales?.length || ssrEntryPath) {\n lines.push(\"\");\n }\n console.log(lines.join(\"\\n\"));\n }\n\n if (isVercel) {\n return { vite };\n }\n\n if (!isProduction) {\n let devVite = vite;\n if (!devVite) {\n const { createServer: createViteServer } = await import(/* @vite-ignore */ \"vite\");\n devVite = await createViteServer({\n root,\n server: { middlewareMode: true },\n appType: \"custom\",\n });\n }\n\n const { getRequestListener } = await import(/* @vite-ignore */ \"@hono/node-server\");\n const { createServer } = await import(/* @vite-ignore */ \"node:http\");\n const listener = getRequestListener(app.fetch);\n const server = createServer((req: any, res: any) => {\n devVite!.middlewares(req, res, () => listener(req, res));\n });\n server.listen(port, () => {\n printStartupBanner();\n });\n return { vite: devVite };\n }\n\n if (isDeno) {\n (globalThis as any).Deno.serve({ port }, app.fetch);\n } else if (isBun) {\n // Bun uses export default\n } else {\n // Node.js production\n const { serveStatic } = await import(/* @vite-ignore */ \"@hono/node-server/serve-static\");\n const path = await import(/* @vite-ignore */ \"node:path\");\n const prodApp = new Hono();\n const clientDir = path.resolve(root, \"dist/client\");\n prodApp.use(\n \"/*\",\n serveStatic({\n root: clientDir,\n // 禁止目录路径自动提供 index.html,让其 fall through 到 SSR\n rewriteRequestPath: (path: string) =>\n path.endsWith(\"/\") ? \"/__nosuchfile__\" : path,\n }),\n );\n prodApp.route(\"/\", app);\n\n const { serve } = await import(/* @vite-ignore */ \"@hono/node-server\");\n serve({ fetch: prodApp.fetch, port }, () => {\n printStartupBanner();\n });\n }\n\n return { vite };\n}\n","/**\n * createServer — 一站式服务器工厂\n *\n * 封装 env 加载、运行时检测、Vite 创建、Hono app、SSR、启动。\n * 保留 setup() 钩子用于注册业务路由。\n */\n\nimport { Hono } from \"hono\";\nimport type { ViteDevServer } from \"vite\";\nimport { createSSRApp, type SSRAppOptions } from \"./app\";\nimport { registerProxyRoutes, type ProxyRouteConfig } from \"./proxy\";\nimport { detectRuntime, type RuntimeInfo } from \"./runtime\";\nimport { startServer } from \"./start\";\n\nexport interface ServerConfig {\n /** 项目根路径(默认 process.cwd()) */\n root?: string;\n /** 支持的语言列表 */\n locales?: string[];\n /** 默认语言 */\n defaultLocale?: string;\n /** 端口号(默认 3000) */\n port?: number;\n /** 注册自定义路由(在 SSR catch-all 之前调用,但在声明式代理之后) */\n setup?: (app: Hono) => void | Promise<void>;\n /** 声明式代理路由配置 */\n proxies?: ProxyRouteConfig[];\n /** SSR 相关选项(透传给 createSSRApp) */\n ssr?: Pick<SSRAppOptions, \"ssrEntryPath\" | \"ssrProductionModule\">;\n}\n\nexport interface ServerInstance {\n app: Hono;\n vite?: ViteDevServer;\n runtime: RuntimeInfo;\n}\n\n/**\n * 创建并启动 SSR 服务器\n *\n * @example\n * ```ts\n * const { app } = await createServer({\n * locales: [\"zh\", \"en\"],\n * setup: (app) => registerProxies(app),\n * });\n * export { app };\n * ```\n */\nexport async function createServer(config: ServerConfig = {}): Promise<ServerInstance> {\n const {\n root: rootOverride,\n locales,\n defaultLocale,\n port = Number(process.env.PORT) || 3000,\n setup,\n proxies,\n ssr,\n } = config;\n\n // 1. 路径 + .env\n const root = rootOverride ?? process.cwd();\n const { existsSync } = await import(/* @vite-ignore */ \"node:fs\");\n const path = await import(/* @vite-ignore */ \"node:path\");\n const envPath = path.resolve(root, \".env\");\n if (existsSync(envPath)) {\n try {\n const { config: dotenvConfig } = await import(/* @vite-ignore */ \"dotenv\");\n dotenvConfig({ path: envPath });\n } catch {\n // dotenv 未安装则跳过,调用方可自行加载 .env\n }\n }\n\n // 2. 运行时检测\n const runtime = detectRuntime();\n\n // 3. Vite(仅开发模式)\n let vite: ViteDevServer | undefined;\n if (!runtime.isProduction && !runtime.isVercel) {\n const { createServer: createViteServer } = await import(/* @vite-ignore */ \"vite\");\n vite = await createViteServer({\n root,\n server: { middlewareMode: true },\n appType: \"custom\",\n });\n }\n\n // 4. Hono app + 声明式代理 + 自定义路由\n const app = new Hono();\n if (proxies?.length) {\n registerProxyRoutes(app, proxies);\n }\n if (setup) {\n await setup(app);\n }\n\n // 5. SSR catch-all\n const ssrApp = createSSRApp({\n root,\n vite,\n isProduction: runtime.isProduction,\n supportedLocales: locales,\n defaultLocale,\n parentFetch: app.fetch.bind(app),\n ...ssr,\n });\n app.route(\"/\", ssrApp);\n\n // 6. 启动\n await startServer({\n app,\n root,\n port,\n isProduction: runtime.isProduction,\n vite,\n runtime,\n locales,\n ssrEntryPath: ssr?.ssrEntryPath,\n });\n\n return { app, vite, runtime };\n}\n","/**\n * finesoftFrontViteConfig — Vite 插件\n *\n * 将 Hono SSR 服务器集成到 Vite 的 dev / build / preview 生命周期中,\n * 使 template-project 只需 `vite` / `vite build` / `vite preview` 即可运行。\n *\n * 支持多平台 adapter: \"vercel\" | \"cloudflare\" | \"netlify\" | \"node\" | \"static\" | \"auto\"\n * 或自定义 Adapter 对象。\n */\n\nimport type { Hono } from \"hono\";\nimport { resolveAdapter } from \"./adapters/resolve\";\nimport { buildBundle, copyStaticAssets, generateSSREntry } from \"./adapters/shared\";\nimport type { Adapter } from \"./adapters/types\";\nimport type { SSRModule } from \"./app\";\nimport { createInternalFetch, MAX_SSR_DEPTH, SSR_DEPTH_HEADER } from \"./internal-fetch\";\nimport { registerProxyRoutes, type ProxyRouteConfig } from \"./proxy\";\n\nexport interface FinesoftFrontViteOptions {\n /** 支持的语言列表 */\n locales?: string[];\n /** 默认语言 */\n defaultLocale?: string;\n /** SSR 配置 */\n ssr?: {\n /** SSR 入口文件路径(默认 \"src/ssr.ts\") */\n entry?: string;\n };\n /**\n * 声明式代理路由配置。\n * 框架统一执行路径校验(SSRF 防护)、Host 限制、错误处理、响应头控制。\n * 代理路由在 setup 之前注册,优先级高于自定义路由。\n */\n proxies?: ProxyRouteConfig[];\n /**\n * 注册自定义路由(非代理类)。\n * - 传入 Function:仅 dev/preview 时可用。\n * - 传入 string(文件路径):dev/preview/adapter 均可用,\n * 文件需 export default 一个 (app: Hono) => void 函数。\n * 注意:代理路由请使用 proxies 选项,不要在 setup 中手写代理。\n */\n setup?: ((app: Hono) => void | Promise<void>) | string;\n /**\n * 部署适配器。\n * - 字符串快捷方式:\"vercel\" | \"cloudflare\" | \"netlify\" | \"node\" | \"static\" | \"auto\"\n * - 自定义 Adapter 对象:{ name, build(ctx) }\n * - 不设置则不生成部署产物\n */\n adapter?: string | Adapter;\n /**\n * 按路由覆盖渲染模式(优先级高于 RouteDefinition.renderMode)。\n * key: 精确路径或 glob 模式,如 \"/search\" 或 \"/blog/*\"\n * value: \"ssr\" | \"csr\" | \"prerender\"\n *\n * @example\n * ```ts\n * renderModes: {\n * \"/search\": \"csr\",\n * \"/blog/*\": \"prerender\",\n * }\n * ```\n */\n renderModes?: Record<string, \"ssr\" | \"csr\" | \"prerender\">;\n /**\n * 路由定义入口文件(用于预渲染时加载路由),默认 \"src/lib/bootstrap.ts\"。\n * 如果项目不使用声明式路由定义,可以不设置。\n */\n bootstrapEntry?: string;\n}\n\n/**\n * 从 setup 模块中查找 setup 函数:优先 default,其次 setup 命名导出。\n */\nfunction resolveSetupFn(mod: Record<string, unknown>): ((app: any) => void | Promise<void>) | null {\n if (typeof mod.default === \"function\") return mod.default as any;\n if (typeof mod.setup === \"function\") return mod.setup as any;\n const first = Object.values(mod).find((v) => typeof v === \"function\");\n return (first as any) ?? null;\n}\n\n/**\n * 匹配 Vite 配置级别的 renderMode 覆盖。\n * 精确路径优先,然后 glob 模式。\n */\nfunction matchRenderModeConfig(url: string, renderModes?: Record<string, string>): string | null {\n if (!renderModes) return null;\n const path = url.split(\"?\")[0];\n if (renderModes[path]) return renderModes[path];\n for (const [pattern, mode] of Object.entries(renderModes)) {\n if (pattern.includes(\"*\")) {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(\"^\" + escaped.replace(/\\*/g, \".*\") + \"$\");\n if (re.test(path)) return mode;\n }\n }\n return null;\n}\n\nexport function finesoftFrontViteConfig(options: FinesoftFrontViteOptions = {}) {\n const ssrEntry = options.ssr?.entry ?? \"src/ssr.ts\";\n let root = process.cwd();\n let resolvedCommand: string | undefined;\n let resolvedResolve: unknown;\n let resolvedCss: unknown;\n\n const CSS_EXTENSIONS = /\\.(css|scss|less|sass|styl|stylus|pcss|postcss)($|\\?)/;\n\n return {\n name: \"finesoft-front\",\n\n config(userConfig: Record<string, any>, env: { command: string }) {\n const overrides: Record<string, any> = {\n appType: \"custom\",\n };\n if (env.command === \"build\" && !process.env.__FINESOFT_SUB_BUILD__) {\n overrides.build = {\n outDir: userConfig.build?.outDir ?? \"dist/client\",\n };\n }\n return overrides;\n },\n\n configResolved(config: Record<string, any>) {\n resolvedCommand = config.command as string;\n resolvedResolve = config.resolve;\n resolvedCss = config.css;\n root = config.root as string;\n },\n\n /**\n * Dev 模式 CSS 内联 — 消除 SSR 首屏布局抖动\n *\n * Vite dev 模式下,global.scss 等非组件 CSS 通过 JS 模块系统异步加载,\n * 导致 SSR HTML 初次渲染缺少布局关键样式(box-sizing、flex 布局、padding-top 等)。\n *\n * 此 hook 在 HTML 模板变换阶段(SSR 渲染之前):\n * 1. 找到浏览器入口脚本(排除 /@vite/client 等内部脚本)\n * 2. 编译入口脚本,填充 Vite 模块图\n * 3. 遍历模块图收集所有 CSS 依赖(排除 .svelte 组件 CSS,由 SSR 渲染自行处理)\n * 4. 通过 ssrLoadModule 获取编译后 CSS(SCSS→CSS)\n * 5. 注入 <style data-vite-dev-id> 标签到 <head>\n *\n * data-vite-dev-id 确保 Vite HMR 客户端复用已有标签,避免重复注入。\n */\n transformIndexHtml: {\n order: \"pre\" as const,\n async handler(html: string, ctx: any) {\n const server = ctx.server;\n if (!server) return;\n\n // 跳过非页面 URL(如 .json / .xml 等资源路径)。\n // Vite 会以页面 URL 为前缀生成虚拟模块 ID,\n // 含 .json 的路径会触发 vite:json 插件误解析 CSS。\n const urlPath = (ctx.originalUrl || ctx.path || \"\").split(\"?\")[0];\n if (/\\.\\w+$/.test(urlPath) && !urlPath.endsWith(\".html\")) {\n return;\n }\n\n // 找到浏览器入口脚本(排除 Vite 内部 /@... 路径)\n const scripts = [...html.matchAll(/<script\\b[^>]*\\bsrc=[\"']([^\"']+)[\"'][^>]*>/g)];\n const appEntry = scripts.find((m) => !m[1].startsWith(\"/@\"));\n if (!appEntry) return;\n\n const browserEntry = appEntry[1];\n\n // 编译浏览器入口,填充模块图\n try {\n await server.transformRequest(browserEntry);\n } catch {\n return;\n }\n\n // 从模块图遍历 CSS 依赖\n const cssUrls: string[] = [];\n const visited = new Set<string>();\n\n function walk(mod: any): void {\n if (!mod?.url || visited.has(mod.url)) return;\n visited.add(mod.url);\n // 收集 CSS,但排除 .svelte 组件 CSS(由 SSR 渲染处理)\n if (CSS_EXTENSIONS.test(mod.url) && !mod.url.includes(\".svelte\")) {\n cssUrls.push(mod.url);\n }\n if (mod.importedModules) {\n for (const imported of mod.importedModules) {\n walk(imported);\n }\n }\n }\n\n const mg = server.moduleGraph;\n const browserMod = await mg.getModuleByUrl(browserEntry);\n if (browserMod) walk(browserMod);\n\n if (cssUrls.length === 0) return;\n\n // 通过 ssrLoadModule 获取编译后 CSS,注入为 <style> 标签\n const tags: Array<{\n tag: string;\n attrs: Record<string, string>;\n children: string;\n injectTo: \"head\";\n }> = [];\n\n for (const url of cssUrls) {\n try {\n const mod: any = await server.ssrLoadModule(url);\n const css = mod?.default;\n if (typeof css === \"string\" && css.length > 0) {\n tags.push({\n tag: \"style\",\n attrs: { \"data-vite-dev-id\": url },\n children: css,\n injectTo: \"head\",\n });\n }\n } catch {\n /* CSS 编译失败则跳过 */\n }\n }\n\n return tags;\n },\n },\n\n // ─── Dev ───────────────────────────────────────────────\n configureServer(server: any) {\n return async () => {\n const { Hono: HonoClass } = await import(/* @vite-ignore */ \"hono\");\n const { createSSRApp } = await import(\"./app\");\n const { getRequestListener } = await import(/* @vite-ignore */ \"@hono/node-server\");\n\n const app = new HonoClass();\n\n // 声明式代理路由(框架层,优先注册)\n if (options.proxies?.length) {\n registerProxyRoutes(app, options.proxies);\n }\n\n // Setup: 函数直接调用,文件路径通过 ssrLoadModule 加载\n if (typeof options.setup === \"function\") {\n await options.setup(app);\n } else if (typeof options.setup === \"string\") {\n const mod = await server.ssrLoadModule(\"/\" + options.setup);\n const fn = resolveSetupFn(mod);\n if (fn) await fn(app);\n }\n\n const ssrApp = createSSRApp({\n root,\n vite: server,\n isProduction: false,\n ssrEntryPath: \"/\" + ssrEntry,\n supportedLocales: options.locales,\n defaultLocale: options.defaultLocale,\n parentFetch: app.fetch.bind(app),\n renderModes: options.renderModes,\n });\n app.route(\"/\", ssrApp);\n\n const listener = getRequestListener(app.fetch);\n\n server.middlewares.use((req: any, res: any) => {\n void listener(req, res);\n });\n };\n },\n\n // ─── Preview ───────────────────────────────────────────\n configurePreviewServer(server: any) {\n return async () => {\n const { readFileSync } = await import(/* @vite-ignore */ \"node:fs\");\n const path = await import(/* @vite-ignore */ \"node:path\");\n const { pathToFileURL } = await import(/* @vite-ignore */ \"node:url\");\n const { Hono: HonoClass } = await import(/* @vite-ignore */ \"hono\");\n const { injectSSRContent, injectCSRShell } = await import(\n /* @vite-ignore */ \"@finesoft/ssr\"\n );\n const { parseAcceptLanguage } = await import(\"./locale\");\n const { getRequestListener } = await import(/* @vite-ignore */ \"@hono/node-server\");\n\n const app = new HonoClass();\n\n // ISR 内存缓存\n const isrCache = new Map<string, string>();\n\n // 声明式代理路由(框架层,优先注册)\n if (options.proxies?.length) {\n registerProxyRoutes(app, options.proxies);\n }\n\n // Setup: 函数直接调用,文件路径从构建产物加载\n if (typeof options.setup === \"function\") {\n await options.setup(app);\n } else if (typeof options.setup === \"string\") {\n try {\n const setupPath = pathToFileURL(\n path.resolve(root, \"dist/server/setup.mjs\"),\n ).href;\n const mod = await import(/* @vite-ignore */ setupPath);\n const fn = resolveSetupFn(mod as Record<string, unknown>);\n if (fn) await fn(app);\n } catch {\n console.warn(\n \"[finesoft] Could not load setup module for preview. API routes disabled.\",\n );\n }\n }\n\n const templatePath = path.resolve(root, \"dist/client/index.html\");\n const template = readFileSync(templatePath, \"utf-8\");\n\n const ssrPath = pathToFileURL(path.resolve(root, \"dist/server/ssr.js\")).href;\n const ssrModule = (await import(/* @vite-ignore */ ssrPath)) as SSRModule;\n\n app.get(\"*\", async (c: any) => {\n // 递归深度保护\n const ssrDepth = parseInt(c.req.header(SSR_DEPTH_HEADER) ?? \"0\", 10);\n if (ssrDepth >= MAX_SSR_DEPTH) {\n return c.text(\"SSR recursion loop detected\", 508);\n }\n\n const url =\n c.req.path + (c.req.url.includes(\"?\") ? \"?\" + c.req.url.split(\"?\")[1] : \"\");\n\n try {\n const locale = parseAcceptLanguage(\n c.req.header(\"accept-language\"),\n options.locales,\n options.defaultLocale,\n );\n\n // Vite 配置级别覆盖\n const overrideMode = matchRenderModeConfig(url, options.renderModes);\n if (overrideMode === \"csr\") {\n return c.html(injectCSRShell(template, locale));\n }\n\n // ISR 缓存命中(key 含 locale,避免跨语言缓存污染)\n const cacheKey = `${locale}:${url}`;\n const cached = isrCache.get(cacheKey);\n if (cached) return c.html(cached);\n\n const {\n html: appHtml,\n head,\n css,\n serverData,\n renderMode,\n } = await ssrModule.render(url, locale, {\n fetch: createInternalFetch(app.fetch.bind(app), ssrDepth + 1),\n });\n\n // 路由级 CSR\n if (renderMode === \"csr\") {\n return c.html(injectCSRShell(template, locale));\n }\n\n const serializedData = ssrModule.serializeServerData(serverData);\n\n const finalHtml = injectSSRContent({\n template,\n locale,\n head,\n css,\n html: appHtml,\n serializedData,\n });\n\n // Prerender ISR 缓存\n if (renderMode === \"prerender\" || overrideMode === \"prerender\") {\n isrCache.set(cacheKey, finalHtml);\n }\n\n return c.html(finalHtml);\n } catch (e) {\n console.error(\"[SSR Preview Error]\", e);\n return c.text(\"Internal Server Error\", 500);\n }\n });\n\n const listener = getRequestListener(app.fetch);\n\n server.middlewares.use((req: any, res: any) => {\n void listener(req, res);\n });\n };\n },\n\n // ─── Build ─────────────────────────────────────────────\n async closeBundle() {\n if (process.env.__FINESOFT_SUB_BUILD__) return;\n if (resolvedCommand !== \"build\") return;\n\n process.env.__FINESOFT_SUB_BUILD__ = \"1\";\n try {\n const vite: any = await import(/* @vite-ignore */ \"vite\");\n const fs = await import(/* @vite-ignore */ \"node:fs\");\n const path = await import(/* @vite-ignore */ \"node:path\");\n\n // ── 1. SSR 构建 ──\n console.log(\"\\n Building SSR bundle...\\n\");\n await vite.build({\n root,\n build: {\n ssr: ssrEntry,\n outDir: \"dist/server\",\n },\n resolve: resolvedResolve,\n css: resolvedCss,\n });\n\n // ── 2. Setup 模块构建(仅当 setup 是文件路径时) ──\n if (typeof options.setup === \"string\") {\n console.log(\" Building setup module...\\n\");\n await vite.build({\n root,\n build: {\n ssr: options.setup,\n outDir: \"dist/server\",\n emptyOutDir: false,\n rollupOptions: {\n output: { entryFileNames: \"setup.mjs\" },\n },\n },\n resolve: resolvedResolve,\n });\n }\n\n // ── 3. Adapter 构建 ──\n if (options.adapter) {\n const adapter = resolveAdapter(options.adapter);\n\n const locales = options.locales ?? [\"zh\", \"en\"];\n const defaultLocale = options.defaultLocale ?? locales[0] ?? \"en\";\n const templateHtml = fs.readFileSync(\n path.resolve(root, \"dist/client/index.html\"),\n \"utf-8\",\n );\n\n const ctx = {\n root,\n ssrEntry,\n setupPath: typeof options.setup === \"string\" ? options.setup : undefined,\n bootstrapEntry: options.bootstrapEntry,\n locales,\n defaultLocale,\n templateHtml,\n renderModes: options.renderModes,\n proxies: options.proxies,\n resolvedResolve,\n resolvedCss,\n vite,\n fs,\n path,\n generateSSREntry(opts: any) {\n return generateSSREntry(ctx, opts);\n },\n buildBundle(opts: any) {\n return buildBundle(ctx, opts);\n },\n copyStaticAssets(destDir: string, opts?: any) {\n return copyStaticAssets(ctx, destDir, opts);\n },\n };\n\n console.log(` Running adapter: ${adapter.name}...\\n`);\n await adapter.build(ctx);\n }\n } finally {\n delete process.env.__FINESOFT_SUB_BUILD__;\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs";
2
+ //#region ../server/src/locale.ts
3
+ var locale_exports = /* @__PURE__ */ __exportAll({ parseAcceptLanguage: () => parseAcceptLanguage });
4
+ /**
5
+ * Accept-Language 解析
6
+ */
7
+ function parseAcceptLanguage(header, supported, fallback) {
8
+ const effectiveSupported = supported ?? ["zh", "en"];
9
+ const effectiveFallback = fallback ?? effectiveSupported[0] ?? "en";
10
+ if (!header) return effectiveFallback;
11
+ const langs = header.split(",").map((part) => {
12
+ const [lang, q] = part.trim().split(";q=");
13
+ return {
14
+ lang: lang.trim().toLowerCase(),
15
+ q: q ? parseFloat(q) || 0 : 1
16
+ };
17
+ }).sort((a, b) => b.q - a.q);
18
+ for (const { lang } of langs) {
19
+ const prefix = lang.split("-")[0];
20
+ if (effectiveSupported.includes(prefix)) return prefix;
21
+ }
22
+ return effectiveFallback;
23
+ }
24
+ //#endregion
25
+ export { parseAcceptLanguage as n, locale_exports as t };
26
+
27
+ //# sourceMappingURL=locale-D2Bu7w47.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-D2Bu7w47.mjs","names":[],"sources":["../../server/src/locale.ts"],"sourcesContent":["/**\n * Accept-Language 解析\n */\n\nexport function parseAcceptLanguage(\n header: string | undefined,\n supported?: string[],\n fallback?: string,\n): string {\n const effectiveSupported = supported ?? [\"zh\", \"en\"];\n const effectiveFallback = fallback ?? effectiveSupported[0] ?? \"en\";\n if (!header) return effectiveFallback;\n const langs = header\n .split(\",\")\n .map((part) => {\n const [lang, q] = part.trim().split(\";q=\");\n return {\n lang: lang.trim().toLowerCase(),\n q: q ? parseFloat(q) || 0 : 1,\n };\n })\n .sort((a, b) => b.q - a.q);\n\n for (const { lang } of langs) {\n const prefix = lang.split(\"-\")[0];\n if (effectiveSupported.includes(prefix)) {\n return prefix;\n }\n }\n return effectiveFallback;\n}\n"],"mappings":";;;;;;AAIA,SAAgB,oBACZ,QACA,WACA,UACM;CACN,MAAM,qBAAqB,aAAa,CAAC,MAAM,KAAK;CACpD,MAAM,oBAAoB,YAAY,mBAAmB,MAAM;AAC/D,KAAI,CAAC,OAAQ,QAAO;CACpB,MAAM,QAAQ,OACT,MAAM,IAAI,CACV,KAAK,SAAS;EACX,MAAM,CAAC,MAAM,KAAK,KAAK,MAAM,CAAC,MAAM,MAAM;AAC1C,SAAO;GACH,MAAM,KAAK,MAAM,CAAC,aAAa;GAC/B,GAAG,IAAI,WAAW,EAAE,IAAI,IAAI;GAC/B;GACH,CACD,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,EAAE;AAE9B,MAAK,MAAM,EAAE,UAAU,OAAO;EAC1B,MAAM,SAAS,KAAK,MAAM,IAAI,CAAC;AAC/B,MAAI,mBAAmB,SAAS,OAAO,CACnC,QAAO;;AAGf,QAAO"}
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -0,0 +1,41 @@
1
+ //#region src/shims/server-peer-modules.d.ts
2
+ declare module "hono" {
3
+ export class Hono {
4
+ constructor(...args: any[]);
5
+ get(path: string, handler: (c: any) => any): this;
6
+ use(...args: any[]): this;
7
+ route(...args: any[]): this;
8
+ fetch: any;
9
+ }
10
+ }
11
+ declare module "vite" {
12
+ export interface ViteDevServer {
13
+ transformIndexHtml(url: string, html: string): string | Promise<string>;
14
+ ssrLoadModule(path: string): Promise<unknown>;
15
+ ssrFixStacktrace(error: Error): void;
16
+ middlewares(req: any, res: any, next: () => void): void;
17
+ }
18
+ export function createServer(options?: any): Promise<ViteDevServer>;
19
+ }
20
+ declare module "dotenv" {
21
+ export interface DotenvConfigOptions {
22
+ path?: string;
23
+ [key: string]: unknown;
24
+ }
25
+ export interface DotenvConfigOutput {
26
+ parsed?: Record<string, string>;
27
+ error?: Error;
28
+ }
29
+ export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
30
+ }
31
+ declare module "@hono/node-server" {
32
+ export function getRequestListener(fetchHandler: any): (req: any, res: any) => any;
33
+ export function serve(options: {
34
+ fetch: any;
35
+ port?: number;
36
+ }, onListen?: () => void): unknown;
37
+ }
38
+ declare module "@hono/node-server/serve-static" {
39
+ export function serveStatic(options?: any): any;
40
+ }
41
+ //# sourceMappingURL=server-peer-modules-BSSsxBaF.d.mts.map