@finesoft/front 0.1.38 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/app-XEMPAI6H.js +10 -0
- package/dist/browser.cjs +219 -19
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +148 -15
- package/dist/browser.d.ts +148 -15
- package/dist/browser.js +18 -2
- package/dist/{chunk-PHDR7PIL.js → chunk-4PPCVAKZ.js} +98 -17
- package/dist/chunk-4PPCVAKZ.js.map +1 -0
- package/dist/{chunk-SFGR32K6.js → chunk-OYTIGVEG.js} +13 -8
- package/dist/chunk-OYTIGVEG.js.map +1 -0
- package/dist/{chunk-OXKFPW4U.js → chunk-SDPWQT2T.js} +118 -6
- package/dist/chunk-SDPWQT2T.js.map +1 -0
- package/dist/{chunk-AYO3UUQC.js → chunk-XQ3UWZOS.js} +72 -3
- package/dist/chunk-XQ3UWZOS.js.map +1 -0
- package/dist/index.cjs +319 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +24 -8
- package/dist/index.js.map +1 -1
- package/dist/{src-MVACJWBF.js → src-XNC7QNVI.js} +3 -3
- package/package.json +1 -1
- package/dist/app-D4K35MX3.js +0 -10
- package/dist/chunk-AYO3UUQC.js.map +0 -1
- package/dist/chunk-OXKFPW4U.js.map +0 -1
- package/dist/chunk-PHDR7PIL.js.map +0 -1
- package/dist/chunk-SFGR32K6.js.map +0 -1
- /package/dist/{app-D4K35MX3.js.map → app-XEMPAI6H.js.map} +0 -0
- /package/dist/{src-MVACJWBF.js.map → src-XNC7QNVI.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../ssr/src/render.ts","../../ssr/src/create-render.ts","../../ssr/src/inject.ts","../../ssr/src/server-data.ts"],"sourcesContent":["/**\n * ssrRender — 通用 SSR 渲染管线\n *\n * 1. 创建 Framework + 注册 Controllers\n * 2. routeUrl → Intent\n * 3. dispatch → Page 数据\n * 4. 调用应用层提供的渲染函数\n */\n\nimport {\n\tFramework,\n\tcreateServerContext,\n\ttype BasePage,\n\ttype FrameworkConfig,\n\ttype MiddlewareResult,\n\ttype PostLoadContext,\n\ttype PrefetchedIntent,\n} from \"@finesoft/core\";\n\nexport interface SSRRenderOptions {\n\t/** 请求 URL */\n\turl: string;\n\t/** Framework 配置(含路由注册等) */\n\tframeworkConfig: FrameworkConfig;\n\t/** 注册 controllers 和路由的引导函数 */\n\tbootstrap: (framework: Framework) => void;\n\t/** 获取错误页面 */\n\tgetErrorPage: (status: number, message: string) => BasePage;\n\t/** 应用层渲染函数(如 Svelte SSR render) */\n\trenderApp: (page: BasePage, framework: Framework) => SSRAppResult;\n\t/** 可选的 SSR 请求上下文(如自定义 fetch) */\n\tssrContext?: SSRContext;\n}\n\n/** SSR 请求级上下文 */\nexport interface SSRContext {\n\t/** 自定义 fetch(如 Hono 内部路由回环) */\n\tfetch?: typeof globalThis.fetch;\n\t/** 原始 Request 对象(用于中间件读取 cookie/header) */\n\trequest?: Request;\n}\n\nexport interface SSRAppResult {\n\thtml: string;\n\thead: string;\n\tcss: string;\n}\n\nexport interface SSRRenderResult {\n\thtml: string;\n\thead: string;\n\tcss: string;\n\tserverData: PrefetchedIntent[];\n\t/** 该路由的渲染模式(由 Router 返回) */\n\trenderMode?: string;\n\t/** 中间件要求的重定向(服务端应返回 HTTP 301/302) */\n\tredirect?: { url: string; status: number };\n}\n\nexport async function ssrRender(\n\toptions: SSRRenderOptions,\n): Promise<SSRRenderResult> {\n\tconst {\n\t\turl,\n\t\tframeworkConfig,\n\t\tbootstrap,\n\t\tgetErrorPage,\n\t\trenderApp,\n\t\tssrContext,\n\t} = options;\n\n\t// 将 SSR 上下文中的 fetch 合并到 frameworkConfig,注入 DI 容器\n\tconst mergedConfig: FrameworkConfig = ssrContext?.fetch\n\t\t? { ...frameworkConfig, fetch: ssrContext.fetch }\n\t\t: frameworkConfig;\n\n\tconst framework = Framework.create(mergedConfig);\n\tbootstrap(framework);\n\n\ttry {\n\t\tconst parsed = new URL(url, \"http://localhost\");\n\t\tconst fullPath = parsed.pathname + parsed.search;\n\t\tconst match = framework.routeUrl(fullPath);\n\n\t\t// CSR 模式:跳过服务端渲染,返回空内容由客户端 JS 渲染\n\t\tif (match?.renderMode === \"csr\") {\n\t\t\treturn {\n\t\t\t\thtml: \"\",\n\t\t\t\thead: \"\",\n\t\t\t\tcss: \"\",\n\t\t\t\tserverData: [],\n\t\t\t\trenderMode: \"csr\",\n\t\t\t};\n\t\t}\n\n\t\tlet page: BasePage;\n\t\tlet serverData: PrefetchedIntent[] = [];\n\n\t\tif (match) {\n\t\t\t// ===== beforeLoad 中间件 =====\n\t\t\tconst navCtx = createServerContext({\n\t\t\t\turl: fullPath,\n\t\t\t\tintent: match.intent,\n\t\t\t\tcontainer: framework.container,\n\t\t\t\trequest: ssrContext?.request,\n\t\t\t});\n\t\t\tconst beforeResult = await framework.runBeforeLoad(\n\t\t\t\tnavCtx,\n\t\t\t\tmatch.beforeGuards,\n\t\t\t);\n\t\t\tif (beforeResult.kind !== \"next\") {\n\t\t\t\tconst earlyReturn = handleMiddlewareResult(\n\t\t\t\t\tbeforeResult,\n\t\t\t\t\tgetErrorPage,\n\t\t\t\t\trenderApp,\n\t\t\t\t\tframework,\n\t\t\t\t);\n\t\t\t\tif (earlyReturn) return earlyReturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tpage = (await framework.dispatch(match.intent)) as BasePage;\n\t\t\t\tserverData = [{ intent: match.intent, data: page }];\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[SSR] dispatch failed for intent \"${match.intent.id}\":`,\n\t\t\t\t\te,\n\t\t\t\t);\n\t\t\t\tpage = getErrorPage(500, \"Internal error\");\n\t\t\t}\n\n\t\t\t// ===== afterLoad 中间件 =====\n\t\t\tconst postCtx: PostLoadContext = {\n\t\t\t\t...navCtx,\n\t\t\t\tpage,\n\t\t\t};\n\t\t\tconst afterResult = await framework.runAfterLoad(\n\t\t\t\tpostCtx,\n\t\t\t\tmatch.afterGuards,\n\t\t\t);\n\t\t\tif (afterResult.kind !== \"next\") {\n\t\t\t\tconst lateReturn = handleMiddlewareResult(\n\t\t\t\t\tafterResult,\n\t\t\t\t\tgetErrorPage,\n\t\t\t\t\trenderApp,\n\t\t\t\t\tframework,\n\t\t\t\t);\n\t\t\t\tif (lateReturn) return lateReturn;\n\t\t\t}\n\t\t} else {\n\t\t\tpage = getErrorPage(404, \"Page not found\");\n\t\t}\n\n\t\tconst result = renderApp(page, framework);\n\n\t\treturn {\n\t\t\thtml: result.html,\n\t\t\thead: result.head,\n\t\t\tcss: result.css,\n\t\t\tserverData,\n\t\t\trenderMode: match?.renderMode,\n\t\t};\n\t} finally {\n\t\tframework.dispose();\n\t}\n}\n\n/**\n * 将中间件结果转换为 SSRRenderResult(如果需要短路返回)。\n * 返回 null 表示继续正常流程。\n */\nfunction handleMiddlewareResult(\n\tresult: MiddlewareResult,\n\tgetErrorPage: (status: number, message: string) => BasePage,\n\trenderApp: (page: BasePage, framework: Framework) => SSRAppResult,\n\tframework: Framework,\n): SSRRenderResult | null {\n\tswitch (result.kind) {\n\t\tcase \"next\":\n\t\t\treturn null;\n\t\tcase \"redirect\":\n\t\t\treturn {\n\t\t\t\thtml: \"\",\n\t\t\t\thead: \"\",\n\t\t\t\tcss: \"\",\n\t\t\t\tserverData: [],\n\t\t\t\tredirect: { url: result.url, status: result.status },\n\t\t\t};\n\t\tcase \"rewrite\":\n\t\t\treturn {\n\t\t\t\thtml: \"\",\n\t\t\t\thead: \"\",\n\t\t\t\tcss: \"\",\n\t\t\t\tserverData: [],\n\t\t\t\tredirect: { url: result.url, status: 301 },\n\t\t\t};\n\t\tcase \"deny\": {\n\t\t\tconst errorPage = getErrorPage(result.status, result.message);\n\t\t\tconst rendered = renderApp(errorPage, framework);\n\t\t\treturn {\n\t\t\t\thtml: rendered.html,\n\t\t\t\thead: rendered.head,\n\t\t\t\tcss: rendered.css,\n\t\t\t\tserverData: [],\n\t\t\t};\n\t\t}\n\t}\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 {\n\tssrRender,\n\ttype SSRAppResult,\n\ttype SSRContext,\n\ttype SSRRenderResult,\n} from \"./render\";\n\nexport interface SSRRenderConfig {\n\t/** 注册 controllers 和路由的引导函数 */\n\tbootstrap: (framework: Framework) => void;\n\n\t/** 获取错误页面 */\n\tgetErrorPage: (status: number, message: string) => BasePage;\n\n\t/**\n\t * 应用层渲染函数\n\t *\n\t * @param page - 当前页面数据\n\t * @param locale - 当前语言\n\t * @returns SSR 渲染结果 { html, head, css }\n\t */\n\trenderApp: (page: BasePage, locale: string) => SSRAppResult;\n\n\t/** Framework 构造配置(可选) */\n\tframeworkConfig?: FrameworkConfig;\n}\n\n/**\n * 创建 render 函数\n *\n * @returns `render(url, locale, ssrContext?)` — 供 @finesoft/server SSRModule 使用\n */\nexport function createSSRRender(\n\tconfig: SSRRenderConfig,\n): (\n\turl: string,\n\tlocale: string,\n\tssrContext?: SSRContext,\n) => Promise<SSRRenderResult> {\n\tconst { bootstrap, getErrorPage, renderApp, frameworkConfig } = config;\n\n\treturn (url: string, locale: string, ssrContext?: SSRContext) =>\n\t\tssrRender({\n\t\t\turl,\n\t\t\tframeworkConfig: frameworkConfig ?? {},\n\t\t\tbootstrap,\n\t\t\tgetErrorPage,\n\t\t\trenderApp: (page) => renderApp(page, locale),\n\t\t\tssrContext,\n\t\t});\n}\n","/**\n * injectSSRContent — 将 SSR 渲染结果注入 HTML 模板\n */\n\n/** SSR HTML 模板占位符常量 */\nexport const SSR_PLACEHOLDERS = {\n\tLANG: \"<!--ssr-lang-->\",\n\tHEAD: \"<!--ssr-head-->\",\n\tBODY: \"<!--ssr-body-->\",\n\tDATA: \"<!--ssr-data-->\",\n} as const;\n\nexport interface InjectSSROptions {\n\ttemplate: string;\n\tlocale: string;\n\thead: string;\n\tcss: string;\n\thtml: string;\n\tserializedData: string;\n}\n\nexport function injectSSRContent(options: InjectSSROptions): string {\n\tconst { template, locale, head, css, html, serializedData } = options;\n\tconst cssTag = css ? `<style>${css}</style>` : \"\";\n\n\treturn template\n\t\t.replace(SSR_PLACEHOLDERS.LANG, locale)\n\t\t.replace(SSR_PLACEHOLDERS.HEAD, `${head}\\n${cssTag}`)\n\t\t.replace(SSR_PLACEHOLDERS.BODY, html)\n\t\t.replace(\n\t\t\tSSR_PLACEHOLDERS.DATA,\n\t\t\t`<script id=\"serialized-server-data\" type=\"application/json\">${serializedData}</script>`,\n\t\t);\n}\n\n/**\n * CSR 空壳注入 — 只替换 lang,清空 body/head/data 占位符\n * 用于 renderMode === \"csr\" 的路由\n */\nexport function injectCSRShell(template: string, locale: string): string {\n\treturn template\n\t\t.replace(SSR_PLACEHOLDERS.LANG, locale)\n\t\t.replace(SSR_PLACEHOLDERS.HEAD, \"\")\n\t\t.replace(SSR_PLACEHOLDERS.BODY, \"\")\n\t\t.replace(SSR_PLACEHOLDERS.DATA, \"\");\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\t\"<\": \"\\\\u003C\",\n\t\">\": \"\\\\u003E\",\n\t\"/\": \"\\\\u002F\",\n\t\"\\u2028\": \"\\\\u2028\",\n\t\"\\u2029\": \"\\\\u2029\",\n};\n\nconst HTML_ESCAPE_PATTERN = /[<>/\\u2028\\u2029]/g;\n\nexport function serializeServerData(data: PrefetchedIntent[]): string {\n\tconst json = JSON.stringify(data);\n\treturn json.replace(\n\t\tHTML_ESCAPE_PATTERN,\n\t\t(match) => HTML_REPLACEMENTS[match] ?? match,\n\t);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -395,7 +395,8 @@ var init_router = __esm({
|
|
|
395
395
|
Router = class {
|
|
396
396
|
routes = [];
|
|
397
397
|
/** 添加路由规则 */
|
|
398
|
-
add(pattern, intentId,
|
|
398
|
+
add(pattern, intentId, renderModeOrOptions) {
|
|
399
|
+
const opts = typeof renderModeOrOptions === "string" ? { renderMode: renderModeOrOptions } : renderModeOrOptions ?? {};
|
|
399
400
|
const paramNames = [];
|
|
400
401
|
const regexStr = pattern.split(/(\/:[\w]+\??)/).map((segment) => {
|
|
401
402
|
const paramMatch = segment.match(/^\/:(\w+)(\?)?$/);
|
|
@@ -410,7 +411,9 @@ var init_router = __esm({
|
|
|
410
411
|
intentId,
|
|
411
412
|
regex: new RegExp(`^${regexStr}/?$`),
|
|
412
413
|
paramNames,
|
|
413
|
-
renderMode
|
|
414
|
+
renderMode: opts.renderMode,
|
|
415
|
+
beforeGuards: opts.beforeGuards,
|
|
416
|
+
afterGuards: opts.afterGuards
|
|
414
417
|
});
|
|
415
418
|
return this;
|
|
416
419
|
}
|
|
@@ -432,7 +435,9 @@ var init_router = __esm({
|
|
|
432
435
|
return {
|
|
433
436
|
intent: { id: route.intentId, params },
|
|
434
437
|
action: makeFlowAction(urlOrPath),
|
|
435
|
-
renderMode: route.renderMode
|
|
438
|
+
renderMode: route.renderMode,
|
|
439
|
+
beforeGuards: route.beforeGuards,
|
|
440
|
+
afterGuards: route.afterGuards
|
|
436
441
|
};
|
|
437
442
|
}
|
|
438
443
|
}
|
|
@@ -507,6 +512,27 @@ var init_composite = __esm({
|
|
|
507
512
|
}
|
|
508
513
|
});
|
|
509
514
|
|
|
515
|
+
// ../core/src/middleware/pipeline.ts
|
|
516
|
+
async function runBeforeLoadGuards(guards, ctx) {
|
|
517
|
+
for (const guard of guards) {
|
|
518
|
+
const result = await guard(ctx);
|
|
519
|
+
if (result.kind !== "next") return result;
|
|
520
|
+
}
|
|
521
|
+
return { kind: "next" };
|
|
522
|
+
}
|
|
523
|
+
async function runAfterLoadGuards(guards, ctx) {
|
|
524
|
+
for (const guard of guards) {
|
|
525
|
+
const result = await guard(ctx);
|
|
526
|
+
if (result.kind !== "next") return result;
|
|
527
|
+
}
|
|
528
|
+
return { kind: "next" };
|
|
529
|
+
}
|
|
530
|
+
var init_pipeline = __esm({
|
|
531
|
+
"../core/src/middleware/pipeline.ts"() {
|
|
532
|
+
"use strict";
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
|
|
510
536
|
// ../core/src/prefetched-intents/stable-stringify.ts
|
|
511
537
|
function stableStringify(obj, _seen) {
|
|
512
538
|
if (obj === null || obj === void 0) return String(obj);
|
|
@@ -589,6 +615,7 @@ var init_framework = __esm({
|
|
|
589
615
|
init_container();
|
|
590
616
|
init_make_dependencies();
|
|
591
617
|
init_dispatcher2();
|
|
618
|
+
init_pipeline();
|
|
592
619
|
init_prefetched_intents();
|
|
593
620
|
init_router();
|
|
594
621
|
Framework = class _Framework {
|
|
@@ -597,6 +624,8 @@ var init_framework = __esm({
|
|
|
597
624
|
actionDispatcher;
|
|
598
625
|
router;
|
|
599
626
|
prefetchedIntents;
|
|
627
|
+
beforeGuards = [];
|
|
628
|
+
afterGuards = [];
|
|
600
629
|
constructor(container, prefetchedIntents) {
|
|
601
630
|
this.container = container;
|
|
602
631
|
this.intentDispatcher = new IntentDispatcher();
|
|
@@ -660,6 +689,25 @@ var init_framework = __esm({
|
|
|
660
689
|
registerIntent(controller) {
|
|
661
690
|
this.intentDispatcher.register(controller);
|
|
662
691
|
}
|
|
692
|
+
// ===== Navigation Middleware =====
|
|
693
|
+
/** 注册 beforeLoad 守卫(路由匹配后、数据加载前) */
|
|
694
|
+
beforeLoad(guard) {
|
|
695
|
+
this.beforeGuards.push(guard);
|
|
696
|
+
}
|
|
697
|
+
/** 注册 afterLoad 守卫(数据加载后、渲染前) */
|
|
698
|
+
afterLoad(guard) {
|
|
699
|
+
this.afterGuards.push(guard);
|
|
700
|
+
}
|
|
701
|
+
/** 执行所有 beforeLoad 守卫(全局 → 路由级) */
|
|
702
|
+
runBeforeLoad(ctx, routeGuards) {
|
|
703
|
+
const guards = routeGuards?.length ? [...this.beforeGuards, ...routeGuards] : this.beforeGuards;
|
|
704
|
+
return runBeforeLoadGuards(guards, ctx);
|
|
705
|
+
}
|
|
706
|
+
/** 执行所有 afterLoad 守卫(全局 → 路由级) */
|
|
707
|
+
runAfterLoad(ctx, routeGuards) {
|
|
708
|
+
const guards = routeGuards?.length ? [...this.afterGuards, ...routeGuards] : this.afterGuards;
|
|
709
|
+
return runAfterLoadGuards(guards, ctx);
|
|
710
|
+
}
|
|
663
711
|
/** 销毁 Framework 实例 */
|
|
664
712
|
dispose() {
|
|
665
713
|
this.container.dispose();
|
|
@@ -823,7 +871,11 @@ function defineRoutes(framework, definitions) {
|
|
|
823
871
|
framework.registerIntent(def.controller);
|
|
824
872
|
registeredIntents.add(def.intentId);
|
|
825
873
|
}
|
|
826
|
-
framework.router.add(def.path, def.intentId,
|
|
874
|
+
framework.router.add(def.path, def.intentId, {
|
|
875
|
+
renderMode: def.renderMode,
|
|
876
|
+
beforeGuards: def.beforeLoad,
|
|
877
|
+
afterGuards: def.afterLoad
|
|
878
|
+
});
|
|
827
879
|
}
|
|
828
880
|
}
|
|
829
881
|
var init_define_routes = __esm({
|
|
@@ -943,6 +995,74 @@ var init_uuid = __esm({
|
|
|
943
995
|
}
|
|
944
996
|
});
|
|
945
997
|
|
|
998
|
+
// ../core/src/middleware/context.ts
|
|
999
|
+
function parseCookieString(str) {
|
|
1000
|
+
const map = /* @__PURE__ */ new Map();
|
|
1001
|
+
if (!str) return map;
|
|
1002
|
+
for (const pair of str.split(";")) {
|
|
1003
|
+
const idx = pair.indexOf("=");
|
|
1004
|
+
if (idx === -1) continue;
|
|
1005
|
+
const key = pair.slice(0, idx).trim();
|
|
1006
|
+
const val = pair.slice(idx + 1).trim();
|
|
1007
|
+
if (key) map.set(key, val);
|
|
1008
|
+
}
|
|
1009
|
+
return map;
|
|
1010
|
+
}
|
|
1011
|
+
function createServerContext(options) {
|
|
1012
|
+
const { url, intent, container, request } = options;
|
|
1013
|
+
const parsed = new URL(url, "http://localhost");
|
|
1014
|
+
const cookieHeader = request?.headers.get("cookie") ?? "";
|
|
1015
|
+
const cookies = parseCookieString(cookieHeader);
|
|
1016
|
+
return {
|
|
1017
|
+
url,
|
|
1018
|
+
path: parsed.pathname,
|
|
1019
|
+
params: intent.params ?? {},
|
|
1020
|
+
intent,
|
|
1021
|
+
isServer: true,
|
|
1022
|
+
container,
|
|
1023
|
+
getCookie: (name) => cookies.get(name),
|
|
1024
|
+
getHeader: (name) => request?.headers.get(name) ?? void 0
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
function createBrowserContext(options) {
|
|
1028
|
+
const { url, intent, container } = options;
|
|
1029
|
+
const parsed = new URL(url, window.location.origin);
|
|
1030
|
+
return {
|
|
1031
|
+
url,
|
|
1032
|
+
path: parsed.pathname,
|
|
1033
|
+
params: intent.params ?? {},
|
|
1034
|
+
intent,
|
|
1035
|
+
isServer: false,
|
|
1036
|
+
container,
|
|
1037
|
+
getCookie: (name) => parseCookieString(document.cookie).get(name),
|
|
1038
|
+
getHeader: () => void 0
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
var init_context = __esm({
|
|
1042
|
+
"../core/src/middleware/context.ts"() {
|
|
1043
|
+
"use strict";
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
// ../core/src/middleware/types.ts
|
|
1048
|
+
function next() {
|
|
1049
|
+
return { kind: "next" };
|
|
1050
|
+
}
|
|
1051
|
+
function redirect(url, status = 302) {
|
|
1052
|
+
return { kind: "redirect", url, status };
|
|
1053
|
+
}
|
|
1054
|
+
function rewrite(url) {
|
|
1055
|
+
return { kind: "rewrite", url };
|
|
1056
|
+
}
|
|
1057
|
+
function deny(status = 403, message = "Forbidden") {
|
|
1058
|
+
return { kind: "deny", status, message };
|
|
1059
|
+
}
|
|
1060
|
+
var init_types2 = __esm({
|
|
1061
|
+
"../core/src/middleware/types.ts"() {
|
|
1062
|
+
"use strict";
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
|
|
946
1066
|
// ../core/src/index.ts
|
|
947
1067
|
var init_src = __esm({
|
|
948
1068
|
"../core/src/index.ts"() {
|
|
@@ -968,6 +1088,9 @@ var init_src = __esm({
|
|
|
968
1088
|
init_optional();
|
|
969
1089
|
init_url();
|
|
970
1090
|
init_uuid();
|
|
1091
|
+
init_context();
|
|
1092
|
+
init_pipeline();
|
|
1093
|
+
init_types2();
|
|
971
1094
|
}
|
|
972
1095
|
});
|
|
973
1096
|
|
|
@@ -1000,6 +1123,25 @@ async function ssrRender(options) {
|
|
|
1000
1123
|
let page;
|
|
1001
1124
|
let serverData = [];
|
|
1002
1125
|
if (match) {
|
|
1126
|
+
const navCtx = createServerContext({
|
|
1127
|
+
url: fullPath,
|
|
1128
|
+
intent: match.intent,
|
|
1129
|
+
container: framework.container,
|
|
1130
|
+
request: ssrContext?.request
|
|
1131
|
+
});
|
|
1132
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1133
|
+
navCtx,
|
|
1134
|
+
match.beforeGuards
|
|
1135
|
+
);
|
|
1136
|
+
if (beforeResult.kind !== "next") {
|
|
1137
|
+
const earlyReturn = handleMiddlewareResult(
|
|
1138
|
+
beforeResult,
|
|
1139
|
+
getErrorPage,
|
|
1140
|
+
renderApp,
|
|
1141
|
+
framework
|
|
1142
|
+
);
|
|
1143
|
+
if (earlyReturn) return earlyReturn;
|
|
1144
|
+
}
|
|
1003
1145
|
try {
|
|
1004
1146
|
page = await framework.dispatch(match.intent);
|
|
1005
1147
|
serverData = [{ intent: match.intent, data: page }];
|
|
@@ -1010,6 +1152,23 @@ async function ssrRender(options) {
|
|
|
1010
1152
|
);
|
|
1011
1153
|
page = getErrorPage(500, "Internal error");
|
|
1012
1154
|
}
|
|
1155
|
+
const postCtx = {
|
|
1156
|
+
...navCtx,
|
|
1157
|
+
page
|
|
1158
|
+
};
|
|
1159
|
+
const afterResult = await framework.runAfterLoad(
|
|
1160
|
+
postCtx,
|
|
1161
|
+
match.afterGuards
|
|
1162
|
+
);
|
|
1163
|
+
if (afterResult.kind !== "next") {
|
|
1164
|
+
const lateReturn = handleMiddlewareResult(
|
|
1165
|
+
afterResult,
|
|
1166
|
+
getErrorPage,
|
|
1167
|
+
renderApp,
|
|
1168
|
+
framework
|
|
1169
|
+
);
|
|
1170
|
+
if (lateReturn) return lateReturn;
|
|
1171
|
+
}
|
|
1013
1172
|
} else {
|
|
1014
1173
|
page = getErrorPage(404, "Page not found");
|
|
1015
1174
|
}
|
|
@@ -1025,6 +1184,38 @@ async function ssrRender(options) {
|
|
|
1025
1184
|
framework.dispose();
|
|
1026
1185
|
}
|
|
1027
1186
|
}
|
|
1187
|
+
function handleMiddlewareResult(result, getErrorPage, renderApp, framework) {
|
|
1188
|
+
switch (result.kind) {
|
|
1189
|
+
case "next":
|
|
1190
|
+
return null;
|
|
1191
|
+
case "redirect":
|
|
1192
|
+
return {
|
|
1193
|
+
html: "",
|
|
1194
|
+
head: "",
|
|
1195
|
+
css: "",
|
|
1196
|
+
serverData: [],
|
|
1197
|
+
redirect: { url: result.url, status: result.status }
|
|
1198
|
+
};
|
|
1199
|
+
case "rewrite":
|
|
1200
|
+
return {
|
|
1201
|
+
html: "",
|
|
1202
|
+
head: "",
|
|
1203
|
+
css: "",
|
|
1204
|
+
serverData: [],
|
|
1205
|
+
redirect: { url: result.url, status: 301 }
|
|
1206
|
+
};
|
|
1207
|
+
case "deny": {
|
|
1208
|
+
const errorPage = getErrorPage(result.status, result.message);
|
|
1209
|
+
const rendered = renderApp(errorPage, framework);
|
|
1210
|
+
return {
|
|
1211
|
+
html: rendered.html,
|
|
1212
|
+
head: rendered.head,
|
|
1213
|
+
css: rendered.css,
|
|
1214
|
+
serverData: []
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1028
1219
|
var init_render = __esm({
|
|
1029
1220
|
"../ssr/src/render.ts"() {
|
|
1030
1221
|
"use strict";
|
|
@@ -1294,17 +1485,22 @@ function createSSRApp(options) {
|
|
|
1294
1485
|
const cached = isrCache.get(cacheKey);
|
|
1295
1486
|
if (cached) return c.html(cached);
|
|
1296
1487
|
const requestFetch = parentFetch ? createInternalFetch(parentFetch, ssrDepth + 1) : void 0;
|
|
1488
|
+
const ssrContext = { request: c.req.raw };
|
|
1489
|
+
if (requestFetch) ssrContext.fetch = requestFetch;
|
|
1297
1490
|
const {
|
|
1298
1491
|
html: appHtml,
|
|
1299
1492
|
head,
|
|
1300
1493
|
css,
|
|
1301
1494
|
serverData,
|
|
1302
|
-
renderMode
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1495
|
+
renderMode,
|
|
1496
|
+
redirect: middlewareRedirect
|
|
1497
|
+
} = await render(url, locale, ssrContext);
|
|
1498
|
+
if (middlewareRedirect) {
|
|
1499
|
+
return c.redirect(
|
|
1500
|
+
middlewareRedirect.url,
|
|
1501
|
+
middlewareRedirect.status
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1308
1504
|
if (renderMode === "csr") {
|
|
1309
1505
|
return c.html(injectCSRShell(template, locale));
|
|
1310
1506
|
}
|
|
@@ -1368,11 +1564,14 @@ __export(index_exports, {
|
|
|
1368
1564
|
autoAdapter: () => autoAdapter,
|
|
1369
1565
|
buildUrl: () => buildUrl,
|
|
1370
1566
|
cloudflareAdapter: () => cloudflareAdapter,
|
|
1567
|
+
createBrowserContext: () => createBrowserContext,
|
|
1371
1568
|
createPrefetchedIntentsFromDom: () => createPrefetchedIntentsFromDom,
|
|
1372
1569
|
createSSRApp: () => createSSRApp,
|
|
1373
1570
|
createSSRRender: () => createSSRRender,
|
|
1374
1571
|
createServer: () => createServer,
|
|
1572
|
+
createServerContext: () => createServerContext,
|
|
1375
1573
|
defineRoutes: () => defineRoutes,
|
|
1574
|
+
deny: () => deny,
|
|
1376
1575
|
deserializeServerData: () => deserializeServerData,
|
|
1377
1576
|
detectRuntime: () => detectRuntime,
|
|
1378
1577
|
finesoftFrontViteConfig: () => finesoftFrontViteConfig,
|
|
@@ -1391,10 +1590,12 @@ __export(index_exports, {
|
|
|
1391
1590
|
makeFlowAction: () => makeFlowAction,
|
|
1392
1591
|
mapEach: () => mapEach,
|
|
1393
1592
|
netlifyAdapter: () => netlifyAdapter,
|
|
1593
|
+
next: () => next,
|
|
1394
1594
|
nodeAdapter: () => nodeAdapter,
|
|
1395
1595
|
parseAcceptLanguage: () => parseAcceptLanguage,
|
|
1396
1596
|
pipe: () => pipe,
|
|
1397
1597
|
pipeAsync: () => pipeAsync,
|
|
1598
|
+
redirect: () => redirect,
|
|
1398
1599
|
registerActionHandlers: () => registerActionHandlers,
|
|
1399
1600
|
registerExternalUrlHandler: () => registerExternalUrlHandler,
|
|
1400
1601
|
registerFlowActionHandler: () => registerFlowActionHandler,
|
|
@@ -1405,6 +1606,9 @@ __export(index_exports, {
|
|
|
1405
1606
|
resetFilterCache: () => resetFilterCache,
|
|
1406
1607
|
resolveAdapter: () => resolveAdapter,
|
|
1407
1608
|
resolveRoot: () => resolveRoot,
|
|
1609
|
+
rewrite: () => rewrite,
|
|
1610
|
+
runAfterLoadGuards: () => runAfterLoadGuards,
|
|
1611
|
+
runBeforeLoadGuards: () => runBeforeLoadGuards,
|
|
1408
1612
|
serializeServerData: () => serializeServerData,
|
|
1409
1613
|
shouldLog: () => shouldLog,
|
|
1410
1614
|
ssrRender: () => ssrRender,
|
|
@@ -1587,31 +1791,49 @@ function registerFlowActionHandler(deps) {
|
|
|
1587
1791
|
const { framework, log, callbacks, updateApp } = deps;
|
|
1588
1792
|
let isFirstPage = true;
|
|
1589
1793
|
let navigationId = 0;
|
|
1794
|
+
const MAX_REDIRECTS = 5;
|
|
1590
1795
|
const defaultGetScrollable = () => document.getElementById("scrollable-page-override") || document.getElementById("scrollable-page") || document.documentElement;
|
|
1591
1796
|
const history = new History(log, {
|
|
1592
1797
|
getScrollablePageElement: deps.getScrollablePageElement ?? defaultGetScrollable
|
|
1593
1798
|
});
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
const match2 = framework.routeUrl(url);
|
|
1600
|
-
if (match2) {
|
|
1601
|
-
const page = await framework.dispatch(
|
|
1602
|
-
match2.intent
|
|
1603
|
-
);
|
|
1604
|
-
callbacks.onModal(page);
|
|
1605
|
-
}
|
|
1799
|
+
async function navigateTo(url, redirectCount, thisNav) {
|
|
1800
|
+
if (redirectCount >= MAX_REDIRECTS) {
|
|
1801
|
+
log.error(
|
|
1802
|
+
`Navigation redirect loop detected (${MAX_REDIRECTS} redirects), stopping at: ${url}`
|
|
1803
|
+
);
|
|
1606
1804
|
return;
|
|
1607
1805
|
}
|
|
1608
|
-
const thisNav = ++navigationId;
|
|
1609
1806
|
const shouldReplace = isFirstPage || url === window.location.pathname + window.location.search;
|
|
1610
1807
|
const match = framework.routeUrl(url);
|
|
1611
1808
|
if (!match) {
|
|
1612
1809
|
log.warn(`FlowAction: no route for ${url}`);
|
|
1613
1810
|
return;
|
|
1614
1811
|
}
|
|
1812
|
+
const navCtx = createBrowserContext({
|
|
1813
|
+
url,
|
|
1814
|
+
intent: match.intent,
|
|
1815
|
+
container: framework.container
|
|
1816
|
+
});
|
|
1817
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1818
|
+
navCtx,
|
|
1819
|
+
match.beforeGuards
|
|
1820
|
+
);
|
|
1821
|
+
if (beforeResult.kind === "redirect") {
|
|
1822
|
+
log.debug(`beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
1823
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
if (beforeResult.kind === "deny") {
|
|
1827
|
+
log.warn(
|
|
1828
|
+
`beforeLoad \u2192 denied (${beforeResult.status}): ${beforeResult.message}`
|
|
1829
|
+
);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
if (beforeResult.kind === "rewrite") {
|
|
1833
|
+
log.debug(`beforeLoad \u2192 rewrite to ${beforeResult.url}`);
|
|
1834
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1615
1837
|
const pagePromise = framework.dispatch(
|
|
1616
1838
|
match.intent
|
|
1617
1839
|
);
|
|
@@ -1627,12 +1849,33 @@ function registerFlowActionHandler(deps) {
|
|
|
1627
1849
|
history.beforeTransition();
|
|
1628
1850
|
updateApp({
|
|
1629
1851
|
page: pagePromise.then(
|
|
1630
|
-
(page) => {
|
|
1852
|
+
async (page) => {
|
|
1631
1853
|
if (thisNav !== navigationId) {
|
|
1632
1854
|
log.info("FlowAction commit superseded", url);
|
|
1633
1855
|
return page;
|
|
1634
1856
|
}
|
|
1635
|
-
const
|
|
1857
|
+
const postCtx = {
|
|
1858
|
+
...navCtx,
|
|
1859
|
+
page
|
|
1860
|
+
};
|
|
1861
|
+
const afterResult = await framework.runAfterLoad(
|
|
1862
|
+
postCtx,
|
|
1863
|
+
match.afterGuards
|
|
1864
|
+
);
|
|
1865
|
+
if (afterResult.kind === "redirect") {
|
|
1866
|
+
log.debug(`afterLoad \u2192 redirect to ${afterResult.url}`);
|
|
1867
|
+
navigateTo(afterResult.url, redirectCount + 1, thisNav);
|
|
1868
|
+
return page;
|
|
1869
|
+
}
|
|
1870
|
+
let canonicalURL = url;
|
|
1871
|
+
if (afterResult.kind === "rewrite") {
|
|
1872
|
+
canonicalURL = afterResult.url;
|
|
1873
|
+
log.debug(`afterLoad \u2192 rewrite URL to ${canonicalURL}`);
|
|
1874
|
+
}
|
|
1875
|
+
if (afterResult.kind === "deny") {
|
|
1876
|
+
log.warn(`afterLoad \u2192 denied (${afterResult.status})`);
|
|
1877
|
+
return page;
|
|
1878
|
+
}
|
|
1636
1879
|
if (shouldReplace) {
|
|
1637
1880
|
history.replaceState({ page }, canonicalURL);
|
|
1638
1881
|
} else {
|
|
@@ -1662,6 +1905,23 @@ function registerFlowActionHandler(deps) {
|
|
|
1662
1905
|
isFirstPage
|
|
1663
1906
|
});
|
|
1664
1907
|
isFirstPage = false;
|
|
1908
|
+
}
|
|
1909
|
+
framework.onAction(ACTION_KINDS.FLOW, async (action) => {
|
|
1910
|
+
const flowAction = action;
|
|
1911
|
+
const url = flowAction.url;
|
|
1912
|
+
log.debug(`FlowAction \u2192 ${url}`);
|
|
1913
|
+
if (flowAction.presentationContext === "modal") {
|
|
1914
|
+
const match = framework.routeUrl(url);
|
|
1915
|
+
if (match) {
|
|
1916
|
+
const page = await framework.dispatch(
|
|
1917
|
+
match.intent
|
|
1918
|
+
);
|
|
1919
|
+
callbacks.onModal(page);
|
|
1920
|
+
}
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
const thisNav = ++navigationId;
|
|
1924
|
+
await navigateTo(url, 0, thisNav);
|
|
1665
1925
|
});
|
|
1666
1926
|
history.onPopState(async (url, cachedState) => {
|
|
1667
1927
|
log.debug(`popstate \u2192 ${url}, cached=${!!cachedState}`);
|
|
@@ -1686,6 +1946,30 @@ function registerFlowActionHandler(deps) {
|
|
|
1686
1946
|
});
|
|
1687
1947
|
return;
|
|
1688
1948
|
}
|
|
1949
|
+
const navCtx = createBrowserContext({
|
|
1950
|
+
url: parsed.pathname + parsed.search,
|
|
1951
|
+
intent: routeMatch.intent,
|
|
1952
|
+
container: framework.container
|
|
1953
|
+
});
|
|
1954
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
1955
|
+
navCtx,
|
|
1956
|
+
routeMatch.beforeGuards
|
|
1957
|
+
);
|
|
1958
|
+
if (beforeResult.kind === "redirect") {
|
|
1959
|
+
log.debug(`popstate beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
1960
|
+
const thisNav = ++navigationId;
|
|
1961
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
if (beforeResult.kind === "deny" || beforeResult.kind === "rewrite") {
|
|
1965
|
+
if (beforeResult.kind === "deny") {
|
|
1966
|
+
log.warn(`popstate beforeLoad \u2192 denied`);
|
|
1967
|
+
} else {
|
|
1968
|
+
const thisNav = ++navigationId;
|
|
1969
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
1970
|
+
}
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1689
1973
|
const pagePromise = framework.dispatch(
|
|
1690
1974
|
routeMatch.intent
|
|
1691
1975
|
);
|
|
@@ -1875,7 +2159,7 @@ function _sanitizeProxyPath(raw) {
|
|
|
1875
2159
|
const pattern = `"${config.prefix}/*"`;
|
|
1876
2160
|
const headersJson = JSON.stringify(config.headers ?? {});
|
|
1877
2161
|
const cacheStr = config.cache ? JSON.stringify(config.cache) : "null";
|
|
1878
|
-
const
|
|
2162
|
+
const redirect2 = config.followRedirects ? '"follow"' : '"manual"';
|
|
1879
2163
|
let authCode = "";
|
|
1880
2164
|
if (config.auth) {
|
|
1881
2165
|
const envKey = JSON.stringify(config.auth.envKey);
|
|
@@ -1894,7 +2178,7 @@ function _sanitizeProxyPath(raw) {
|
|
|
1894
2178
|
_reqUrl.searchParams.forEach((v, k) => _target.searchParams.set(k, v));
|
|
1895
2179
|
const _headers = ${headersJson};${authCode}
|
|
1896
2180
|
try {
|
|
1897
|
-
const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${
|
|
2181
|
+
const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${redirect2} });
|
|
1898
2182
|
const _body = await _resp.text();
|
|
1899
2183
|
const _rh = { "Content-Type": _resp.headers.get("Content-Type") || "application/json" };
|
|
1900
2184
|
if (${cacheStr}) _rh["Cache-Control"] = ${cacheStr};
|
|
@@ -3319,11 +3603,14 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3319
3603
|
autoAdapter,
|
|
3320
3604
|
buildUrl,
|
|
3321
3605
|
cloudflareAdapter,
|
|
3606
|
+
createBrowserContext,
|
|
3322
3607
|
createPrefetchedIntentsFromDom,
|
|
3323
3608
|
createSSRApp,
|
|
3324
3609
|
createSSRRender,
|
|
3325
3610
|
createServer,
|
|
3611
|
+
createServerContext,
|
|
3326
3612
|
defineRoutes,
|
|
3613
|
+
deny,
|
|
3327
3614
|
deserializeServerData,
|
|
3328
3615
|
detectRuntime,
|
|
3329
3616
|
finesoftFrontViteConfig,
|
|
@@ -3342,10 +3629,12 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3342
3629
|
makeFlowAction,
|
|
3343
3630
|
mapEach,
|
|
3344
3631
|
netlifyAdapter,
|
|
3632
|
+
next,
|
|
3345
3633
|
nodeAdapter,
|
|
3346
3634
|
parseAcceptLanguage,
|
|
3347
3635
|
pipe,
|
|
3348
3636
|
pipeAsync,
|
|
3637
|
+
redirect,
|
|
3349
3638
|
registerActionHandlers,
|
|
3350
3639
|
registerExternalUrlHandler,
|
|
3351
3640
|
registerFlowActionHandler,
|
|
@@ -3356,6 +3645,9 @@ function finesoftFrontViteConfig(options = {}) {
|
|
|
3356
3645
|
resetFilterCache,
|
|
3357
3646
|
resolveAdapter,
|
|
3358
3647
|
resolveRoot,
|
|
3648
|
+
rewrite,
|
|
3649
|
+
runAfterLoadGuards,
|
|
3650
|
+
runBeforeLoadGuards,
|
|
3359
3651
|
serializeServerData,
|
|
3360
3652
|
shouldLog,
|
|
3361
3653
|
ssrRender,
|