@finesoft/front 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -24,6 +24,13 @@ interface SSRRenderOptions {
24
24
  getErrorPage: (status: number, message: string) => BasePage;
25
25
  /** 应用层渲染函数(如 Svelte SSR render) */
26
26
  renderApp: (page: BasePage, framework: Framework) => SSRAppResult;
27
+ /** 可选的 SSR 请求上下文(如自定义 fetch) */
28
+ ssrContext?: SSRContext;
29
+ }
30
+ /** SSR 请求级上下文 */
31
+ interface SSRContext {
32
+ /** 自定义 fetch(如 Hono 内部路由回环) */
33
+ fetch?: typeof globalThis.fetch;
27
34
  }
28
35
  interface SSRAppResult {
29
36
  html: string;
@@ -67,9 +74,9 @@ interface SSRRenderConfig {
67
74
  /**
68
75
  * 创建 render 函数
69
76
  *
70
- * @returns `render(url, locale)` — 供 @finesoft/server SSRModule 使用
77
+ * @returns `render(url, locale, ssrContext?)` — 供 @finesoft/server SSRModule 使用
71
78
  */
72
- declare function createSSRRender(config: SSRRenderConfig): (url: string, locale: string) => Promise<SSRRenderResult>;
79
+ declare function createSSRRender(config: SSRRenderConfig): (url: string, locale: string, ssrContext?: SSRContext) => Promise<SSRRenderResult>;
73
80
 
74
81
  /**
75
82
  * injectSSRContent — 将 SSR 渲染结果注入 HTML 模板
@@ -292,7 +299,9 @@ declare function vercelAdapter(): Adapter;
292
299
  */
293
300
 
294
301
  interface SSRModule {
295
- render: (url: string, locale: string) => Promise<{
302
+ render: (url: string, locale: string, ssrContext?: {
303
+ fetch?: typeof globalThis.fetch;
304
+ }) => Promise<{
296
305
  html: string;
297
306
  head: string;
298
307
  css: string;
@@ -316,6 +325,12 @@ interface SSRAppOptions {
316
325
  supportedLocales?: string[];
317
326
  /** 默认语言 */
318
327
  defaultLocale?: string;
328
+ /**
329
+ * 父级 Hono app 的 fetch 函数,用于 SSR 内部路由回环。
330
+ * SSR 渲染时,控制器的 fetch 请求(如 /api/apple/*)会通过此函数
331
+ * 直接在进程内路由到代理 handler,避免网络自请求死锁。
332
+ */
333
+ parentFetch?: (request: Request) => Promise<Response>;
319
334
  }
320
335
  declare function createSSRApp(options: SSRAppOptions): Hono;
321
336
 
@@ -478,4 +493,4 @@ declare function finesoftFrontViteConfig(options?: FinesoftFrontViteOptions): {
478
493
  closeBundle(): Promise<void>;
479
494
  };
480
495
 
481
- export { type Adapter, type AdapterContext, BasePage, type FinesoftFrontViteOptions, Framework, FrameworkConfig, type InjectSSROptions, PrefetchedIntent, type RuntimeInfo, type SSRAppOptions, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, type ServerConfig, type ServerInstance, type StartServerOptions, autoAdapter, cloudflareAdapter, createSSRApp, createSSRRender, createServer, detectRuntime, finesoftFrontViteConfig, injectCSRShell, injectSSRContent, netlifyAdapter, nodeAdapter, parseAcceptLanguage, resolveAdapter, resolveRoot, serializeServerData, ssrRender, startServer, staticAdapter, vercelAdapter };
496
+ export { type Adapter, type AdapterContext, BasePage, type FinesoftFrontViteOptions, Framework, FrameworkConfig, type InjectSSROptions, PrefetchedIntent, type RuntimeInfo, type SSRAppOptions, type SSRContext, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, type ServerConfig, type ServerInstance, type StartServerOptions, autoAdapter, cloudflareAdapter, createSSRApp, createSSRRender, createServer, detectRuntime, finesoftFrontViteConfig, injectCSRShell, injectSSRContent, netlifyAdapter, nodeAdapter, parseAcceptLanguage, resolveAdapter, resolveRoot, serializeServerData, ssrRender, startServer, staticAdapter, vercelAdapter };
package/dist/index.d.ts CHANGED
@@ -24,6 +24,13 @@ interface SSRRenderOptions {
24
24
  getErrorPage: (status: number, message: string) => BasePage;
25
25
  /** 应用层渲染函数(如 Svelte SSR render) */
26
26
  renderApp: (page: BasePage, framework: Framework) => SSRAppResult;
27
+ /** 可选的 SSR 请求上下文(如自定义 fetch) */
28
+ ssrContext?: SSRContext;
29
+ }
30
+ /** SSR 请求级上下文 */
31
+ interface SSRContext {
32
+ /** 自定义 fetch(如 Hono 内部路由回环) */
33
+ fetch?: typeof globalThis.fetch;
27
34
  }
28
35
  interface SSRAppResult {
29
36
  html: string;
@@ -67,9 +74,9 @@ interface SSRRenderConfig {
67
74
  /**
68
75
  * 创建 render 函数
69
76
  *
70
- * @returns `render(url, locale)` — 供 @finesoft/server SSRModule 使用
77
+ * @returns `render(url, locale, ssrContext?)` — 供 @finesoft/server SSRModule 使用
71
78
  */
72
- declare function createSSRRender(config: SSRRenderConfig): (url: string, locale: string) => Promise<SSRRenderResult>;
79
+ declare function createSSRRender(config: SSRRenderConfig): (url: string, locale: string, ssrContext?: SSRContext) => Promise<SSRRenderResult>;
73
80
 
74
81
  /**
75
82
  * injectSSRContent — 将 SSR 渲染结果注入 HTML 模板
@@ -292,7 +299,9 @@ declare function vercelAdapter(): Adapter;
292
299
  */
293
300
 
294
301
  interface SSRModule {
295
- render: (url: string, locale: string) => Promise<{
302
+ render: (url: string, locale: string, ssrContext?: {
303
+ fetch?: typeof globalThis.fetch;
304
+ }) => Promise<{
296
305
  html: string;
297
306
  head: string;
298
307
  css: string;
@@ -316,6 +325,12 @@ interface SSRAppOptions {
316
325
  supportedLocales?: string[];
317
326
  /** 默认语言 */
318
327
  defaultLocale?: string;
328
+ /**
329
+ * 父级 Hono app 的 fetch 函数,用于 SSR 内部路由回环。
330
+ * SSR 渲染时,控制器的 fetch 请求(如 /api/apple/*)会通过此函数
331
+ * 直接在进程内路由到代理 handler,避免网络自请求死锁。
332
+ */
333
+ parentFetch?: (request: Request) => Promise<Response>;
319
334
  }
320
335
  declare function createSSRApp(options: SSRAppOptions): Hono;
321
336
 
@@ -478,4 +493,4 @@ declare function finesoftFrontViteConfig(options?: FinesoftFrontViteOptions): {
478
493
  closeBundle(): Promise<void>;
479
494
  };
480
495
 
481
- export { type Adapter, type AdapterContext, BasePage, type FinesoftFrontViteOptions, Framework, FrameworkConfig, type InjectSSROptions, PrefetchedIntent, type RuntimeInfo, type SSRAppOptions, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, type ServerConfig, type ServerInstance, type StartServerOptions, autoAdapter, cloudflareAdapter, createSSRApp, createSSRRender, createServer, detectRuntime, finesoftFrontViteConfig, injectCSRShell, injectSSRContent, netlifyAdapter, nodeAdapter, parseAcceptLanguage, resolveAdapter, resolveRoot, serializeServerData, ssrRender, startServer, staticAdapter, vercelAdapter };
496
+ export { type Adapter, type AdapterContext, BasePage, type FinesoftFrontViteOptions, Framework, FrameworkConfig, type InjectSSROptions, PrefetchedIntent, type RuntimeInfo, type SSRAppOptions, type SSRContext, type SSRModule, type SSRRenderConfig, type SSRRenderOptions, type SSRRenderResult, SSR_PLACEHOLDERS, type ServerConfig, type ServerInstance, type StartServerOptions, autoAdapter, cloudflareAdapter, createSSRApp, createSSRRender, createServer, detectRuntime, finesoftFrontViteConfig, injectCSRShell, injectSSRContent, netlifyAdapter, nodeAdapter, parseAcceptLanguage, resolveAdapter, resolveRoot, serializeServerData, ssrRender, startServer, staticAdapter, vercelAdapter };
package/dist/index.js CHANGED
@@ -9,8 +9,9 @@ import {
9
9
  tryScroll
10
10
  } from "./chunk-H3RNYNSD.js";
11
11
  import {
12
+ createInternalFetch,
12
13
  createSSRApp
13
- } from "./chunk-IITKGRCO.js";
14
+ } from "./chunk-WD72JAMS.js";
14
15
  import {
15
16
  SSR_PLACEHOLDERS,
16
17
  createSSRRender,
@@ -18,7 +19,7 @@ import {
18
19
  injectSSRContent,
19
20
  serializeServerData,
20
21
  ssrRender
21
- } from "./chunk-5ZECBECP.js";
22
+ } from "./chunk-N4AEOYUR.js";
22
23
  import {
23
24
  ACTION_KINDS,
24
25
  ActionDispatcher,
@@ -147,6 +148,20 @@ const app = new Hono();
147
148
  ${setupCall}
148
149
  ${opts.platformMiddleware ?? ""}
149
150
 
151
+ // \u5185\u90E8 fetch \u56DE\u73AF\uFF1ASSR \u63A7\u5236\u5668\u7684 fetch \u8BF7\u6C42\u76F4\u63A5\u8D70 Hono \u5185\u5B58\u8DEF\u7531
152
+ // \u53EA\u62E6\u622A\u76F8\u5BF9\u8DEF\u5F84\uFF08/api/* \u7B49\uFF09\uFF0C\u7EDD\u5BF9 URL \u8D70\u6B63\u5E38\u7F51\u7EDC\uFF1B\u542B\u9012\u5F52\u4FDD\u62A4
153
+ let _fetchDepth = 0;
154
+ function _internalFetch(input, init) {
155
+ if (typeof input === "string" && input.startsWith("/")) {
156
+ if (_fetchDepth >= 5) {
157
+ return Promise.resolve(new Response("Internal fetch loop detected", { status: 508 }));
158
+ }
159
+ _fetchDepth++;
160
+ return app.fetch(new Request("http://localhost" + input, init)).finally(() => { _fetchDepth--; });
161
+ }
162
+ return globalThis.fetch(input, init);
163
+ }
164
+
150
165
  app.get("*", async (c) => {
151
166
  const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
152
167
  try {
@@ -162,7 +177,7 @@ app.get("*", async (c) => {
162
177
  const cached = await platformCacheGet(url);
163
178
  if (cached) return c.html(cached);
164
179
 
165
- const { html: appHtml, head, css, serverData, renderMode } = await render(url, locale);
180
+ const { html: appHtml, head, css, serverData, renderMode } = await render(url, locale, { fetch: _internalFetch });
166
181
 
167
182
  // \u8DEF\u7531\u7EA7 CSR
168
183
  if (renderMode === "csr") {
@@ -691,14 +706,31 @@ function vercelAdapter() {
691
706
  fs.rmSync(outputDir, { recursive: true, force: true });
692
707
  const entrySource = generateSSREntry(ctx, {
693
708
  platformImport: `import { getRequestListener } from "@hono/node-server";`,
694
- platformExport: `export default getRequestListener(app.fetch);`
709
+ platformExport: [
710
+ `const _listener = getRequestListener(app.fetch);`,
711
+ `export default (req, res) => {`,
712
+ ` const m = req.headers["x-now-route-matches"];`,
713
+ ` if (typeof m === "string") {`,
714
+ ` try {`,
715
+ ` const p = new URLSearchParams(m);`,
716
+ ` const c = p.get("1");`,
717
+ ` if (c != null) {`,
718
+ ` const qi = (req.url || "").indexOf("?");`,
719
+ ` const qs = qi !== -1 ? req.url.slice(qi) : "";`,
720
+ ` req.url = "/" + decodeURIComponent(c) + qs;`,
721
+ ` }`,
722
+ ` } catch {}`,
723
+ ` }`,
724
+ ` return _listener(req, res);`,
725
+ `};`
726
+ ].join("\n")
695
727
  });
696
728
  const tempEntry = path.resolve(root, ".vercel-entry.tmp.mjs");
697
729
  fs.writeFileSync(tempEntry, entrySource);
698
730
  try {
699
731
  const funcDir = path.resolve(
700
732
  root,
701
- ".vercel/output/functions/[[...path]].func"
733
+ ".vercel/output/functions/ssr.func"
702
734
  );
703
735
  await buildBundle(ctx, {
704
736
  entry: ".vercel-entry.tmp.mjs",
@@ -728,7 +760,7 @@ function vercelAdapter() {
728
760
  version: 3,
729
761
  routes: [
730
762
  { handle: "filesystem" },
731
- { src: "/(.*)", dest: "/functions/[[...path]]" }
763
+ { src: "/(.*)", dest: "/ssr" }
732
764
  ]
733
765
  },
734
766
  null,
@@ -1003,6 +1035,7 @@ async function createServer(config = {}) {
1003
1035
  isProduction: runtime.isProduction,
1004
1036
  supportedLocales: locales,
1005
1037
  defaultLocale,
1038
+ parentFetch: app.fetch.bind(app),
1006
1039
  ...ssr
1007
1040
  });
1008
1041
  app.route("/", ssrApp);
@@ -1070,7 +1103,7 @@ function finesoftFrontViteConfig(options = {}) {
1070
1103
  /* @vite-ignore */
1071
1104
  "hono"
1072
1105
  );
1073
- const { createSSRApp: createSSRApp2 } = await import("./app-BPO26FAD.js");
1106
+ const { createSSRApp: createSSRApp2 } = await import("./app-QERC5VUP.js");
1074
1107
  const { getRequestListener } = await import(
1075
1108
  /* @vite-ignore */
1076
1109
  "@hono/node-server"
@@ -1089,7 +1122,8 @@ function finesoftFrontViteConfig(options = {}) {
1089
1122
  isProduction: false,
1090
1123
  ssrEntryPath: "/" + ssrEntry,
1091
1124
  supportedLocales: options.locales,
1092
- defaultLocale: options.defaultLocale
1125
+ defaultLocale: options.defaultLocale,
1126
+ parentFetch: app.fetch.bind(app)
1093
1127
  });
1094
1128
  app.route("/", ssrApp);
1095
1129
  const listener = getRequestListener(app.fetch);
@@ -1119,7 +1153,7 @@ function finesoftFrontViteConfig(options = {}) {
1119
1153
  );
1120
1154
  const { injectSSRContent: injectSSRContent2, injectCSRShell: injectCSRShell2 } = await import(
1121
1155
  /* @vite-ignore */
1122
- "./src-KUWACLPD.js"
1156
+ "./src-LYKZSLF7.js"
1123
1157
  );
1124
1158
  const { parseAcceptLanguage: parseAcceptLanguage2 } = await import("./locale-YK3THSI6.js");
1125
1159
  const { getRequestListener } = await import(
@@ -1181,7 +1215,9 @@ function finesoftFrontViteConfig(options = {}) {
1181
1215
  css,
1182
1216
  serverData,
1183
1217
  renderMode
1184
- } = await ssrModule.render(url, locale);
1218
+ } = await ssrModule.render(url, locale, {
1219
+ fetch: createInternalFetch(app.fetch.bind(app))
1220
+ });
1185
1221
  if (renderMode === "csr") {
1186
1222
  return c.html(injectCSRShell2(template, locale));
1187
1223
  }