@finesoft/front 0.1.13 → 0.1.15

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.js CHANGED
@@ -1,3 +1,23 @@
1
+ import {
2
+ History,
3
+ createPrefetchedIntentsFromDom,
4
+ deserializeServerData,
5
+ registerActionHandlers,
6
+ registerExternalUrlHandler,
7
+ registerFlowActionHandler,
8
+ startBrowserApp,
9
+ tryScroll
10
+ } from "./chunk-T2AQHAYK.js";
11
+ import {
12
+ createSSRApp
13
+ } from "./chunk-Z4MHYAS3.js";
14
+ import {
15
+ SSR_PLACEHOLDERS,
16
+ createSSRRender,
17
+ injectSSRContent,
18
+ serializeServerData,
19
+ ssrRender
20
+ } from "./chunk-2VETWTN5.js";
1
21
  import {
2
22
  ACTION_KINDS,
3
23
  ActionDispatcher,
@@ -10,7 +30,6 @@ import {
10
30
  Container,
11
31
  DEP_KEYS,
12
32
  Framework,
13
- History,
14
33
  HttpClient,
15
34
  HttpError,
16
35
  IntentDispatcher,
@@ -18,9 +37,7 @@ import {
18
37
  PrefetchedIntents,
19
38
  Router,
20
39
  buildUrl,
21
- createPrefetchedIntentsFromDom,
22
40
  defineRoutes,
23
- deserializeServerData,
24
41
  generateUuid,
25
42
  getBaseUrl,
26
43
  isCompoundAction,
@@ -34,217 +51,460 @@ import {
34
51
  mapEach,
35
52
  pipe,
36
53
  pipeAsync,
37
- registerActionHandlers,
38
- registerExternalUrlHandler,
39
- registerFlowActionHandler,
40
54
  removeHost,
41
55
  removeQueryParams,
42
56
  removeScheme,
43
57
  resetFilterCache,
44
58
  shouldLog,
45
- stableStringify,
46
- startBrowserApp,
47
- tryScroll
48
- } from "./chunk-OVGQ4NUA.js";
59
+ stableStringify
60
+ } from "./chunk-RVKDILGM.js";
61
+ import {
62
+ parseAcceptLanguage
63
+ } from "./chunk-FYP2ZYYV.js";
49
64
 
50
- // ../ssr/src/render.ts
51
- async function ssrRender(options) {
52
- const { url, frameworkConfig, bootstrap, getErrorPage, renderApp } = options;
53
- const framework = Framework.create(frameworkConfig);
54
- bootstrap(framework);
55
- const parsed = new URL(url, "http://localhost");
56
- const fullPath = parsed.pathname + parsed.search;
57
- const match = framework.routeUrl(fullPath);
58
- let page;
59
- let serverData = [];
60
- if (match) {
61
- try {
62
- page = await framework.dispatch(match.intent);
63
- serverData = [{ intent: match.intent, data: page }];
64
- } catch {
65
- page = getErrorPage(500, "Internal error");
66
- }
67
- } else {
68
- page = getErrorPage(404, "Page not found");
65
+ // ../server/src/adapters/shared.ts
66
+ var BUILD_TOOL_EXTERNALS = [
67
+ "vite",
68
+ "esbuild",
69
+ "rollup",
70
+ "fsevents",
71
+ "lightningcss"
72
+ ];
73
+ function generateSSREntry(ctx, opts) {
74
+ const setupImport = ctx.setupPath ? `import _setupDefault from "./${ctx.setupPath}";` : ``;
75
+ const setupCall = ctx.setupPath ? `if (typeof _setupDefault === "function") await _setupDefault(app);` : ``;
76
+ const locales = JSON.stringify(ctx.locales);
77
+ const defaultLocale = JSON.stringify(ctx.defaultLocale);
78
+ return `
79
+ import { Hono } from "hono";
80
+ ${opts.platformImport}
81
+ import { render, serializeServerData } from "./${ctx.ssrEntry}";
82
+ ${setupImport}
83
+
84
+ const TEMPLATE = ${JSON.stringify(ctx.templateHtml)};
85
+ const LOCALES = ${locales};
86
+ const DEFAULT_LOCALE = ${defaultLocale};
87
+
88
+ function parseAcceptLanguage(header) {
89
+ if (!header) return DEFAULT_LOCALE;
90
+ const langs = header.split(",").map(p => {
91
+ const [l, q] = p.trim().split(";q=");
92
+ return { l: l.trim().toLowerCase(), q: q ? +q : 1 };
93
+ }).sort((a, b) => b.q - a.q);
94
+ for (const { l } of langs) {
95
+ const prefix = l.split("-")[0];
96
+ if (LOCALES.includes(prefix)) return prefix;
69
97
  }
70
- const result = renderApp(page, framework);
71
- framework.dispose();
72
- return {
73
- html: result.html,
74
- head: result.head,
75
- css: result.css,
76
- serverData
77
- };
98
+ return DEFAULT_LOCALE;
78
99
  }
79
100
 
80
- // ../ssr/src/create-render.ts
81
- function createSSRRender(config) {
82
- const { bootstrap, getErrorPage, renderApp, frameworkConfig } = config;
83
- return (url, locale) => ssrRender({
84
- url,
85
- frameworkConfig: frameworkConfig ?? {},
86
- bootstrap,
87
- getErrorPage,
88
- renderApp: (page) => renderApp(page, locale)
89
- });
101
+ function injectSSR(t, locale, head, css, html, data) {
102
+ return t
103
+ .replace("<!--ssr-lang-->", locale)
104
+ .replace("<!--ssr-head-->", head + "\\n<style>" + css + "</style>")
105
+ .replace("<!--ssr-body-->", html)
106
+ .replace("<!--ssr-data-->", '<script id="serialized-server-data" type="application/json">' + data + "</script>");
90
107
  }
91
108
 
92
- // ../ssr/src/inject.ts
93
- var SSR_PLACEHOLDERS = {
94
- LANG: "<!--ssr-lang-->",
95
- HEAD: "<!--ssr-head-->",
96
- BODY: "<!--ssr-body-->",
97
- DATA: "<!--ssr-data-->"
98
- };
99
- function injectSSRContent(options) {
100
- const { template, locale, head, css, html, serializedData } = options;
101
- const cssTag = css ? `<style>${css}</style>` : "";
102
- return template.replace(SSR_PLACEHOLDERS.LANG, locale).replace(SSR_PLACEHOLDERS.HEAD, `${head}
103
- ${cssTag}`).replace(SSR_PLACEHOLDERS.BODY, html).replace(
104
- SSR_PLACEHOLDERS.DATA,
105
- `<script id="serialized-server-data" type="application/json">${serializedData}</script>`
106
- );
109
+ const app = new Hono();
110
+ ${setupCall}
111
+
112
+ app.get("*", async (c) => {
113
+ const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
114
+ try {
115
+ const locale = parseAcceptLanguage(c.req.header("accept-language"));
116
+ const { html: appHtml, head, css, serverData } = await render(url, locale);
117
+ const serializedData = serializeServerData(serverData);
118
+ return c.html(injectSSR(TEMPLATE, locale, head, css, appHtml, serializedData));
119
+ } catch (e) {
120
+ console.error("[SSR Error]", e);
121
+ return c.text("Internal Server Error", 500);
122
+ }
123
+ });
124
+
125
+ ${opts.platformExport}
126
+ `;
127
+ }
128
+ async function buildBundle(ctx, opts) {
129
+ await ctx.vite.build({
130
+ root: ctx.root,
131
+ build: {
132
+ ssr: opts.entry,
133
+ outDir: opts.outDir,
134
+ emptyOutDir: true,
135
+ target: opts.target ?? "node18",
136
+ rollupOptions: {
137
+ output: { entryFileNames: opts.fileName ?? "index.mjs" }
138
+ }
139
+ },
140
+ ssr: {
141
+ noExternal: opts.noExternal !== false,
142
+ external: opts.external ?? BUILD_TOOL_EXTERNALS
143
+ },
144
+ resolve: ctx.resolvedResolve,
145
+ css: ctx.resolvedCss
146
+ });
147
+ }
148
+ function copyStaticAssets(ctx, destDir, opts) {
149
+ const { fs, path } = ctx;
150
+ fs.cpSync(path.resolve(ctx.root, "dist/client"), destDir, {
151
+ recursive: true
152
+ });
153
+ if (opts?.excludeHtml !== false) {
154
+ fs.rmSync(path.join(destDir, "index.html"), { force: true });
155
+ }
107
156
  }
108
157
 
109
- // ../ssr/src/server-data.ts
110
- var HTML_REPLACEMENTS = {
111
- "<": "\\u003C",
112
- ">": "\\u003E",
113
- "/": "\\u002F",
114
- "\u2028": "\\u2028",
115
- "\u2029": "\\u2029"
116
- };
117
- var HTML_ESCAPE_PATTERN = /[<>/\u2028\u2029]/g;
118
- function serializeServerData(data) {
119
- const json = JSON.stringify(data);
120
- return json.replace(
121
- HTML_ESCAPE_PATTERN,
122
- (match) => HTML_REPLACEMENTS[match] ?? match
123
- );
158
+ // ../server/src/adapters/cloudflare.ts
159
+ function cloudflareAdapter() {
160
+ return {
161
+ name: "cloudflare",
162
+ async build(ctx) {
163
+ const { fs, path, root } = ctx;
164
+ const outputDir = path.resolve(root, "dist/cloudflare");
165
+ fs.rmSync(outputDir, { recursive: true, force: true });
166
+ const entrySource = generateSSREntry(ctx, {
167
+ platformImport: ``,
168
+ platformExport: `export default app;`
169
+ });
170
+ const tempEntry = path.resolve(root, ".cf-entry.tmp.mjs");
171
+ fs.writeFileSync(tempEntry, entrySource);
172
+ try {
173
+ await buildBundle(ctx, {
174
+ entry: ".cf-entry.tmp.mjs",
175
+ outDir: outputDir,
176
+ target: "es2022",
177
+ fileName: "_worker.js"
178
+ // 使用默认 external(vite/esbuild/rollup/fsevents/lightningcss)
179
+ // 这些构建工具运行时不需要,且 fsevents 是 macOS .node 原生二进制无法打包
180
+ });
181
+ copyStaticAssets(ctx, path.resolve(outputDir, "assets"));
182
+ } finally {
183
+ fs.rmSync(tempEntry, { force: true });
184
+ }
185
+ console.log(" Cloudflare output \u2192 dist/cloudflare/\n");
186
+ }
187
+ };
124
188
  }
125
189
 
126
- // ../server/src/app.ts
127
- import { Hono } from "hono";
190
+ // ../server/src/adapters/netlify.ts
191
+ function netlifyAdapter() {
192
+ return {
193
+ name: "netlify",
194
+ async build(ctx) {
195
+ const { fs, path, root } = ctx;
196
+ const funcDir = path.resolve(
197
+ root,
198
+ ".netlify/functions-internal/ssr"
199
+ );
200
+ fs.rmSync(path.resolve(root, ".netlify"), {
201
+ recursive: true,
202
+ force: true
203
+ });
204
+ const entrySource = generateSSREntry(ctx, {
205
+ platformImport: `import { handle } from "hono/netlify";`,
206
+ platformExport: `export default handle(app);`
207
+ });
208
+ const tempEntry = path.resolve(root, ".netlify-entry.tmp.mjs");
209
+ fs.writeFileSync(tempEntry, entrySource);
210
+ try {
211
+ await buildBundle(ctx, {
212
+ entry: ".netlify-entry.tmp.mjs",
213
+ outDir: funcDir,
214
+ target: "node18"
215
+ });
216
+ } finally {
217
+ fs.rmSync(tempEntry, { force: true });
218
+ }
219
+ const redirects = `/* /.netlify/functions/ssr 200
220
+ `;
221
+ fs.writeFileSync(
222
+ path.resolve(root, "dist/client/_redirects"),
223
+ redirects
224
+ );
225
+ console.log(
226
+ " Netlify output \u2192 .netlify/functions-internal/ssr/\n Publish dir: dist/client/\n"
227
+ );
228
+ }
229
+ };
230
+ }
128
231
 
129
- // ../server/src/locale.ts
130
- function parseAcceptLanguage(header, supported, fallback) {
131
- const effectiveSupported = supported ?? ["zh", "en"];
132
- const effectiveFallback = fallback ?? effectiveSupported[0] ?? "en";
133
- if (!header) return effectiveFallback;
134
- const langs = header.split(",").map((part) => {
135
- const [lang, q] = part.trim().split(";q=");
136
- return {
137
- lang: lang.trim().toLowerCase(),
138
- q: q ? parseFloat(q) : 1
139
- };
140
- }).sort((a, b) => b.q - a.q);
141
- for (const { lang } of langs) {
142
- const prefix = lang.split("-")[0];
143
- if (effectiveSupported.includes(prefix)) {
144
- return prefix;
232
+ // ../server/src/adapters/node.ts
233
+ function nodeAdapter() {
234
+ return {
235
+ name: "node",
236
+ async build(ctx) {
237
+ const { fs, path, root } = ctx;
238
+ const entrySource = generateSSREntry(ctx, {
239
+ platformImport: `import { serve } from "@hono/node-server";`,
240
+ platformExport: `
241
+ const port = +(process.env.PORT || 3000);
242
+ serve({ fetch: app.fetch, port }, (info) => {
243
+ console.log(\`Server running at http://localhost:\${info.port}\`);
244
+ });
245
+ `
246
+ });
247
+ const tempEntry = path.resolve(root, ".node-entry.tmp.mjs");
248
+ fs.writeFileSync(tempEntry, entrySource);
249
+ try {
250
+ await buildBundle(ctx, {
251
+ entry: ".node-entry.tmp.mjs",
252
+ outDir: path.resolve(root, "dist/server"),
253
+ target: "node18"
254
+ });
255
+ } finally {
256
+ fs.rmSync(tempEntry, { force: true });
257
+ }
258
+ console.log(
259
+ " Node output \u2192 dist/server/index.mjs\n Run: node dist/server/index.mjs\n"
260
+ );
145
261
  }
146
- }
147
- return effectiveFallback;
262
+ };
148
263
  }
149
264
 
150
- // ../server/src/app.ts
151
- function createSSRApp(options) {
152
- const {
153
- root,
154
- vite,
155
- isProduction,
156
- ssrEntryPath = "/src/ssr.ts",
157
- ssrProductionModule,
158
- supportedLocales,
159
- defaultLocale
160
- } = options;
161
- const app = new Hono();
162
- async function readTemplate(url) {
163
- if (!isProduction && vite) {
164
- const { readFileSync: readFileSync2 } = await import(
265
+ // ../server/src/adapters/static.ts
266
+ function staticAdapter(opts = {}) {
267
+ return {
268
+ name: "static",
269
+ async build(ctx) {
270
+ const { fs, path, root, vite } = ctx;
271
+ const outputDir = path.resolve(root, "dist/static");
272
+ fs.rmSync(outputDir, { recursive: true, force: true });
273
+ fs.mkdirSync(outputDir, { recursive: true });
274
+ const { pathToFileURL } = await import(
165
275
  /* @vite-ignore */
166
- "fs"
276
+ "url"
167
277
  );
168
- const { resolve: resolve2 } = await import(
278
+ const ssrPath = pathToFileURL(
279
+ path.resolve(root, "dist/server/ssr.js")
280
+ ).href;
281
+ const ssrModule = await import(
169
282
  /* @vite-ignore */
170
- "path"
283
+ ssrPath
171
284
  );
172
- const raw = readFileSync2(resolve2(root, "index.html"), "utf-8");
173
- return vite.transformIndexHtml(url, raw);
174
- }
175
- const isDeno = typeof globalThis.Deno !== "undefined";
176
- if (isDeno) {
177
- return globalThis.Deno.readTextFileSync(
178
- new URL("../dist/client/index.html", import.meta.url)
285
+ const routePaths = await extractRoutes(ctx, opts);
286
+ const allUrls = [];
287
+ for (const routePath of routePaths) {
288
+ for (const locale of ctx.locales) {
289
+ const url = locale === ctx.defaultLocale ? routePath : `/${locale}${routePath === "/" ? "" : routePath}`;
290
+ allUrls.push(url);
291
+ }
292
+ }
293
+ console.log(
294
+ ` Pre-rendering ${allUrls.length} pages (${routePaths.length} routes \xD7 ${ctx.locales.length} locales)...
295
+ `
179
296
  );
297
+ for (const url of allUrls) {
298
+ try {
299
+ const locale = inferLocale(
300
+ url,
301
+ ctx.locales,
302
+ ctx.defaultLocale
303
+ );
304
+ const {
305
+ html: appHtml,
306
+ head,
307
+ css,
308
+ serverData
309
+ } = await ssrModule.render(url, locale);
310
+ const serializedData = ssrModule.serializeServerData(serverData);
311
+ const finalHtml = injectSSRForStatic(
312
+ ctx.templateHtml,
313
+ locale,
314
+ head,
315
+ css,
316
+ appHtml,
317
+ serializedData
318
+ );
319
+ const filePath = url === "/" ? path.join(outputDir, "index.html") : path.join(outputDir, url, "index.html");
320
+ fs.mkdirSync(path.resolve(filePath, ".."), {
321
+ recursive: true
322
+ });
323
+ fs.writeFileSync(filePath, finalHtml);
324
+ } catch (e) {
325
+ console.warn(` [static] Failed to render ${url}:`, e);
326
+ }
327
+ }
328
+ ctx.copyStaticAssets(outputDir, { excludeHtml: true });
329
+ console.log(` Static output \u2192 dist/static/
330
+ `);
180
331
  }
181
- const { readFileSync } = await import(
332
+ };
333
+ }
334
+ async function extractRoutes(ctx, opts) {
335
+ const routesFile = opts.routesExport ?? "src/lib/bootstrap.ts";
336
+ const paths = [];
337
+ try {
338
+ const { pathToFileURL } = await import(
182
339
  /* @vite-ignore */
183
- "fs"
340
+ "url"
184
341
  );
185
- const { resolve } = await import(
342
+ await ctx.vite.build({
343
+ root: ctx.root,
344
+ build: {
345
+ ssr: routesFile,
346
+ outDir: ctx.path.resolve(ctx.root, "dist/server"),
347
+ emptyOutDir: false,
348
+ rollupOptions: {
349
+ output: { entryFileNames: "_routes.mjs" }
350
+ }
351
+ },
352
+ resolve: ctx.resolvedResolve
353
+ });
354
+ const routesPath = pathToFileURL(
355
+ ctx.path.resolve(ctx.root, "dist/server/_routes.mjs")
356
+ ).href;
357
+ const routesMod = await import(
186
358
  /* @vite-ignore */
187
- "path"
359
+ routesPath
188
360
  );
189
- return readFileSync(resolve(root, "dist/client/index.html"), "utf-8");
190
- }
191
- async function loadSSRModule() {
192
- if (!isProduction && vite) {
193
- return await vite.ssrLoadModule(ssrEntryPath);
194
- }
195
- if (ssrProductionModule) {
196
- return import(ssrProductionModule);
361
+ const routes = routesMod.routes ?? routesMod.default;
362
+ if (Array.isArray(routes)) {
363
+ for (const r of routes) {
364
+ if (r.path && !r.path.includes(":")) {
365
+ paths.push(r.path);
366
+ }
367
+ }
197
368
  }
198
- const { resolve } = await import(
199
- /* @vite-ignore */
200
- "path"
201
- );
202
- const { pathToFileURL } = await import(
203
- /* @vite-ignore */
204
- "url"
369
+ ctx.fs.rmSync(ctx.path.resolve(ctx.root, "dist/server/_routes.mjs"), {
370
+ force: true
371
+ });
372
+ } catch (e) {
373
+ console.warn(
374
+ ` [static] Could not load routes from "${routesFile}". Using "/" only.`,
375
+ e
205
376
  );
206
- const absPath = pathToFileURL(resolve(root, "dist/server/ssr.js")).href;
207
- return import(absPath);
377
+ if (paths.length === 0) paths.push("/");
208
378
  }
209
- app.get("*", async (c) => {
210
- const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
211
- try {
212
- const template = await readTemplate(url);
213
- const { render, serializeServerData: serializeServerData2 } = await loadSSRModule();
214
- const locale = parseAcceptLanguage(
215
- c.req.header("accept-language"),
216
- supportedLocales,
217
- defaultLocale
218
- );
219
- const {
220
- html: appHtml,
221
- head,
222
- css,
223
- serverData
224
- } = await render(url, locale);
225
- const serializedData = serializeServerData2(serverData);
226
- const finalHtml = injectSSRContent({
227
- template,
228
- locale,
229
- head,
230
- css,
231
- html: appHtml,
232
- serializedData
379
+ if (opts.dynamicRoutes) {
380
+ for (const r of opts.dynamicRoutes) {
381
+ if (!paths.includes(r)) paths.push(r);
382
+ }
383
+ }
384
+ if (paths.length === 0) paths.push("/");
385
+ return paths;
386
+ }
387
+ function inferLocale(url, locales, defaultLocale) {
388
+ const segments = url.split("/").filter(Boolean);
389
+ if (segments.length > 0 && locales.includes(segments[0])) {
390
+ return segments[0];
391
+ }
392
+ return defaultLocale;
393
+ }
394
+ function injectSSRForStatic(template, locale, head, css, html, serializedData) {
395
+ return template.replace("<!--ssr-lang-->", locale).replace("<!--ssr-head-->", head + "\n<style>" + css + "</style>").replace("<!--ssr-body-->", html).replace(
396
+ "<!--ssr-data-->",
397
+ '<script id="serialized-server-data" type="application/json">' + serializedData + "</script>"
398
+ );
399
+ }
400
+
401
+ // ../server/src/adapters/vercel.ts
402
+ function vercelAdapter() {
403
+ return {
404
+ name: "vercel",
405
+ async build(ctx) {
406
+ const { fs, path, root } = ctx;
407
+ const outputDir = path.resolve(root, ".vercel/output");
408
+ fs.rmSync(outputDir, { recursive: true, force: true });
409
+ const entrySource = generateSSREntry(ctx, {
410
+ platformImport: `import { handle } from "hono/vercel";`,
411
+ platformExport: `export default handle(app);`
233
412
  });
234
- return c.html(finalHtml);
235
- } catch (e) {
236
- if (!isProduction && vite) {
237
- vite.ssrFixStacktrace(e);
413
+ const tempEntry = path.resolve(root, ".vercel-entry.tmp.mjs");
414
+ fs.writeFileSync(tempEntry, entrySource);
415
+ try {
416
+ const funcDir = path.resolve(
417
+ root,
418
+ ".vercel/output/functions/ssr.func"
419
+ );
420
+ await buildBundle(ctx, {
421
+ entry: ".vercel-entry.tmp.mjs",
422
+ outDir: funcDir,
423
+ target: "node18"
424
+ });
425
+ fs.writeFileSync(
426
+ path.resolve(funcDir, ".vc-config.json"),
427
+ JSON.stringify(
428
+ {
429
+ runtime: "nodejs20.x",
430
+ handler: "index.mjs",
431
+ launcherType: "Nodejs"
432
+ },
433
+ null,
434
+ 2
435
+ )
436
+ );
437
+ copyStaticAssets(
438
+ ctx,
439
+ path.resolve(root, ".vercel/output/static")
440
+ );
441
+ fs.writeFileSync(
442
+ path.resolve(root, ".vercel/output/config.json"),
443
+ JSON.stringify(
444
+ {
445
+ version: 3,
446
+ routes: [
447
+ { handle: "filesystem" },
448
+ { src: "/(.*)", dest: "/ssr" }
449
+ ]
450
+ },
451
+ null,
452
+ 2
453
+ )
454
+ );
455
+ } finally {
456
+ fs.rmSync(tempEntry, { force: true });
238
457
  }
239
- console.error("[SSR Error]", e);
240
- return c.text("Internal Server Error", 500);
458
+ console.log(" Vercel output \u2192 .vercel/output/\n");
241
459
  }
242
- });
243
- return app;
460
+ };
461
+ }
462
+
463
+ // ../server/src/adapters/resolve.ts
464
+ function resolveAdapter(value) {
465
+ if (typeof value !== "string") return value;
466
+ switch (value) {
467
+ case "vercel":
468
+ return vercelAdapter();
469
+ case "cloudflare":
470
+ return cloudflareAdapter();
471
+ case "netlify":
472
+ return netlifyAdapter();
473
+ case "node":
474
+ return nodeAdapter();
475
+ case "static":
476
+ return staticAdapter();
477
+ case "auto":
478
+ return autoAdapter();
479
+ default:
480
+ throw new Error(
481
+ `[finesoft] Unknown adapter: "${value}". Available: vercel, cloudflare, netlify, node, static, auto`
482
+ );
483
+ }
484
+ }
485
+
486
+ // ../server/src/adapters/auto.ts
487
+ function autoAdapter() {
488
+ return {
489
+ name: "auto",
490
+ async build(ctx) {
491
+ const detected = detectPlatform();
492
+ console.log(` [auto] Detected platform: ${detected}
493
+ `);
494
+ const adapter = resolveAdapter(detected);
495
+ return adapter.build(ctx);
496
+ }
497
+ };
498
+ }
499
+ function detectPlatform() {
500
+ if (process.env.VERCEL) return "vercel";
501
+ if (process.env.CF_PAGES) return "cloudflare";
502
+ if (process.env.NETLIFY) return "netlify";
503
+ return "node";
244
504
  }
245
505
 
246
506
  // ../server/src/create-server.ts
247
- import { Hono as Hono3 } from "hono";
507
+ import { Hono as Hono2 } from "hono";
248
508
 
249
509
  // ../server/src/runtime.ts
250
510
  function detectRuntime() {
@@ -280,7 +540,7 @@ async function resolveRoot(importMetaUrl, levelsUp = 0) {
280
540
  }
281
541
 
282
542
  // ../server/src/start.ts
283
- import { Hono as Hono2 } from "hono";
543
+ import { Hono } from "hono";
284
544
  async function startServer(options) {
285
545
  const {
286
546
  app,
@@ -362,7 +622,7 @@ async function startServer(options) {
362
622
  /* @vite-ignore */
363
623
  "path"
364
624
  );
365
- const prodApp = new Hono2();
625
+ const prodApp = new Hono();
366
626
  const clientDir = resolve(root, "dist/client");
367
627
  prodApp.use(
368
628
  "/*",
@@ -427,7 +687,7 @@ async function createServer(config = {}) {
427
687
  appType: "custom"
428
688
  });
429
689
  }
430
- const app = new Hono3();
690
+ const app = new Hono2();
431
691
  if (setup) {
432
692
  await setup(app);
433
693
  }
@@ -452,6 +712,251 @@ async function createServer(config = {}) {
452
712
  });
453
713
  return { app, vite, runtime };
454
714
  }
715
+
716
+ // ../server/src/vite-plugin.ts
717
+ function resolveSetupFn(mod) {
718
+ if (typeof mod.default === "function") return mod.default;
719
+ if (typeof mod.setup === "function") return mod.setup;
720
+ const first = Object.values(mod).find((v) => typeof v === "function");
721
+ return first ?? null;
722
+ }
723
+ function finesoftFrontViteConfig(options = {}) {
724
+ const ssrEntry = options.ssr?.entry ?? "src/ssr.ts";
725
+ let root = process.cwd();
726
+ let resolvedCommand;
727
+ let resolvedResolve;
728
+ let resolvedCss;
729
+ return {
730
+ name: "finesoft-front",
731
+ config(userConfig, env) {
732
+ const overrides = {
733
+ appType: "custom"
734
+ };
735
+ if (env.command === "build" && !process.env.__FINESOFT_SUB_BUILD__) {
736
+ overrides.build = {
737
+ outDir: userConfig.build?.outDir ?? "dist/client"
738
+ };
739
+ }
740
+ return overrides;
741
+ },
742
+ configResolved(config) {
743
+ resolvedCommand = config.command;
744
+ resolvedResolve = config.resolve;
745
+ resolvedCss = config.css;
746
+ root = config.root;
747
+ },
748
+ // ─── Dev ───────────────────────────────────────────────
749
+ configureServer(server) {
750
+ return async () => {
751
+ const { Hono: HonoClass } = await import(
752
+ /* @vite-ignore */
753
+ "hono"
754
+ );
755
+ const { createSSRApp: createSSRApp2 } = await import("./app-MYBG3TGV.js");
756
+ const { getRequestListener } = await import(
757
+ /* @vite-ignore */
758
+ "@hono/node-server"
759
+ );
760
+ const app = new HonoClass();
761
+ if (typeof options.setup === "function") {
762
+ await options.setup(app);
763
+ } else if (typeof options.setup === "string") {
764
+ const mod = await server.ssrLoadModule("/" + options.setup);
765
+ const fn = resolveSetupFn(mod);
766
+ if (fn) await fn(app);
767
+ }
768
+ const ssrApp = createSSRApp2({
769
+ root,
770
+ vite: server,
771
+ isProduction: false,
772
+ ssrEntryPath: "/" + ssrEntry,
773
+ supportedLocales: options.locales,
774
+ defaultLocale: options.defaultLocale
775
+ });
776
+ app.route("/", ssrApp);
777
+ const listener = getRequestListener(app.fetch);
778
+ server.middlewares.use((req, res) => {
779
+ listener(req, res);
780
+ });
781
+ };
782
+ },
783
+ // ─── Preview ───────────────────────────────────────────
784
+ configurePreviewServer(server) {
785
+ return async () => {
786
+ const { readFileSync } = await import(
787
+ /* @vite-ignore */
788
+ "fs"
789
+ );
790
+ const { resolve } = await import(
791
+ /* @vite-ignore */
792
+ "path"
793
+ );
794
+ const { pathToFileURL } = await import(
795
+ /* @vite-ignore */
796
+ "url"
797
+ );
798
+ const { Hono: HonoClass } = await import(
799
+ /* @vite-ignore */
800
+ "hono"
801
+ );
802
+ const { injectSSRContent: injectSSRContent2 } = await import(
803
+ /* @vite-ignore */
804
+ "./src-7D236CLJ.js"
805
+ );
806
+ const { parseAcceptLanguage: parseAcceptLanguage2 } = await import("./locale-YK3THSI6.js");
807
+ const { getRequestListener } = await import(
808
+ /* @vite-ignore */
809
+ "@hono/node-server"
810
+ );
811
+ const app = new HonoClass();
812
+ if (typeof options.setup === "function") {
813
+ await options.setup(app);
814
+ } else if (typeof options.setup === "string") {
815
+ try {
816
+ const setupPath = pathToFileURL(
817
+ resolve(root, "dist/server/setup.mjs")
818
+ ).href;
819
+ const mod = await import(
820
+ /* @vite-ignore */
821
+ setupPath
822
+ );
823
+ const fn = resolveSetupFn(
824
+ mod
825
+ );
826
+ if (fn) await fn(app);
827
+ } catch {
828
+ console.warn(
829
+ "[finesoft] Could not load setup module for preview. API routes disabled."
830
+ );
831
+ }
832
+ }
833
+ const templatePath = resolve(root, "dist/client/index.html");
834
+ const template = readFileSync(templatePath, "utf-8");
835
+ const ssrPath = pathToFileURL(
836
+ resolve(root, "dist/server/ssr.js")
837
+ ).href;
838
+ const ssrModule = await import(
839
+ /* @vite-ignore */
840
+ ssrPath
841
+ );
842
+ app.get("*", async (c) => {
843
+ const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
844
+ try {
845
+ const locale = parseAcceptLanguage2(
846
+ c.req.header("accept-language"),
847
+ options.locales,
848
+ options.defaultLocale
849
+ );
850
+ const {
851
+ html: appHtml,
852
+ head,
853
+ css,
854
+ serverData
855
+ } = await ssrModule.render(url, locale);
856
+ const serializedData = ssrModule.serializeServerData(serverData);
857
+ const finalHtml = injectSSRContent2({
858
+ template,
859
+ locale,
860
+ head,
861
+ css,
862
+ html: appHtml,
863
+ serializedData
864
+ });
865
+ return c.html(finalHtml);
866
+ } catch (e) {
867
+ console.error("[SSR Preview Error]", e);
868
+ return c.text("Internal Server Error", 500);
869
+ }
870
+ });
871
+ const listener = getRequestListener(app.fetch);
872
+ server.middlewares.use((req, res) => {
873
+ listener(req, res);
874
+ });
875
+ };
876
+ },
877
+ // ─── Build ─────────────────────────────────────────────
878
+ async closeBundle() {
879
+ if (process.env.__FINESOFT_SUB_BUILD__) return;
880
+ if (resolvedCommand !== "build") return;
881
+ process.env.__FINESOFT_SUB_BUILD__ = "1";
882
+ try {
883
+ const vite = await import(
884
+ /* @vite-ignore */
885
+ "vite"
886
+ );
887
+ const fs = await import(
888
+ /* @vite-ignore */
889
+ "fs"
890
+ );
891
+ const path = await import(
892
+ /* @vite-ignore */
893
+ "path"
894
+ );
895
+ console.log("\n Building SSR bundle...\n");
896
+ await vite.build({
897
+ root,
898
+ build: {
899
+ ssr: ssrEntry,
900
+ outDir: "dist/server"
901
+ },
902
+ resolve: resolvedResolve,
903
+ css: resolvedCss
904
+ });
905
+ if (typeof options.setup === "string") {
906
+ console.log(" Building setup module...\n");
907
+ await vite.build({
908
+ root,
909
+ build: {
910
+ ssr: options.setup,
911
+ outDir: "dist/server",
912
+ emptyOutDir: false,
913
+ rollupOptions: {
914
+ output: { entryFileNames: "setup.mjs" }
915
+ }
916
+ },
917
+ resolve: resolvedResolve
918
+ });
919
+ }
920
+ if (options.adapter) {
921
+ const adapter = resolveAdapter(options.adapter);
922
+ const locales = options.locales ?? ["zh", "en"];
923
+ const defaultLocale = options.defaultLocale ?? locales[0] ?? "en";
924
+ const templateHtml = fs.readFileSync(
925
+ path.resolve(root, "dist/client/index.html"),
926
+ "utf-8"
927
+ );
928
+ const ctx = {
929
+ root,
930
+ ssrEntry,
931
+ setupPath: typeof options.setup === "string" ? options.setup : void 0,
932
+ locales,
933
+ defaultLocale,
934
+ templateHtml,
935
+ resolvedResolve,
936
+ resolvedCss,
937
+ vite,
938
+ fs,
939
+ path,
940
+ generateSSREntry(opts) {
941
+ return generateSSREntry(ctx, opts);
942
+ },
943
+ buildBundle(opts) {
944
+ return buildBundle(ctx, opts);
945
+ },
946
+ copyStaticAssets(destDir, opts) {
947
+ return copyStaticAssets(ctx, destDir, opts);
948
+ }
949
+ };
950
+ console.log(` Running adapter: ${adapter.name}...
951
+ `);
952
+ await adapter.build(ctx);
953
+ }
954
+ } finally {
955
+ delete process.env.__FINESOFT_SUB_BUILD__;
956
+ }
957
+ }
958
+ };
959
+ }
455
960
  export {
456
961
  ACTION_KINDS,
457
962
  ActionDispatcher,
@@ -472,7 +977,9 @@ export {
472
977
  PrefetchedIntents,
473
978
  Router,
474
979
  SSR_PLACEHOLDERS,
980
+ autoAdapter,
475
981
  buildUrl,
982
+ cloudflareAdapter,
476
983
  createPrefetchedIntentsFromDom,
477
984
  createSSRApp,
478
985
  createSSRRender,
@@ -480,6 +987,7 @@ export {
480
987
  defineRoutes,
481
988
  deserializeServerData,
482
989
  detectRuntime,
990
+ finesoftFrontViteConfig,
483
991
  generateUuid,
484
992
  getBaseUrl,
485
993
  injectSSRContent,
@@ -492,6 +1000,8 @@ export {
492
1000
  makeExternalUrlAction,
493
1001
  makeFlowAction,
494
1002
  mapEach,
1003
+ netlifyAdapter,
1004
+ nodeAdapter,
495
1005
  parseAcceptLanguage,
496
1006
  pipe,
497
1007
  pipeAsync,
@@ -502,6 +1012,7 @@ export {
502
1012
  removeQueryParams,
503
1013
  removeScheme,
504
1014
  resetFilterCache,
1015
+ resolveAdapter,
505
1016
  resolveRoot,
506
1017
  serializeServerData,
507
1018
  shouldLog,
@@ -509,6 +1020,8 @@ export {
509
1020
  stableStringify,
510
1021
  startBrowserApp,
511
1022
  startServer,
512
- tryScroll
1023
+ staticAdapter,
1024
+ tryScroll,
1025
+ vercelAdapter
513
1026
  };
514
1027
  //# sourceMappingURL=index.js.map