@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.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,75 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- ACTION_KINDS: () => ACTION_KINDS,
34
- ActionDispatcher: () => ActionDispatcher,
35
- BaseController: () => BaseController,
36
- BaseLogger: () => BaseLogger,
37
- CompositeLogger: () => CompositeLogger,
38
- CompositeLoggerFactory: () => CompositeLoggerFactory,
39
- ConsoleLogger: () => ConsoleLogger,
40
- ConsoleLoggerFactory: () => ConsoleLoggerFactory,
41
- Container: () => Container,
42
- DEP_KEYS: () => DEP_KEYS,
43
- Framework: () => Framework,
44
- History: () => History,
45
- HttpClient: () => HttpClient,
46
- HttpError: () => HttpError,
47
- IntentDispatcher: () => IntentDispatcher,
48
- LruMap: () => LruMap,
49
- PrefetchedIntents: () => PrefetchedIntents,
50
- Router: () => Router,
51
- SSR_PLACEHOLDERS: () => SSR_PLACEHOLDERS,
52
- buildUrl: () => buildUrl,
53
- createPrefetchedIntentsFromDom: () => createPrefetchedIntentsFromDom,
54
- createSSRApp: () => createSSRApp,
55
- createSSRRender: () => createSSRRender,
56
- createServer: () => createServer,
57
- defineRoutes: () => defineRoutes,
58
- deserializeServerData: () => deserializeServerData,
59
- detectRuntime: () => detectRuntime,
60
- generateUuid: () => generateUuid,
61
- getBaseUrl: () => getBaseUrl,
62
- injectSSRContent: () => injectSSRContent,
63
- isCompoundAction: () => isCompoundAction,
64
- isExternalUrlAction: () => isExternalUrlAction,
65
- isFlowAction: () => isFlowAction,
66
- isNone: () => isNone,
67
- isSome: () => isSome,
68
- makeDependencies: () => makeDependencies,
69
- makeExternalUrlAction: () => makeExternalUrlAction,
70
- makeFlowAction: () => makeFlowAction,
71
- mapEach: () => mapEach,
72
- parseAcceptLanguage: () => parseAcceptLanguage,
73
- pipe: () => pipe,
74
- pipeAsync: () => pipeAsync,
75
- registerActionHandlers: () => registerActionHandlers,
76
- registerExternalUrlHandler: () => registerExternalUrlHandler,
77
- registerFlowActionHandler: () => registerFlowActionHandler,
78
- removeHost: () => removeHost,
79
- removeQueryParams: () => removeQueryParams,
80
- removeScheme: () => removeScheme,
81
- resetFilterCache: () => resetFilterCache,
82
- resolveRoot: () => resolveRoot,
83
- serializeServerData: () => serializeServerData,
84
- shouldLog: () => shouldLog,
85
- ssrRender: () => ssrRender,
86
- stableStringify: () => stableStringify,
87
- startBrowserApp: () => startBrowserApp,
88
- startServer: () => startServer,
89
- tryScroll: () => tryScroll
90
- });
91
- module.exports = __toCommonJS(index_exports);
92
-
93
33
  // ../core/src/actions/types.ts
94
- var ACTION_KINDS = {
95
- FLOW: "flow",
96
- EXTERNAL_URL: "externalUrl",
97
- COMPOUND: "compound"
98
- };
99
34
  function isFlowAction(action) {
100
35
  return action.kind === ACTION_KINDS.FLOW;
101
36
  }
@@ -111,119 +46,144 @@ function makeFlowAction(url, presentationContext) {
111
46
  function makeExternalUrlAction(url) {
112
47
  return { kind: ACTION_KINDS.EXTERNAL_URL, url };
113
48
  }
49
+ var ACTION_KINDS;
50
+ var init_types = __esm({
51
+ "../core/src/actions/types.ts"() {
52
+ "use strict";
53
+ ACTION_KINDS = {
54
+ FLOW: "flow",
55
+ EXTERNAL_URL: "externalUrl",
56
+ COMPOUND: "compound"
57
+ };
58
+ }
59
+ });
114
60
 
115
61
  // ../core/src/actions/dispatcher.ts
116
- var ActionDispatcher = class {
117
- handlers = /* @__PURE__ */ new Map();
118
- wiredActions = /* @__PURE__ */ new Set();
119
- /** 注册指定 kind 的 handler(防止重复注册) */
120
- onAction(kind, handler) {
121
- if (this.wiredActions.has(kind)) {
122
- console.warn(
123
- `[ActionDispatcher] kind="${kind}" already registered, skipping`
124
- );
125
- return;
126
- }
127
- this.wiredActions.add(kind);
128
- this.handlers.set(kind, handler);
129
- }
130
- /** 执行一个 Action(CompoundAction 递归展开) */
131
- async perform(action) {
132
- if (isCompoundAction(action)) {
133
- for (const subAction of action.actions) {
134
- await this.perform(subAction);
62
+ var ActionDispatcher;
63
+ var init_dispatcher = __esm({
64
+ "../core/src/actions/dispatcher.ts"() {
65
+ "use strict";
66
+ init_types();
67
+ ActionDispatcher = class {
68
+ handlers = /* @__PURE__ */ new Map();
69
+ wiredActions = /* @__PURE__ */ new Set();
70
+ /** 注册指定 kind 的 handler(防止重复注册) */
71
+ onAction(kind, handler) {
72
+ if (this.wiredActions.has(kind)) {
73
+ console.warn(
74
+ `[ActionDispatcher] kind="${kind}" already registered, skipping`
75
+ );
76
+ return;
77
+ }
78
+ this.wiredActions.add(kind);
79
+ this.handlers.set(kind, handler);
135
80
  }
136
- return;
137
- }
138
- const handler = this.handlers.get(action.kind);
139
- if (!handler) {
140
- console.warn(
141
- `[ActionDispatcher] No handler for kind="${action.kind}"`
142
- );
143
- return;
144
- }
145
- await handler(action);
81
+ /** 执行一个 Action(CompoundAction 递归展开) */
82
+ async perform(action) {
83
+ if (isCompoundAction(action)) {
84
+ for (const subAction of action.actions) {
85
+ await this.perform(subAction);
86
+ }
87
+ return;
88
+ }
89
+ const handler = this.handlers.get(action.kind);
90
+ if (!handler) {
91
+ console.warn(
92
+ `[ActionDispatcher] No handler for kind="${action.kind}"`
93
+ );
94
+ return;
95
+ }
96
+ await handler(action);
97
+ }
98
+ };
146
99
  }
147
- };
100
+ });
148
101
 
149
102
  // ../core/src/intents/dispatcher.ts
150
- var IntentDispatcher = class {
151
- controllers = /* @__PURE__ */ new Map();
152
- /** 注册一个 IntentController */
153
- register(controller) {
154
- this.controllers.set(controller.intentId, controller);
155
- }
156
- /** 分发 Intent 到对应 Controller */
157
- async dispatch(intent, container) {
158
- const controller = this.controllers.get(intent.id);
159
- if (!controller) {
160
- throw new Error(
161
- `[IntentDispatcher] No controller for "${intent.id}". Registered: [${Array.from(this.controllers.keys()).join(", ")}]`
162
- );
163
- }
164
- return controller.perform(intent, container);
165
- }
166
- /** 检查是否已注册某个 Intent */
167
- has(intentId) {
168
- return this.controllers.has(intentId);
103
+ var IntentDispatcher;
104
+ var init_dispatcher2 = __esm({
105
+ "../core/src/intents/dispatcher.ts"() {
106
+ "use strict";
107
+ IntentDispatcher = class {
108
+ controllers = /* @__PURE__ */ new Map();
109
+ /** 注册一个 IntentController */
110
+ register(controller) {
111
+ this.controllers.set(controller.intentId, controller);
112
+ }
113
+ /** 分发 Intent 到对应 Controller */
114
+ async dispatch(intent, container) {
115
+ const controller = this.controllers.get(intent.id);
116
+ if (!controller) {
117
+ throw new Error(
118
+ `[IntentDispatcher] No controller for "${intent.id}". Registered: [${Array.from(this.controllers.keys()).join(", ")}]`
119
+ );
120
+ }
121
+ return controller.perform(intent, container);
122
+ }
123
+ /** 检查是否已注册某个 Intent */
124
+ has(intentId) {
125
+ return this.controllers.has(intentId);
126
+ }
127
+ };
169
128
  }
170
- };
129
+ });
171
130
 
172
131
  // ../core/src/dependencies/container.ts
173
- var Container = class {
174
- registrations = /* @__PURE__ */ new Map();
175
- /** 注册依赖(默认单例) */
176
- register(key, factory, singleton = true) {
177
- this.registrations.set(key, { factory, singleton });
178
- return this;
179
- }
180
- /** 解析依赖 */
181
- resolve(key) {
182
- const reg = this.registrations.get(key);
183
- if (!reg) {
184
- throw new Error(`[Container] No registration for key: "${key}"`);
185
- }
186
- if (reg.singleton) {
187
- if (reg.instance === void 0) {
188
- reg.instance = reg.factory();
132
+ var Container;
133
+ var init_container = __esm({
134
+ "../core/src/dependencies/container.ts"() {
135
+ "use strict";
136
+ Container = class {
137
+ registrations = /* @__PURE__ */ new Map();
138
+ /** 注册依赖(默认单例) */
139
+ register(key, factory, singleton = true) {
140
+ this.registrations.set(key, { factory, singleton });
141
+ return this;
189
142
  }
190
- return reg.instance;
191
- }
192
- return reg.factory();
193
- }
194
- /** 检查是否已注册 */
195
- has(key) {
196
- return this.registrations.has(key);
197
- }
198
- /** 销毁容器,清除所有缓存 */
199
- dispose() {
200
- for (const reg of this.registrations.values()) {
201
- reg.instance = void 0;
202
- }
203
- this.registrations.clear();
143
+ /** 解析依赖 */
144
+ resolve(key) {
145
+ const reg = this.registrations.get(key);
146
+ if (!reg) {
147
+ throw new Error(`[Container] No registration for key: "${key}"`);
148
+ }
149
+ if (reg.singleton) {
150
+ if (reg.instance === void 0) {
151
+ reg.instance = reg.factory();
152
+ }
153
+ return reg.instance;
154
+ }
155
+ return reg.factory();
156
+ }
157
+ /** 检查是否已注册 */
158
+ has(key) {
159
+ return this.registrations.has(key);
160
+ }
161
+ /** 销毁容器,清除所有缓存 */
162
+ dispose() {
163
+ for (const reg of this.registrations.values()) {
164
+ reg.instance = void 0;
165
+ }
166
+ this.registrations.clear();
167
+ }
168
+ };
204
169
  }
205
- };
170
+ });
206
171
 
207
172
  // ../core/src/logger/base.ts
208
- var BaseLogger = class {
209
- category;
210
- constructor(category) {
211
- this.category = category;
173
+ var BaseLogger;
174
+ var init_base = __esm({
175
+ "../core/src/logger/base.ts"() {
176
+ "use strict";
177
+ BaseLogger = class {
178
+ category;
179
+ constructor(category) {
180
+ this.category = category;
181
+ }
182
+ };
212
183
  }
213
- };
184
+ });
214
185
 
215
186
  // ../core/src/logger/local-storage-filter.ts
216
- var LEVEL_TO_NUM = {
217
- "*": 4,
218
- debug: 4,
219
- info: 3,
220
- warn: 2,
221
- error: 1,
222
- off: 0,
223
- "": 0
224
- };
225
- var cachedRules;
226
- var cachedRaw;
227
187
  function parseRules() {
228
188
  if (typeof globalThis.localStorage === "undefined") {
229
189
  return {};
@@ -272,94 +232,62 @@ function resetFilterCache() {
272
232
  cachedRules = void 0;
273
233
  cachedRaw = void 0;
274
234
  }
235
+ var LEVEL_TO_NUM, cachedRules, cachedRaw;
236
+ var init_local_storage_filter = __esm({
237
+ "../core/src/logger/local-storage-filter.ts"() {
238
+ "use strict";
239
+ LEVEL_TO_NUM = {
240
+ "*": 4,
241
+ debug: 4,
242
+ info: 3,
243
+ warn: 2,
244
+ error: 1,
245
+ off: 0,
246
+ "": 0
247
+ };
248
+ }
249
+ });
275
250
 
276
251
  // ../core/src/logger/console.ts
277
- var ConsoleLogger = class extends BaseLogger {
278
- debug(...args) {
279
- if (shouldLog(this.category, "debug")) {
280
- console.debug(`[${this.category}]`, ...args);
281
- }
282
- return "";
283
- }
284
- info(...args) {
285
- if (shouldLog(this.category, "info")) {
286
- console.info(`[${this.category}]`, ...args);
287
- }
288
- return "";
289
- }
290
- warn(...args) {
291
- if (shouldLog(this.category, "warn")) {
292
- console.warn(`[${this.category}]`, ...args);
293
- }
294
- return "";
295
- }
296
- error(...args) {
297
- console.error(`[${this.category}]`, ...args);
298
- return "";
299
- }
300
- };
301
- var ConsoleLoggerFactory = class {
302
- loggerFor(category) {
303
- return new ConsoleLogger(category);
252
+ var ConsoleLogger, ConsoleLoggerFactory;
253
+ var init_console = __esm({
254
+ "../core/src/logger/console.ts"() {
255
+ "use strict";
256
+ init_base();
257
+ init_local_storage_filter();
258
+ ConsoleLogger = class extends BaseLogger {
259
+ debug(...args) {
260
+ if (shouldLog(this.category, "debug")) {
261
+ console.debug(`[${this.category}]`, ...args);
262
+ }
263
+ return "";
264
+ }
265
+ info(...args) {
266
+ if (shouldLog(this.category, "info")) {
267
+ console.info(`[${this.category}]`, ...args);
268
+ }
269
+ return "";
270
+ }
271
+ warn(...args) {
272
+ if (shouldLog(this.category, "warn")) {
273
+ console.warn(`[${this.category}]`, ...args);
274
+ }
275
+ return "";
276
+ }
277
+ error(...args) {
278
+ console.error(`[${this.category}]`, ...args);
279
+ return "";
280
+ }
281
+ };
282
+ ConsoleLoggerFactory = class {
283
+ loggerFor(category) {
284
+ return new ConsoleLogger(category);
285
+ }
286
+ };
304
287
  }
305
- };
288
+ });
306
289
 
307
290
  // ../core/src/dependencies/make-dependencies.ts
308
- var DEP_KEYS = {
309
- LOGGER: "logger",
310
- LOGGER_FACTORY: "loggerFactory",
311
- NET: "net",
312
- LOCALE: "locale",
313
- STORAGE: "storage",
314
- FEATURE_FLAGS: "featureFlags",
315
- METRICS: "metrics",
316
- FETCH: "fetch"
317
- };
318
- var DefaultLocale = class {
319
- language = "en";
320
- storefront = "us";
321
- setActiveLocale(language, storefront) {
322
- this.language = language;
323
- this.storefront = storefront;
324
- }
325
- };
326
- var MemoryStorage = class {
327
- store = /* @__PURE__ */ new Map();
328
- get(key) {
329
- return this.store.get(key);
330
- }
331
- set(key, value) {
332
- this.store.set(key, value);
333
- }
334
- delete(key) {
335
- this.store.delete(key);
336
- }
337
- };
338
- var DefaultFeatureFlags = class {
339
- flags;
340
- constructor(flags = {}) {
341
- this.flags = flags;
342
- }
343
- isEnabled(key) {
344
- return this.flags[key] === true;
345
- }
346
- getString(key) {
347
- const v = this.flags[key];
348
- return typeof v === "string" ? v : void 0;
349
- }
350
- getNumber(key) {
351
- const v = this.flags[key];
352
- return typeof v === "number" ? v : void 0;
353
- }
354
- };
355
- var ConsoleMetrics = class {
356
- recordPageView(page, fields) {
357
- console.info(`[Metrics:PageView] ${page}`, fields ?? "");
358
- }
359
- recordEvent(name, fields) {
360
- console.info(`[Metrics:Event] ${name}`, fields ?? "");
361
- }
362
- };
363
291
  function makeDependencies(container, options = {}) {
364
292
  const {
365
293
  fetch: fetchFn = globalThis.fetch?.bind(globalThis),
@@ -395,111 +323,186 @@ function makeDependencies(container, options = {}) {
395
323
  );
396
324
  container.register(DEP_KEYS.FETCH, () => fetchFn);
397
325
  }
326
+ var DEP_KEYS, DefaultLocale, MemoryStorage, DefaultFeatureFlags, ConsoleMetrics;
327
+ var init_make_dependencies = __esm({
328
+ "../core/src/dependencies/make-dependencies.ts"() {
329
+ "use strict";
330
+ init_console();
331
+ DEP_KEYS = {
332
+ LOGGER: "logger",
333
+ LOGGER_FACTORY: "loggerFactory",
334
+ NET: "net",
335
+ LOCALE: "locale",
336
+ STORAGE: "storage",
337
+ FEATURE_FLAGS: "featureFlags",
338
+ METRICS: "metrics",
339
+ FETCH: "fetch"
340
+ };
341
+ DefaultLocale = class {
342
+ language = "en";
343
+ storefront = "us";
344
+ setActiveLocale(language, storefront) {
345
+ this.language = language;
346
+ this.storefront = storefront;
347
+ }
348
+ };
349
+ MemoryStorage = class {
350
+ store = /* @__PURE__ */ new Map();
351
+ get(key) {
352
+ return this.store.get(key);
353
+ }
354
+ set(key, value) {
355
+ this.store.set(key, value);
356
+ }
357
+ delete(key) {
358
+ this.store.delete(key);
359
+ }
360
+ };
361
+ DefaultFeatureFlags = class {
362
+ flags;
363
+ constructor(flags = {}) {
364
+ this.flags = flags;
365
+ }
366
+ isEnabled(key) {
367
+ return this.flags[key] === true;
368
+ }
369
+ getString(key) {
370
+ const v = this.flags[key];
371
+ return typeof v === "string" ? v : void 0;
372
+ }
373
+ getNumber(key) {
374
+ const v = this.flags[key];
375
+ return typeof v === "number" ? v : void 0;
376
+ }
377
+ };
378
+ ConsoleMetrics = class {
379
+ recordPageView(page, fields) {
380
+ console.info(`[Metrics:PageView] ${page}`, fields ?? "");
381
+ }
382
+ recordEvent(name, fields) {
383
+ console.info(`[Metrics:Event] ${name}`, fields ?? "");
384
+ }
385
+ };
386
+ }
387
+ });
398
388
 
399
389
  // ../core/src/router/router.ts
400
- var Router = class {
401
- routes = [];
402
- /** 添加路由规则 */
403
- add(pattern, intentId) {
404
- const paramNames = [];
405
- const regexStr = pattern.replace(
406
- /\/:(\w+)(\?)?/g,
407
- (_, name, optional) => {
408
- paramNames.push(name);
409
- return optional ? "(?:/([^/]+))?" : "/([^/]+)";
410
- }
411
- );
412
- this.routes.push({
413
- pattern,
414
- intentId,
415
- regex: new RegExp(`^${regexStr}/?$`),
416
- paramNames
417
- });
418
- return this;
419
- }
420
- /** 解析 URL → RouteMatch */
421
- resolve(urlOrPath) {
422
- const path = this.extractPath(urlOrPath);
423
- const queryParams = this.extractQueryParams(urlOrPath);
424
- for (const route of this.routes) {
425
- const match = path.match(route.regex);
426
- if (match) {
427
- const params = {};
428
- route.paramNames.forEach((name, index) => {
429
- const value = match[index + 1];
430
- if (value) params[name] = value;
390
+ var Router;
391
+ var init_router = __esm({
392
+ "../core/src/router/router.ts"() {
393
+ "use strict";
394
+ init_types();
395
+ Router = class {
396
+ routes = [];
397
+ /** 添加路由规则 */
398
+ add(pattern, intentId) {
399
+ const paramNames = [];
400
+ const regexStr = pattern.replace(
401
+ /\/:(\w+)(\?)?/g,
402
+ (_, name, optional) => {
403
+ paramNames.push(name);
404
+ return optional ? "(?:/([^/]+))?" : "/([^/]+)";
405
+ }
406
+ );
407
+ this.routes.push({
408
+ pattern,
409
+ intentId,
410
+ regex: new RegExp(`^${regexStr}/?$`),
411
+ paramNames
431
412
  });
432
- for (const [k, v] of Object.entries(queryParams)) {
433
- if (!(k in params)) params[k] = v;
413
+ return this;
414
+ }
415
+ /** 解析 URL → RouteMatch */
416
+ resolve(urlOrPath) {
417
+ const path = this.extractPath(urlOrPath);
418
+ const queryParams = this.extractQueryParams(urlOrPath);
419
+ for (const route of this.routes) {
420
+ const match = path.match(route.regex);
421
+ if (match) {
422
+ const params = {};
423
+ route.paramNames.forEach((name, index) => {
424
+ const value = match[index + 1];
425
+ if (value) params[name] = value;
426
+ });
427
+ for (const [k, v] of Object.entries(queryParams)) {
428
+ if (!(k in params)) params[k] = v;
429
+ }
430
+ return {
431
+ intent: { id: route.intentId, params },
432
+ action: makeFlowAction(urlOrPath)
433
+ };
434
+ }
434
435
  }
435
- return {
436
- intent: { id: route.intentId, params },
437
- action: makeFlowAction(urlOrPath)
438
- };
436
+ return null;
439
437
  }
440
- }
441
- return null;
442
- }
443
- /** 获取所有已注册的路由 */
444
- getRoutes() {
445
- return this.routes.map((r) => `${r.pattern} \u2192 ${r.intentId}`);
446
- }
447
- extractPath(url) {
448
- try {
449
- const parsed = new URL(url, "http://localhost");
450
- return parsed.pathname;
451
- } catch {
452
- return url.split("?")[0].split("#")[0];
453
- }
454
- }
455
- extractQueryParams(url) {
456
- try {
457
- const parsed = new URL(url, "http://localhost");
458
- const params = {};
459
- parsed.searchParams.forEach((v, k) => {
460
- params[k] = v;
461
- });
462
- return params;
463
- } catch {
464
- return {};
465
- }
438
+ /** 获取所有已注册的路由 */
439
+ getRoutes() {
440
+ return this.routes.map((r) => `${r.pattern} \u2192 ${r.intentId}`);
441
+ }
442
+ extractPath(url) {
443
+ try {
444
+ const parsed = new URL(url, "http://localhost");
445
+ return parsed.pathname;
446
+ } catch {
447
+ return url.split("?")[0].split("#")[0];
448
+ }
449
+ }
450
+ extractQueryParams(url) {
451
+ try {
452
+ const parsed = new URL(url, "http://localhost");
453
+ const params = {};
454
+ parsed.searchParams.forEach((v, k) => {
455
+ params[k] = v;
456
+ });
457
+ return params;
458
+ } catch {
459
+ return {};
460
+ }
461
+ }
462
+ };
466
463
  }
467
- };
464
+ });
468
465
 
469
466
  // ../core/src/logger/composite.ts
470
- var CompositeLoggerFactory = class {
471
- constructor(factories) {
472
- this.factories = factories;
473
- }
474
- loggerFor(name) {
475
- return new CompositeLogger(
476
- this.factories.map((f) => f.loggerFor(name))
477
- );
478
- }
479
- };
480
- var CompositeLogger = class {
481
- constructor(loggers) {
482
- this.loggers = loggers;
483
- }
484
- debug(...args) {
485
- return this.callAll("debug", args);
486
- }
487
- info(...args) {
488
- return this.callAll("info", args);
489
- }
490
- warn(...args) {
491
- return this.callAll("warn", args);
492
- }
493
- error(...args) {
494
- return this.callAll("error", args);
495
- }
496
- callAll(method, args) {
497
- for (const logger of this.loggers) {
498
- logger[method](...args);
499
- }
500
- return "";
467
+ var CompositeLoggerFactory, CompositeLogger;
468
+ var init_composite = __esm({
469
+ "../core/src/logger/composite.ts"() {
470
+ "use strict";
471
+ CompositeLoggerFactory = class {
472
+ constructor(factories) {
473
+ this.factories = factories;
474
+ }
475
+ loggerFor(name) {
476
+ return new CompositeLogger(
477
+ this.factories.map((f) => f.loggerFor(name))
478
+ );
479
+ }
480
+ };
481
+ CompositeLogger = class {
482
+ constructor(loggers) {
483
+ this.loggers = loggers;
484
+ }
485
+ debug(...args) {
486
+ return this.callAll("debug", args);
487
+ }
488
+ info(...args) {
489
+ return this.callAll("info", args);
490
+ }
491
+ warn(...args) {
492
+ return this.callAll("warn", args);
493
+ }
494
+ error(...args) {
495
+ return this.callAll("error", args);
496
+ }
497
+ callAll(method, args) {
498
+ for (const logger of this.loggers) {
499
+ logger[method](...args);
500
+ }
501
+ return "";
502
+ }
503
+ };
501
504
  }
502
- };
505
+ });
503
506
 
504
507
  // ../core/src/prefetched-intents/stable-stringify.ts
505
508
  function stableStringify(obj) {
@@ -514,360 +517,789 @@ function stableStringify(obj) {
514
517
  );
515
518
  return "{" + parts.join(",") + "}";
516
519
  }
520
+ var init_stable_stringify = __esm({
521
+ "../core/src/prefetched-intents/stable-stringify.ts"() {
522
+ "use strict";
523
+ }
524
+ });
517
525
 
518
526
  // ../core/src/prefetched-intents/prefetched-intents.ts
519
- var PrefetchedIntents = class _PrefetchedIntents {
520
- intents;
521
- constructor(intents) {
522
- this.intents = intents;
523
- }
524
- /** PrefetchedIntent 数组创建缓存实例 */
525
- static fromArray(items) {
526
- const map = /* @__PURE__ */ new Map();
527
- for (const item of items) {
528
- if (item.intent && item.data !== void 0) {
529
- const key = stableStringify(item.intent);
530
- map.set(key, item.data);
527
+ var PrefetchedIntents;
528
+ var init_prefetched_intents = __esm({
529
+ "../core/src/prefetched-intents/prefetched-intents.ts"() {
530
+ "use strict";
531
+ init_stable_stringify();
532
+ PrefetchedIntents = class _PrefetchedIntents {
533
+ intents;
534
+ constructor(intents) {
535
+ this.intents = intents;
536
+ }
537
+ /** PrefetchedIntent 数组创建缓存实例 */
538
+ static fromArray(items) {
539
+ const map = /* @__PURE__ */ new Map();
540
+ for (const item of items) {
541
+ if (item.intent && item.data !== void 0) {
542
+ const key = stableStringify(item.intent);
543
+ map.set(key, item.data);
544
+ }
545
+ }
546
+ return new _PrefetchedIntents(map);
547
+ }
548
+ /** 创建空缓存实例 */
549
+ static empty() {
550
+ return new _PrefetchedIntents(/* @__PURE__ */ new Map());
551
+ }
552
+ /**
553
+ * 获取缓存的 Intent 结果(一次性使用)。
554
+ * 命中后从缓存中删除。
555
+ */
556
+ get(intent) {
557
+ const key = stableStringify(intent);
558
+ const data = this.intents.get(key);
559
+ if (data !== void 0) {
560
+ this.intents.delete(key);
561
+ return data;
562
+ }
563
+ return void 0;
564
+ }
565
+ /** 检查缓存中是否有某个 Intent 的数据 */
566
+ has(intent) {
567
+ return this.intents.has(stableStringify(intent));
568
+ }
569
+ /** 缓存中的条目数 */
570
+ get size() {
571
+ return this.intents.size;
572
+ }
573
+ };
574
+ }
575
+ });
576
+
577
+ // ../core/src/framework.ts
578
+ var Framework;
579
+ var init_framework = __esm({
580
+ "../core/src/framework.ts"() {
581
+ "use strict";
582
+ init_dispatcher();
583
+ init_container();
584
+ init_make_dependencies();
585
+ init_dispatcher2();
586
+ init_prefetched_intents();
587
+ init_router();
588
+ Framework = class _Framework {
589
+ container;
590
+ intentDispatcher;
591
+ actionDispatcher;
592
+ router;
593
+ prefetchedIntents;
594
+ constructor(container, prefetchedIntents) {
595
+ this.container = container;
596
+ this.intentDispatcher = new IntentDispatcher();
597
+ this.actionDispatcher = new ActionDispatcher();
598
+ this.router = new Router();
599
+ this.prefetchedIntents = prefetchedIntents;
600
+ }
601
+ /** 创建并初始化 Framework 实例 */
602
+ static create(config = {}) {
603
+ const container = new Container();
604
+ makeDependencies(container, config);
605
+ const fw = new _Framework(
606
+ container,
607
+ config.prefetchedIntents ?? PrefetchedIntents.empty()
608
+ );
609
+ config.setupRoutes?.(fw.router);
610
+ return fw;
611
+ }
612
+ /** 分发 Intent — 获取页面数据 */
613
+ async dispatch(intent) {
614
+ const logger = this.container.resolve(DEP_KEYS.LOGGER);
615
+ const cached = this.prefetchedIntents.get(intent);
616
+ if (cached !== void 0) {
617
+ logger.debug(
618
+ `[Framework] re-using prefetched intent response for: ${intent.id}`,
619
+ intent.params
620
+ );
621
+ return cached;
622
+ }
623
+ logger.debug(
624
+ `[Framework] dispatch intent: ${intent.id}`,
625
+ intent.params
626
+ );
627
+ return this.intentDispatcher.dispatch(intent, this.container);
628
+ }
629
+ /** 执行 Action — 处理用户交互 */
630
+ async perform(action) {
631
+ const logger = this.container.resolve(DEP_KEYS.LOGGER);
632
+ logger.debug(`[Framework] perform action: ${action.kind}`);
633
+ return this.actionDispatcher.perform(action);
634
+ }
635
+ /** 路由 URL — 将 URL 解析为 Intent + Action */
636
+ routeUrl(url) {
637
+ return this.router.resolve(url);
638
+ }
639
+ /** 记录页面访问事件 */
640
+ didEnterPage(page) {
641
+ const metrics = this.container.resolve(
642
+ DEP_KEYS.METRICS
643
+ );
644
+ metrics.recordPageView(page.pageType, {
645
+ pageId: page.id,
646
+ title: page.title
647
+ });
648
+ }
649
+ /** 注册 Action 处理器 */
650
+ onAction(kind, handler) {
651
+ this.actionDispatcher.onAction(kind, handler);
652
+ }
653
+ /** 注册 Intent Controller */
654
+ registerIntent(controller) {
655
+ this.intentDispatcher.register(controller);
656
+ }
657
+ /** 销毁 Framework 实例 */
658
+ dispose() {
659
+ this.container.dispose();
660
+ }
661
+ };
662
+ }
663
+ });
664
+
665
+ // ../core/src/http/client.ts
666
+ var HttpError, HttpClient;
667
+ var init_client = __esm({
668
+ "../core/src/http/client.ts"() {
669
+ "use strict";
670
+ HttpError = class extends Error {
671
+ constructor(status, statusText, body) {
672
+ super(`HTTP ${status}: ${statusText}`);
673
+ this.status = status;
674
+ this.statusText = statusText;
675
+ this.body = body;
676
+ this.name = "HttpError";
677
+ }
678
+ };
679
+ HttpClient = class {
680
+ baseUrl;
681
+ defaultHeaders;
682
+ fetchFn;
683
+ constructor(config) {
684
+ this.baseUrl = config.baseUrl;
685
+ this.defaultHeaders = config.defaultHeaders ?? {};
686
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
687
+ }
688
+ /** GET 请求,返回解析后的 JSON */
689
+ async get(path, params) {
690
+ return this.request("GET", path, { params });
531
691
  }
692
+ /** POST 请求,自动序列化 body 为 JSON */
693
+ async post(path, body, params) {
694
+ return this.request("POST", path, { body, params });
695
+ }
696
+ /** PUT 请求 */
697
+ async put(path, body, params) {
698
+ return this.request("PUT", path, { body, params });
699
+ }
700
+ /** DELETE 请求 */
701
+ async del(path, params) {
702
+ return this.request("DELETE", path, { params });
703
+ }
704
+ /**
705
+ * 底层请求方法 — 子类可覆写以自定义行为
706
+ *
707
+ * 自动处理:
708
+ * - URL 拼接 (baseUrl + path + params)
709
+ * - 默认 headers 合并
710
+ * - JSON body 序列化
711
+ * - 响应 JSON 解析
712
+ * - 非 2xx 状态码抛出 HttpError
713
+ */
714
+ async request(method, path, options) {
715
+ const url = this.buildUrl(path, options?.params);
716
+ const headers = {
717
+ ...this.defaultHeaders,
718
+ ...options?.headers
719
+ };
720
+ const init = { method, headers };
721
+ if (options?.body !== void 0) {
722
+ headers["Content-Type"] = headers["Content-Type"] ?? "application/json";
723
+ init.body = JSON.stringify(options.body);
724
+ }
725
+ const response = await this.fetchFn(url, init);
726
+ if (!response.ok) {
727
+ const body = await response.text().catch(() => void 0);
728
+ throw new HttpError(response.status, response.statusText, body);
729
+ }
730
+ return response.json();
731
+ }
732
+ /** 构建完整 URL — 子类可覆写以自定义 URL 拼接逻辑 */
733
+ buildUrl(path, params) {
734
+ const base = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
735
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
736
+ const url = new URL(`${base}${normalizedPath}`, "http://placeholder");
737
+ if (params) {
738
+ for (const [k, v] of Object.entries(params)) {
739
+ url.searchParams.set(k, v);
740
+ }
741
+ }
742
+ if (this.baseUrl.startsWith("http")) {
743
+ return url.toString();
744
+ }
745
+ return `${url.pathname}${url.search}`;
746
+ }
747
+ };
748
+ }
749
+ });
750
+
751
+ // ../core/src/intents/base-controller.ts
752
+ var BaseController;
753
+ var init_base_controller = __esm({
754
+ "../core/src/intents/base-controller.ts"() {
755
+ "use strict";
756
+ BaseController = class {
757
+ /**
758
+ * 错误回退 — 子类可选覆写
759
+ *
760
+ * 当 execute() 抛出异常时调用。
761
+ * 默认行为: 重新抛出原始错误。
762
+ *
763
+ * @param params - Intent 参数
764
+ * @param error - execute() 抛出的错误
765
+ * @returns 回退数据
766
+ */
767
+ fallback(params, error) {
768
+ throw error;
769
+ }
770
+ /**
771
+ * IntentController.perform() 实现
772
+ *
773
+ * 自动 try/catch → fallback 模式。
774
+ */
775
+ async perform(intent, container) {
776
+ const params = intent.params ?? {};
777
+ try {
778
+ return await this.execute(params, container);
779
+ } catch (e) {
780
+ return this.fallback(
781
+ params,
782
+ e instanceof Error ? e : new Error(String(e))
783
+ );
784
+ }
785
+ }
786
+ };
787
+ }
788
+ });
789
+
790
+ // ../core/src/data/mapper.ts
791
+ function pipe(...mappers) {
792
+ return (input) => mappers.reduce((acc, mapper) => mapper(acc), input);
793
+ }
794
+ function pipeAsync(...mappers) {
795
+ return async (input) => {
796
+ let acc = input;
797
+ for (const mapper of mappers) {
798
+ acc = await mapper(acc);
532
799
  }
533
- return new _PrefetchedIntents(map);
534
- }
535
- /** 创建空缓存实例 */
536
- static empty() {
537
- return new _PrefetchedIntents(/* @__PURE__ */ new Map());
538
- }
539
- /**
540
- * 获取缓存的 Intent 结果(一次性使用)。
541
- * 命中后从缓存中删除。
542
- */
543
- get(intent) {
544
- const key = stableStringify(intent);
545
- const data = this.intents.get(key);
546
- if (data !== void 0) {
547
- this.intents.delete(key);
548
- return data;
800
+ return acc;
801
+ };
802
+ }
803
+ function mapEach(mapper) {
804
+ return (items) => items.map(mapper);
805
+ }
806
+ var init_mapper = __esm({
807
+ "../core/src/data/mapper.ts"() {
808
+ "use strict";
809
+ }
810
+ });
811
+
812
+ // ../core/src/bootstrap/define-routes.ts
813
+ function defineRoutes(framework, definitions) {
814
+ const registeredIntents = /* @__PURE__ */ new Set();
815
+ for (const def of definitions) {
816
+ if (def.controller && !registeredIntents.has(def.intentId)) {
817
+ framework.registerIntent(def.controller);
818
+ registeredIntents.add(def.intentId);
549
819
  }
550
- return void 0;
820
+ framework.router.add(def.path, def.intentId);
551
821
  }
552
- /** 检查缓存中是否有某个 Intent 的数据 */
553
- has(intent) {
554
- return this.intents.has(stableStringify(intent));
822
+ }
823
+ var init_define_routes = __esm({
824
+ "../core/src/bootstrap/define-routes.ts"() {
825
+ "use strict";
555
826
  }
556
- /** 缓存中的条目数 */
557
- get size() {
558
- return this.intents.size;
827
+ });
828
+
829
+ // ../core/src/utils/lru-map.ts
830
+ var LruMap;
831
+ var init_lru_map = __esm({
832
+ "../core/src/utils/lru-map.ts"() {
833
+ "use strict";
834
+ LruMap = class {
835
+ map = /* @__PURE__ */ new Map();
836
+ capacity;
837
+ constructor(capacity) {
838
+ this.capacity = capacity;
839
+ }
840
+ get(key) {
841
+ const value = this.map.get(key);
842
+ if (value !== void 0) {
843
+ this.map.delete(key);
844
+ this.map.set(key, value);
845
+ }
846
+ return value;
847
+ }
848
+ set(key, value) {
849
+ if (this.map.has(key)) {
850
+ this.map.delete(key);
851
+ } else if (this.map.size >= this.capacity) {
852
+ const oldest = this.map.keys().next().value;
853
+ if (oldest !== void 0) {
854
+ this.map.delete(oldest);
855
+ }
856
+ }
857
+ this.map.set(key, value);
858
+ }
859
+ has(key) {
860
+ return this.map.has(key);
861
+ }
862
+ delete(key) {
863
+ return this.map.delete(key);
864
+ }
865
+ get size() {
866
+ return this.map.size;
867
+ }
868
+ clear() {
869
+ this.map.clear();
870
+ }
871
+ };
559
872
  }
560
- };
873
+ });
561
874
 
562
- // ../core/src/framework.ts
563
- var Framework = class _Framework {
564
- container;
565
- intentDispatcher;
566
- actionDispatcher;
567
- router;
568
- prefetchedIntents;
569
- constructor(container, prefetchedIntents) {
570
- this.container = container;
571
- this.intentDispatcher = new IntentDispatcher();
572
- this.actionDispatcher = new ActionDispatcher();
573
- this.router = new Router();
574
- this.prefetchedIntents = prefetchedIntents;
575
- }
576
- /** 创建并初始化 Framework 实例 */
577
- static create(config = {}) {
578
- const container = new Container();
579
- makeDependencies(container, config);
580
- const fw = new _Framework(
581
- container,
582
- config.prefetchedIntents ?? PrefetchedIntents.empty()
583
- );
584
- config.setupRoutes?.(fw.router);
585
- return fw;
586
- }
587
- /** 分发 Intent — 获取页面数据 */
588
- async dispatch(intent) {
589
- const logger = this.container.resolve(DEP_KEYS.LOGGER);
590
- const cached = this.prefetchedIntents.get(intent);
591
- if (cached !== void 0) {
592
- logger.debug(
593
- `[Framework] re-using prefetched intent response for: ${intent.id}`,
594
- intent.params
875
+ // ../core/src/utils/optional.ts
876
+ function isSome(value) {
877
+ return value !== null && value !== void 0;
878
+ }
879
+ function isNone(value) {
880
+ return value === null || value === void 0;
881
+ }
882
+ var init_optional = __esm({
883
+ "../core/src/utils/optional.ts"() {
884
+ "use strict";
885
+ }
886
+ });
887
+
888
+ // ../core/src/utils/url.ts
889
+ function removeScheme(url) {
890
+ return url.replace(/^https?:\/\//, "");
891
+ }
892
+ function removeHost(url) {
893
+ try {
894
+ const parsed = new URL(url);
895
+ return parsed.pathname + parsed.search + parsed.hash;
896
+ } catch {
897
+ return url;
898
+ }
899
+ }
900
+ function removeQueryParams(url) {
901
+ return url.split("?")[0];
902
+ }
903
+ function getBaseUrl(url) {
904
+ return url.split("?")[0].split("#")[0];
905
+ }
906
+ function buildUrl(path, params) {
907
+ if (!params) return path;
908
+ const searchParams = new URLSearchParams();
909
+ for (const [key, value] of Object.entries(params)) {
910
+ if (value !== void 0) {
911
+ searchParams.set(key, value);
912
+ }
913
+ }
914
+ const qs = searchParams.toString();
915
+ return qs ? `${path}?${qs}` : path;
916
+ }
917
+ var init_url = __esm({
918
+ "../core/src/utils/url.ts"() {
919
+ "use strict";
920
+ }
921
+ });
922
+
923
+ // ../core/src/utils/uuid.ts
924
+ function generateUuid() {
925
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
926
+ return crypto.randomUUID();
927
+ }
928
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
929
+ const r = Math.random() * 16 | 0;
930
+ const v = c === "x" ? r : r & 3 | 8;
931
+ return v.toString(16);
932
+ });
933
+ }
934
+ var init_uuid = __esm({
935
+ "../core/src/utils/uuid.ts"() {
936
+ "use strict";
937
+ }
938
+ });
939
+
940
+ // ../core/src/index.ts
941
+ var init_src = __esm({
942
+ "../core/src/index.ts"() {
943
+ "use strict";
944
+ init_dispatcher();
945
+ init_types();
946
+ init_dispatcher2();
947
+ init_container();
948
+ init_make_dependencies();
949
+ init_router();
950
+ init_base();
951
+ init_composite();
952
+ init_console();
953
+ init_local_storage_filter();
954
+ init_framework();
955
+ init_prefetched_intents();
956
+ init_stable_stringify();
957
+ init_client();
958
+ init_base_controller();
959
+ init_mapper();
960
+ init_define_routes();
961
+ init_lru_map();
962
+ init_optional();
963
+ init_url();
964
+ init_uuid();
965
+ }
966
+ });
967
+
968
+ // ../ssr/src/render.ts
969
+ async function ssrRender(options) {
970
+ const { url, frameworkConfig, bootstrap, getErrorPage, renderApp } = options;
971
+ const framework = Framework.create(frameworkConfig);
972
+ bootstrap(framework);
973
+ const parsed = new URL(url, "http://localhost");
974
+ const fullPath = parsed.pathname + parsed.search;
975
+ const match = framework.routeUrl(fullPath);
976
+ let page;
977
+ let serverData = [];
978
+ if (match) {
979
+ try {
980
+ page = await framework.dispatch(match.intent);
981
+ serverData = [{ intent: match.intent, data: page }];
982
+ } catch {
983
+ page = getErrorPage(500, "Internal error");
984
+ }
985
+ } else {
986
+ page = getErrorPage(404, "Page not found");
987
+ }
988
+ const result = renderApp(page, framework);
989
+ framework.dispose();
990
+ return {
991
+ html: result.html,
992
+ head: result.head,
993
+ css: result.css,
994
+ serverData
995
+ };
996
+ }
997
+ var init_render = __esm({
998
+ "../ssr/src/render.ts"() {
999
+ "use strict";
1000
+ init_src();
1001
+ }
1002
+ });
1003
+
1004
+ // ../ssr/src/create-render.ts
1005
+ function createSSRRender(config) {
1006
+ const { bootstrap, getErrorPage, renderApp, frameworkConfig } = config;
1007
+ return (url, locale) => ssrRender({
1008
+ url,
1009
+ frameworkConfig: frameworkConfig ?? {},
1010
+ bootstrap,
1011
+ getErrorPage,
1012
+ renderApp: (page) => renderApp(page, locale)
1013
+ });
1014
+ }
1015
+ var init_create_render = __esm({
1016
+ "../ssr/src/create-render.ts"() {
1017
+ "use strict";
1018
+ init_render();
1019
+ }
1020
+ });
1021
+
1022
+ // ../ssr/src/inject.ts
1023
+ function injectSSRContent(options) {
1024
+ const { template, locale, head, css, html, serializedData } = options;
1025
+ const cssTag = css ? `<style>${css}</style>` : "";
1026
+ return template.replace(SSR_PLACEHOLDERS.LANG, locale).replace(SSR_PLACEHOLDERS.HEAD, `${head}
1027
+ ${cssTag}`).replace(SSR_PLACEHOLDERS.BODY, html).replace(
1028
+ SSR_PLACEHOLDERS.DATA,
1029
+ `<script id="serialized-server-data" type="application/json">${serializedData}</script>`
1030
+ );
1031
+ }
1032
+ var SSR_PLACEHOLDERS;
1033
+ var init_inject = __esm({
1034
+ "../ssr/src/inject.ts"() {
1035
+ "use strict";
1036
+ SSR_PLACEHOLDERS = {
1037
+ LANG: "<!--ssr-lang-->",
1038
+ HEAD: "<!--ssr-head-->",
1039
+ BODY: "<!--ssr-body-->",
1040
+ DATA: "<!--ssr-data-->"
1041
+ };
1042
+ }
1043
+ });
1044
+
1045
+ // ../ssr/src/server-data.ts
1046
+ function serializeServerData(data) {
1047
+ const json = JSON.stringify(data);
1048
+ return json.replace(
1049
+ HTML_ESCAPE_PATTERN,
1050
+ (match) => HTML_REPLACEMENTS[match] ?? match
1051
+ );
1052
+ }
1053
+ var HTML_REPLACEMENTS, HTML_ESCAPE_PATTERN;
1054
+ var init_server_data = __esm({
1055
+ "../ssr/src/server-data.ts"() {
1056
+ "use strict";
1057
+ HTML_REPLACEMENTS = {
1058
+ "<": "\\u003C",
1059
+ ">": "\\u003E",
1060
+ "/": "\\u002F",
1061
+ "\u2028": "\\u2028",
1062
+ "\u2029": "\\u2029"
1063
+ };
1064
+ HTML_ESCAPE_PATTERN = /[<>/\u2028\u2029]/g;
1065
+ }
1066
+ });
1067
+
1068
+ // ../ssr/src/index.ts
1069
+ var src_exports = {};
1070
+ __export(src_exports, {
1071
+ Framework: () => Framework,
1072
+ SSR_PLACEHOLDERS: () => SSR_PLACEHOLDERS,
1073
+ createSSRRender: () => createSSRRender,
1074
+ injectSSRContent: () => injectSSRContent,
1075
+ serializeServerData: () => serializeServerData,
1076
+ ssrRender: () => ssrRender
1077
+ });
1078
+ var init_src2 = __esm({
1079
+ "../ssr/src/index.ts"() {
1080
+ "use strict";
1081
+ init_create_render();
1082
+ init_inject();
1083
+ init_render();
1084
+ init_server_data();
1085
+ init_src();
1086
+ }
1087
+ });
1088
+
1089
+ // ../server/src/locale.ts
1090
+ var locale_exports = {};
1091
+ __export(locale_exports, {
1092
+ parseAcceptLanguage: () => parseAcceptLanguage
1093
+ });
1094
+ function parseAcceptLanguage(header, supported, fallback) {
1095
+ const effectiveSupported = supported ?? ["zh", "en"];
1096
+ const effectiveFallback = fallback ?? effectiveSupported[0] ?? "en";
1097
+ if (!header) return effectiveFallback;
1098
+ const langs = header.split(",").map((part) => {
1099
+ const [lang, q] = part.trim().split(";q=");
1100
+ return {
1101
+ lang: lang.trim().toLowerCase(),
1102
+ q: q ? parseFloat(q) : 1
1103
+ };
1104
+ }).sort((a, b) => b.q - a.q);
1105
+ for (const { lang } of langs) {
1106
+ const prefix = lang.split("-")[0];
1107
+ if (effectiveSupported.includes(prefix)) {
1108
+ return prefix;
1109
+ }
1110
+ }
1111
+ return effectiveFallback;
1112
+ }
1113
+ var init_locale = __esm({
1114
+ "../server/src/locale.ts"() {
1115
+ "use strict";
1116
+ }
1117
+ });
1118
+
1119
+ // ../server/src/app.ts
1120
+ var app_exports = {};
1121
+ __export(app_exports, {
1122
+ createSSRApp: () => createSSRApp
1123
+ });
1124
+ function createSSRApp(options) {
1125
+ const {
1126
+ root,
1127
+ vite,
1128
+ isProduction,
1129
+ ssrEntryPath = "/src/ssr.ts",
1130
+ ssrProductionModule,
1131
+ supportedLocales,
1132
+ defaultLocale
1133
+ } = options;
1134
+ const app = new import_hono.Hono();
1135
+ async function readTemplate(url) {
1136
+ if (!isProduction && vite) {
1137
+ const { readFileSync: readFileSync2 } = await import(
1138
+ /* @vite-ignore */
1139
+ "fs"
1140
+ );
1141
+ const { resolve: resolve2 } = await import(
1142
+ /* @vite-ignore */
1143
+ "path"
1144
+ );
1145
+ const raw = readFileSync2(resolve2(root, "index.html"), "utf-8");
1146
+ return vite.transformIndexHtml(url, raw);
1147
+ }
1148
+ const isDeno = typeof globalThis.Deno !== "undefined";
1149
+ if (isDeno) {
1150
+ return globalThis.Deno.readTextFileSync(
1151
+ new URL("../dist/client/index.html", import_meta.url)
595
1152
  );
596
- return cached;
597
1153
  }
598
- logger.debug(
599
- `[Framework] dispatch intent: ${intent.id}`,
600
- intent.params
1154
+ const { readFileSync } = await import(
1155
+ /* @vite-ignore */
1156
+ "fs"
601
1157
  );
602
- return this.intentDispatcher.dispatch(intent, this.container);
603
- }
604
- /** 执行 Action — 处理用户交互 */
605
- async perform(action) {
606
- const logger = this.container.resolve(DEP_KEYS.LOGGER);
607
- logger.debug(`[Framework] perform action: ${action.kind}`);
608
- return this.actionDispatcher.perform(action);
609
- }
610
- /** 路由 URL — 将 URL 解析为 Intent + Action */
611
- routeUrl(url) {
612
- return this.router.resolve(url);
613
- }
614
- /** 记录页面访问事件 */
615
- didEnterPage(page) {
616
- const metrics = this.container.resolve(
617
- DEP_KEYS.METRICS
1158
+ const { resolve } = await import(
1159
+ /* @vite-ignore */
1160
+ "path"
618
1161
  );
619
- metrics.recordPageView(page.pageType, {
620
- pageId: page.id,
621
- title: page.title
622
- });
623
- }
624
- /** 注册 Action 处理器 */
625
- onAction(kind, handler) {
626
- this.actionDispatcher.onAction(kind, handler);
627
- }
628
- /** 注册 Intent Controller */
629
- registerIntent(controller) {
630
- this.intentDispatcher.register(controller);
631
- }
632
- /** 销毁 Framework 实例 */
633
- dispose() {
634
- this.container.dispose();
635
- }
636
- };
637
-
638
- // ../core/src/http/client.ts
639
- var HttpError = class extends Error {
640
- constructor(status, statusText, body) {
641
- super(`HTTP ${status}: ${statusText}`);
642
- this.status = status;
643
- this.statusText = statusText;
644
- this.body = body;
645
- this.name = "HttpError";
646
- }
647
- };
648
- var HttpClient = class {
649
- baseUrl;
650
- defaultHeaders;
651
- fetchFn;
652
- constructor(config) {
653
- this.baseUrl = config.baseUrl;
654
- this.defaultHeaders = config.defaultHeaders ?? {};
655
- this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
656
- }
657
- /** GET 请求,返回解析后的 JSON */
658
- async get(path, params) {
659
- return this.request("GET", path, { params });
660
- }
661
- /** POST 请求,自动序列化 body 为 JSON */
662
- async post(path, body, params) {
663
- return this.request("POST", path, { body, params });
664
- }
665
- /** PUT 请求 */
666
- async put(path, body, params) {
667
- return this.request("PUT", path, { body, params });
668
- }
669
- /** DELETE 请求 */
670
- async del(path, params) {
671
- return this.request("DELETE", path, { params });
672
- }
673
- /**
674
- * 底层请求方法 — 子类可覆写以自定义行为
675
- *
676
- * 自动处理:
677
- * - URL 拼接 (baseUrl + path + params)
678
- * - 默认 headers 合并
679
- * - JSON body 序列化
680
- * - 响应 JSON 解析
681
- * - 非 2xx 状态码抛出 HttpError
682
- */
683
- async request(method, path, options) {
684
- const url = this.buildUrl(path, options?.params);
685
- const headers = {
686
- ...this.defaultHeaders,
687
- ...options?.headers
688
- };
689
- const init = { method, headers };
690
- if (options?.body !== void 0) {
691
- headers["Content-Type"] = headers["Content-Type"] ?? "application/json";
692
- init.body = JSON.stringify(options.body);
693
- }
694
- const response = await this.fetchFn(url, init);
695
- if (!response.ok) {
696
- const body = await response.text().catch(() => void 0);
697
- throw new HttpError(response.status, response.statusText, body);
698
- }
699
- return response.json();
1162
+ return readFileSync(resolve(root, "dist/client/index.html"), "utf-8");
700
1163
  }
701
- /** 构建完整 URL — 子类可覆写以自定义 URL 拼接逻辑 */
702
- buildUrl(path, params) {
703
- const base = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
704
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
705
- const url = new URL(`${base}${normalizedPath}`, "http://placeholder");
706
- if (params) {
707
- for (const [k, v] of Object.entries(params)) {
708
- url.searchParams.set(k, v);
709
- }
1164
+ async function loadSSRModule() {
1165
+ if (!isProduction && vite) {
1166
+ return await vite.ssrLoadModule(ssrEntryPath);
710
1167
  }
711
- if (this.baseUrl.startsWith("http")) {
712
- return url.toString();
1168
+ if (ssrProductionModule) {
1169
+ return import(ssrProductionModule);
713
1170
  }
714
- return `${url.pathname}${url.search}`;
1171
+ const { resolve } = await import(
1172
+ /* @vite-ignore */
1173
+ "path"
1174
+ );
1175
+ const { pathToFileURL } = await import(
1176
+ /* @vite-ignore */
1177
+ "url"
1178
+ );
1179
+ const absPath = pathToFileURL(resolve(root, "dist/server/ssr.js")).href;
1180
+ return import(absPath);
715
1181
  }
716
- };
717
-
718
- // ../core/src/intents/base-controller.ts
719
- var BaseController = class {
720
- /**
721
- * 错误回退 — 子类可选覆写
722
- *
723
- * 当 execute() 抛出异常时调用。
724
- * 默认行为: 重新抛出原始错误。
725
- *
726
- * @param params - Intent 参数
727
- * @param error - execute() 抛出的错误
728
- * @returns 回退数据
729
- */
730
- fallback(params, error) {
731
- throw error;
732
- }
733
- /**
734
- * IntentController.perform() 实现
735
- *
736
- * 自动 try/catch → fallback 模式。
737
- */
738
- async perform(intent, container) {
739
- const params = intent.params ?? {};
1182
+ app.get("*", async (c) => {
1183
+ const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
740
1184
  try {
741
- return await this.execute(params, container);
742
- } catch (e) {
743
- return this.fallback(
744
- params,
745
- e instanceof Error ? e : new Error(String(e))
1185
+ const template = await readTemplate(url);
1186
+ const { render, serializeServerData: serializeServerData2 } = await loadSSRModule();
1187
+ const locale = parseAcceptLanguage(
1188
+ c.req.header("accept-language"),
1189
+ supportedLocales,
1190
+ defaultLocale
746
1191
  );
747
- }
748
- }
749
- };
750
-
751
- // ../core/src/data/mapper.ts
752
- function pipe(...mappers) {
753
- return (input) => mappers.reduce((acc, mapper) => mapper(acc), input);
754
- }
755
- function pipeAsync(...mappers) {
756
- return async (input) => {
757
- let acc = input;
758
- for (const mapper of mappers) {
759
- acc = await mapper(acc);
760
- }
761
- return acc;
762
- };
763
- }
764
- function mapEach(mapper) {
765
- return (items) => items.map(mapper);
766
- }
767
-
768
- // ../core/src/bootstrap/define-routes.ts
769
- function defineRoutes(framework, definitions) {
770
- const registeredIntents = /* @__PURE__ */ new Set();
771
- for (const def of definitions) {
772
- if (def.controller && !registeredIntents.has(def.intentId)) {
773
- framework.registerIntent(def.controller);
774
- registeredIntents.add(def.intentId);
775
- }
776
- framework.router.add(def.path, def.intentId);
777
- }
778
- }
779
-
780
- // ../core/src/utils/lru-map.ts
781
- var LruMap = class {
782
- map = /* @__PURE__ */ new Map();
783
- capacity;
784
- constructor(capacity) {
785
- this.capacity = capacity;
786
- }
787
- get(key) {
788
- const value = this.map.get(key);
789
- if (value !== void 0) {
790
- this.map.delete(key);
791
- this.map.set(key, value);
792
- }
793
- return value;
794
- }
795
- set(key, value) {
796
- if (this.map.has(key)) {
797
- this.map.delete(key);
798
- } else if (this.map.size >= this.capacity) {
799
- const oldest = this.map.keys().next().value;
800
- if (oldest !== void 0) {
801
- this.map.delete(oldest);
1192
+ const {
1193
+ html: appHtml,
1194
+ head,
1195
+ css,
1196
+ serverData
1197
+ } = await render(url, locale);
1198
+ const serializedData = serializeServerData2(serverData);
1199
+ const finalHtml = injectSSRContent({
1200
+ template,
1201
+ locale,
1202
+ head,
1203
+ css,
1204
+ html: appHtml,
1205
+ serializedData
1206
+ });
1207
+ return c.html(finalHtml);
1208
+ } catch (e) {
1209
+ if (!isProduction && vite) {
1210
+ vite.ssrFixStacktrace(e);
802
1211
  }
1212
+ console.error("[SSR Error]", e);
1213
+ return c.text("Internal Server Error", 500);
803
1214
  }
804
- this.map.set(key, value);
805
- }
806
- has(key) {
807
- return this.map.has(key);
808
- }
809
- delete(key) {
810
- return this.map.delete(key);
811
- }
812
- get size() {
813
- return this.map.size;
814
- }
815
- clear() {
816
- this.map.clear();
817
- }
818
- };
819
-
820
- // ../core/src/utils/optional.ts
821
- function isSome(value) {
822
- return value !== null && value !== void 0;
823
- }
824
- function isNone(value) {
825
- return value === null || value === void 0;
826
- }
827
-
828
- // ../core/src/utils/url.ts
829
- function removeScheme(url) {
830
- return url.replace(/^https?:\/\//, "");
831
- }
832
- function removeHost(url) {
833
- try {
834
- const parsed = new URL(url);
835
- return parsed.pathname + parsed.search + parsed.hash;
836
- } catch {
837
- return url;
838
- }
839
- }
840
- function removeQueryParams(url) {
841
- return url.split("?")[0];
842
- }
843
- function getBaseUrl(url) {
844
- return url.split("?")[0].split("#")[0];
1215
+ });
1216
+ return app;
845
1217
  }
846
- function buildUrl(path, params) {
847
- if (!params) return path;
848
- const searchParams = new URLSearchParams();
849
- for (const [key, value] of Object.entries(params)) {
850
- if (value !== void 0) {
851
- searchParams.set(key, value);
852
- }
1218
+ var import_hono, import_meta;
1219
+ var init_app = __esm({
1220
+ "../server/src/app.ts"() {
1221
+ "use strict";
1222
+ init_src2();
1223
+ import_hono = require("hono");
1224
+ init_locale();
1225
+ import_meta = {};
853
1226
  }
854
- const qs = searchParams.toString();
855
- return qs ? `${path}?${qs}` : path;
856
- }
1227
+ });
857
1228
 
858
- // ../core/src/utils/uuid.ts
859
- function generateUuid() {
860
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
861
- return crypto.randomUUID();
862
- }
863
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
864
- const r = Math.random() * 16 | 0;
865
- const v = c === "x" ? r : r & 3 | 8;
866
- return v.toString(16);
867
- });
868
- }
1229
+ // src/index.ts
1230
+ var index_exports = {};
1231
+ __export(index_exports, {
1232
+ ACTION_KINDS: () => ACTION_KINDS,
1233
+ ActionDispatcher: () => ActionDispatcher,
1234
+ BaseController: () => BaseController,
1235
+ BaseLogger: () => BaseLogger,
1236
+ CompositeLogger: () => CompositeLogger,
1237
+ CompositeLoggerFactory: () => CompositeLoggerFactory,
1238
+ ConsoleLogger: () => ConsoleLogger,
1239
+ ConsoleLoggerFactory: () => ConsoleLoggerFactory,
1240
+ Container: () => Container,
1241
+ DEP_KEYS: () => DEP_KEYS,
1242
+ Framework: () => Framework,
1243
+ History: () => History,
1244
+ HttpClient: () => HttpClient,
1245
+ HttpError: () => HttpError,
1246
+ IntentDispatcher: () => IntentDispatcher,
1247
+ LruMap: () => LruMap,
1248
+ PrefetchedIntents: () => PrefetchedIntents,
1249
+ Router: () => Router,
1250
+ SSR_PLACEHOLDERS: () => SSR_PLACEHOLDERS,
1251
+ autoAdapter: () => autoAdapter,
1252
+ buildUrl: () => buildUrl,
1253
+ cloudflareAdapter: () => cloudflareAdapter,
1254
+ createPrefetchedIntentsFromDom: () => createPrefetchedIntentsFromDom,
1255
+ createSSRApp: () => createSSRApp,
1256
+ createSSRRender: () => createSSRRender,
1257
+ createServer: () => createServer,
1258
+ defineRoutes: () => defineRoutes,
1259
+ deserializeServerData: () => deserializeServerData,
1260
+ detectRuntime: () => detectRuntime,
1261
+ finesoftFrontViteConfig: () => finesoftFrontViteConfig,
1262
+ generateUuid: () => generateUuid,
1263
+ getBaseUrl: () => getBaseUrl,
1264
+ injectSSRContent: () => injectSSRContent,
1265
+ isCompoundAction: () => isCompoundAction,
1266
+ isExternalUrlAction: () => isExternalUrlAction,
1267
+ isFlowAction: () => isFlowAction,
1268
+ isNone: () => isNone,
1269
+ isSome: () => isSome,
1270
+ makeDependencies: () => makeDependencies,
1271
+ makeExternalUrlAction: () => makeExternalUrlAction,
1272
+ makeFlowAction: () => makeFlowAction,
1273
+ mapEach: () => mapEach,
1274
+ netlifyAdapter: () => netlifyAdapter,
1275
+ nodeAdapter: () => nodeAdapter,
1276
+ parseAcceptLanguage: () => parseAcceptLanguage,
1277
+ pipe: () => pipe,
1278
+ pipeAsync: () => pipeAsync,
1279
+ registerActionHandlers: () => registerActionHandlers,
1280
+ registerExternalUrlHandler: () => registerExternalUrlHandler,
1281
+ registerFlowActionHandler: () => registerFlowActionHandler,
1282
+ removeHost: () => removeHost,
1283
+ removeQueryParams: () => removeQueryParams,
1284
+ removeScheme: () => removeScheme,
1285
+ resetFilterCache: () => resetFilterCache,
1286
+ resolveAdapter: () => resolveAdapter,
1287
+ resolveRoot: () => resolveRoot,
1288
+ serializeServerData: () => serializeServerData,
1289
+ shouldLog: () => shouldLog,
1290
+ ssrRender: () => ssrRender,
1291
+ stableStringify: () => stableStringify,
1292
+ startBrowserApp: () => startBrowserApp,
1293
+ startServer: () => startServer,
1294
+ staticAdapter: () => staticAdapter,
1295
+ tryScroll: () => tryScroll,
1296
+ vercelAdapter: () => vercelAdapter
1297
+ });
1298
+ module.exports = __toCommonJS(index_exports);
1299
+ init_src();
869
1300
 
870
1301
  // ../browser/src/action-handlers/external-url-action.ts
1302
+ init_src();
871
1303
  function registerExternalUrlHandler(deps) {
872
1304
  const { framework, log } = deps;
873
1305
  framework.onAction(
@@ -879,6 +1311,12 @@ function registerExternalUrlHandler(deps) {
879
1311
  );
880
1312
  }
881
1313
 
1314
+ // ../browser/src/action-handlers/flow-action.ts
1315
+ init_src();
1316
+
1317
+ // ../browser/src/utils/history.ts
1318
+ init_src();
1319
+
882
1320
  // ../browser/src/utils/try-scroll.ts
883
1321
  var MAX_TRIES = 100;
884
1322
  var FUDGE = 16;
@@ -1126,7 +1564,11 @@ function registerActionHandlers(deps) {
1126
1564
  registerExternalUrlHandler({ framework, log });
1127
1565
  }
1128
1566
 
1567
+ // ../browser/src/start-app.ts
1568
+ init_src();
1569
+
1129
1570
  // ../browser/src/server-data.ts
1571
+ init_src();
1130
1572
  var SERVER_DATA_ID = "serialized-server-data";
1131
1573
  function deserializeServerData() {
1132
1574
  const script = document.getElementById(SERVER_DATA_ID);
@@ -1184,205 +1626,459 @@ async function startBrowserApp(config) {
1184
1626
  }
1185
1627
  }
1186
1628
 
1187
- // ../ssr/src/render.ts
1188
- async function ssrRender(options) {
1189
- const { url, frameworkConfig, bootstrap, getErrorPage, renderApp } = options;
1190
- const framework = Framework.create(frameworkConfig);
1191
- bootstrap(framework);
1192
- const parsed = new URL(url, "http://localhost");
1193
- const fullPath = parsed.pathname + parsed.search;
1194
- const match = framework.routeUrl(fullPath);
1195
- let page;
1196
- let serverData = [];
1197
- if (match) {
1198
- try {
1199
- page = await framework.dispatch(match.intent);
1200
- serverData = [{ intent: match.intent, data: page }];
1201
- } catch {
1202
- page = getErrorPage(500, "Internal error");
1203
- }
1204
- } else {
1205
- page = getErrorPage(404, "Page not found");
1629
+ // ../browser/src/index.ts
1630
+ init_src();
1631
+
1632
+ // src/index.ts
1633
+ init_src2();
1634
+
1635
+ // ../server/src/adapters/shared.ts
1636
+ var BUILD_TOOL_EXTERNALS = [
1637
+ "vite",
1638
+ "esbuild",
1639
+ "rollup",
1640
+ "fsevents",
1641
+ "lightningcss"
1642
+ ];
1643
+ function generateSSREntry(ctx, opts) {
1644
+ const setupImport = ctx.setupPath ? `import _setupDefault from "./${ctx.setupPath}";` : ``;
1645
+ const setupCall = ctx.setupPath ? `if (typeof _setupDefault === "function") await _setupDefault(app);` : ``;
1646
+ const locales = JSON.stringify(ctx.locales);
1647
+ const defaultLocale = JSON.stringify(ctx.defaultLocale);
1648
+ return `
1649
+ import { Hono } from "hono";
1650
+ ${opts.platformImport}
1651
+ import { render, serializeServerData } from "./${ctx.ssrEntry}";
1652
+ ${setupImport}
1653
+
1654
+ const TEMPLATE = ${JSON.stringify(ctx.templateHtml)};
1655
+ const LOCALES = ${locales};
1656
+ const DEFAULT_LOCALE = ${defaultLocale};
1657
+
1658
+ function parseAcceptLanguage(header) {
1659
+ if (!header) return DEFAULT_LOCALE;
1660
+ const langs = header.split(",").map(p => {
1661
+ const [l, q] = p.trim().split(";q=");
1662
+ return { l: l.trim().toLowerCase(), q: q ? +q : 1 };
1663
+ }).sort((a, b) => b.q - a.q);
1664
+ for (const { l } of langs) {
1665
+ const prefix = l.split("-")[0];
1666
+ if (LOCALES.includes(prefix)) return prefix;
1206
1667
  }
1207
- const result = renderApp(page, framework);
1208
- framework.dispose();
1209
- return {
1210
- html: result.html,
1211
- head: result.head,
1212
- css: result.css,
1213
- serverData
1214
- };
1668
+ return DEFAULT_LOCALE;
1215
1669
  }
1216
1670
 
1217
- // ../ssr/src/create-render.ts
1218
- function createSSRRender(config) {
1219
- const { bootstrap, getErrorPage, renderApp, frameworkConfig } = config;
1220
- return (url, locale) => ssrRender({
1221
- url,
1222
- frameworkConfig: frameworkConfig ?? {},
1223
- bootstrap,
1224
- getErrorPage,
1225
- renderApp: (page) => renderApp(page, locale)
1226
- });
1671
+ function injectSSR(t, locale, head, css, html, data) {
1672
+ return t
1673
+ .replace("<!--ssr-lang-->", locale)
1674
+ .replace("<!--ssr-head-->", head + "\\n<style>" + css + "</style>")
1675
+ .replace("<!--ssr-body-->", html)
1676
+ .replace("<!--ssr-data-->", '<script id="serialized-server-data" type="application/json">' + data + "</script>");
1227
1677
  }
1228
1678
 
1229
- // ../ssr/src/inject.ts
1230
- var SSR_PLACEHOLDERS = {
1231
- LANG: "<!--ssr-lang-->",
1232
- HEAD: "<!--ssr-head-->",
1233
- BODY: "<!--ssr-body-->",
1234
- DATA: "<!--ssr-data-->"
1235
- };
1236
- function injectSSRContent(options) {
1237
- const { template, locale, head, css, html, serializedData } = options;
1238
- const cssTag = css ? `<style>${css}</style>` : "";
1239
- return template.replace(SSR_PLACEHOLDERS.LANG, locale).replace(SSR_PLACEHOLDERS.HEAD, `${head}
1240
- ${cssTag}`).replace(SSR_PLACEHOLDERS.BODY, html).replace(
1241
- SSR_PLACEHOLDERS.DATA,
1242
- `<script id="serialized-server-data" type="application/json">${serializedData}</script>`
1243
- );
1679
+ const app = new Hono();
1680
+ ${setupCall}
1681
+
1682
+ app.get("*", async (c) => {
1683
+ const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
1684
+ try {
1685
+ const locale = parseAcceptLanguage(c.req.header("accept-language"));
1686
+ const { html: appHtml, head, css, serverData } = await render(url, locale);
1687
+ const serializedData = serializeServerData(serverData);
1688
+ return c.html(injectSSR(TEMPLATE, locale, head, css, appHtml, serializedData));
1689
+ } catch (e) {
1690
+ console.error("[SSR Error]", e);
1691
+ return c.text("Internal Server Error", 500);
1692
+ }
1693
+ });
1694
+
1695
+ ${opts.platformExport}
1696
+ `;
1697
+ }
1698
+ async function buildBundle(ctx, opts) {
1699
+ await ctx.vite.build({
1700
+ root: ctx.root,
1701
+ build: {
1702
+ ssr: opts.entry,
1703
+ outDir: opts.outDir,
1704
+ emptyOutDir: true,
1705
+ target: opts.target ?? "node18",
1706
+ rollupOptions: {
1707
+ output: { entryFileNames: opts.fileName ?? "index.mjs" }
1708
+ }
1709
+ },
1710
+ ssr: {
1711
+ noExternal: opts.noExternal !== false,
1712
+ external: opts.external ?? BUILD_TOOL_EXTERNALS
1713
+ },
1714
+ resolve: ctx.resolvedResolve,
1715
+ css: ctx.resolvedCss
1716
+ });
1717
+ }
1718
+ function copyStaticAssets(ctx, destDir, opts) {
1719
+ const { fs, path } = ctx;
1720
+ fs.cpSync(path.resolve(ctx.root, "dist/client"), destDir, {
1721
+ recursive: true
1722
+ });
1723
+ if (opts?.excludeHtml !== false) {
1724
+ fs.rmSync(path.join(destDir, "index.html"), { force: true });
1725
+ }
1244
1726
  }
1245
1727
 
1246
- // ../ssr/src/server-data.ts
1247
- var HTML_REPLACEMENTS = {
1248
- "<": "\\u003C",
1249
- ">": "\\u003E",
1250
- "/": "\\u002F",
1251
- "\u2028": "\\u2028",
1252
- "\u2029": "\\u2029"
1253
- };
1254
- var HTML_ESCAPE_PATTERN = /[<>/\u2028\u2029]/g;
1255
- function serializeServerData(data) {
1256
- const json = JSON.stringify(data);
1257
- return json.replace(
1258
- HTML_ESCAPE_PATTERN,
1259
- (match) => HTML_REPLACEMENTS[match] ?? match
1260
- );
1728
+ // ../server/src/adapters/cloudflare.ts
1729
+ function cloudflareAdapter() {
1730
+ return {
1731
+ name: "cloudflare",
1732
+ async build(ctx) {
1733
+ const { fs, path, root } = ctx;
1734
+ const outputDir = path.resolve(root, "dist/cloudflare");
1735
+ fs.rmSync(outputDir, { recursive: true, force: true });
1736
+ const entrySource = generateSSREntry(ctx, {
1737
+ platformImport: ``,
1738
+ platformExport: `export default app;`
1739
+ });
1740
+ const tempEntry = path.resolve(root, ".cf-entry.tmp.mjs");
1741
+ fs.writeFileSync(tempEntry, entrySource);
1742
+ try {
1743
+ await buildBundle(ctx, {
1744
+ entry: ".cf-entry.tmp.mjs",
1745
+ outDir: outputDir,
1746
+ target: "es2022",
1747
+ fileName: "_worker.js"
1748
+ // 使用默认 external(vite/esbuild/rollup/fsevents/lightningcss)
1749
+ // 这些构建工具运行时不需要,且 fsevents 是 macOS .node 原生二进制无法打包
1750
+ });
1751
+ copyStaticAssets(ctx, path.resolve(outputDir, "assets"));
1752
+ } finally {
1753
+ fs.rmSync(tempEntry, { force: true });
1754
+ }
1755
+ console.log(" Cloudflare output \u2192 dist/cloudflare/\n");
1756
+ }
1757
+ };
1261
1758
  }
1262
1759
 
1263
- // ../server/src/app.ts
1264
- var import_hono = require("hono");
1760
+ // ../server/src/adapters/netlify.ts
1761
+ function netlifyAdapter() {
1762
+ return {
1763
+ name: "netlify",
1764
+ async build(ctx) {
1765
+ const { fs, path, root } = ctx;
1766
+ const funcDir = path.resolve(
1767
+ root,
1768
+ ".netlify/functions-internal/ssr"
1769
+ );
1770
+ fs.rmSync(path.resolve(root, ".netlify"), {
1771
+ recursive: true,
1772
+ force: true
1773
+ });
1774
+ const entrySource = generateSSREntry(ctx, {
1775
+ platformImport: `import { handle } from "hono/netlify";`,
1776
+ platformExport: `export default handle(app);`
1777
+ });
1778
+ const tempEntry = path.resolve(root, ".netlify-entry.tmp.mjs");
1779
+ fs.writeFileSync(tempEntry, entrySource);
1780
+ try {
1781
+ await buildBundle(ctx, {
1782
+ entry: ".netlify-entry.tmp.mjs",
1783
+ outDir: funcDir,
1784
+ target: "node18"
1785
+ });
1786
+ } finally {
1787
+ fs.rmSync(tempEntry, { force: true });
1788
+ }
1789
+ const redirects = `/* /.netlify/functions/ssr 200
1790
+ `;
1791
+ fs.writeFileSync(
1792
+ path.resolve(root, "dist/client/_redirects"),
1793
+ redirects
1794
+ );
1795
+ console.log(
1796
+ " Netlify output \u2192 .netlify/functions-internal/ssr/\n Publish dir: dist/client/\n"
1797
+ );
1798
+ }
1799
+ };
1800
+ }
1265
1801
 
1266
- // ../server/src/locale.ts
1267
- function parseAcceptLanguage(header, supported, fallback) {
1268
- const effectiveSupported = supported ?? ["zh", "en"];
1269
- const effectiveFallback = fallback ?? effectiveSupported[0] ?? "en";
1270
- if (!header) return effectiveFallback;
1271
- const langs = header.split(",").map((part) => {
1272
- const [lang, q] = part.trim().split(";q=");
1273
- return {
1274
- lang: lang.trim().toLowerCase(),
1275
- q: q ? parseFloat(q) : 1
1276
- };
1277
- }).sort((a, b) => b.q - a.q);
1278
- for (const { lang } of langs) {
1279
- const prefix = lang.split("-")[0];
1280
- if (effectiveSupported.includes(prefix)) {
1281
- return prefix;
1802
+ // ../server/src/adapters/node.ts
1803
+ function nodeAdapter() {
1804
+ return {
1805
+ name: "node",
1806
+ async build(ctx) {
1807
+ const { fs, path, root } = ctx;
1808
+ const entrySource = generateSSREntry(ctx, {
1809
+ platformImport: `import { serve } from "@hono/node-server";`,
1810
+ platformExport: `
1811
+ const port = +(process.env.PORT || 3000);
1812
+ serve({ fetch: app.fetch, port }, (info) => {
1813
+ console.log(\`Server running at http://localhost:\${info.port}\`);
1814
+ });
1815
+ `
1816
+ });
1817
+ const tempEntry = path.resolve(root, ".node-entry.tmp.mjs");
1818
+ fs.writeFileSync(tempEntry, entrySource);
1819
+ try {
1820
+ await buildBundle(ctx, {
1821
+ entry: ".node-entry.tmp.mjs",
1822
+ outDir: path.resolve(root, "dist/server"),
1823
+ target: "node18"
1824
+ });
1825
+ } finally {
1826
+ fs.rmSync(tempEntry, { force: true });
1827
+ }
1828
+ console.log(
1829
+ " Node output \u2192 dist/server/index.mjs\n Run: node dist/server/index.mjs\n"
1830
+ );
1282
1831
  }
1283
- }
1284
- return effectiveFallback;
1832
+ };
1285
1833
  }
1286
1834
 
1287
- // ../server/src/app.ts
1288
- var import_meta = {};
1289
- function createSSRApp(options) {
1290
- const {
1291
- root,
1292
- vite,
1293
- isProduction,
1294
- ssrEntryPath = "/src/ssr.ts",
1295
- ssrProductionModule,
1296
- supportedLocales,
1297
- defaultLocale
1298
- } = options;
1299
- const app = new import_hono.Hono();
1300
- async function readTemplate(url) {
1301
- if (!isProduction && vite) {
1302
- const { readFileSync: readFileSync2 } = await import(
1835
+ // ../server/src/adapters/static.ts
1836
+ function staticAdapter(opts = {}) {
1837
+ return {
1838
+ name: "static",
1839
+ async build(ctx) {
1840
+ const { fs, path, root, vite } = ctx;
1841
+ const outputDir = path.resolve(root, "dist/static");
1842
+ fs.rmSync(outputDir, { recursive: true, force: true });
1843
+ fs.mkdirSync(outputDir, { recursive: true });
1844
+ const { pathToFileURL } = await import(
1303
1845
  /* @vite-ignore */
1304
- "fs"
1846
+ "url"
1305
1847
  );
1306
- const { resolve: resolve2 } = await import(
1848
+ const ssrPath = pathToFileURL(
1849
+ path.resolve(root, "dist/server/ssr.js")
1850
+ ).href;
1851
+ const ssrModule = await import(
1307
1852
  /* @vite-ignore */
1308
- "path"
1853
+ ssrPath
1309
1854
  );
1310
- const raw = readFileSync2(resolve2(root, "index.html"), "utf-8");
1311
- return vite.transformIndexHtml(url, raw);
1312
- }
1313
- const isDeno = typeof globalThis.Deno !== "undefined";
1314
- if (isDeno) {
1315
- return globalThis.Deno.readTextFileSync(
1316
- new URL("../dist/client/index.html", import_meta.url)
1855
+ const routePaths = await extractRoutes(ctx, opts);
1856
+ const allUrls = [];
1857
+ for (const routePath of routePaths) {
1858
+ for (const locale of ctx.locales) {
1859
+ const url = locale === ctx.defaultLocale ? routePath : `/${locale}${routePath === "/" ? "" : routePath}`;
1860
+ allUrls.push(url);
1861
+ }
1862
+ }
1863
+ console.log(
1864
+ ` Pre-rendering ${allUrls.length} pages (${routePaths.length} routes \xD7 ${ctx.locales.length} locales)...
1865
+ `
1317
1866
  );
1867
+ for (const url of allUrls) {
1868
+ try {
1869
+ const locale = inferLocale(
1870
+ url,
1871
+ ctx.locales,
1872
+ ctx.defaultLocale
1873
+ );
1874
+ const {
1875
+ html: appHtml,
1876
+ head,
1877
+ css,
1878
+ serverData
1879
+ } = await ssrModule.render(url, locale);
1880
+ const serializedData = ssrModule.serializeServerData(serverData);
1881
+ const finalHtml = injectSSRForStatic(
1882
+ ctx.templateHtml,
1883
+ locale,
1884
+ head,
1885
+ css,
1886
+ appHtml,
1887
+ serializedData
1888
+ );
1889
+ const filePath = url === "/" ? path.join(outputDir, "index.html") : path.join(outputDir, url, "index.html");
1890
+ fs.mkdirSync(path.resolve(filePath, ".."), {
1891
+ recursive: true
1892
+ });
1893
+ fs.writeFileSync(filePath, finalHtml);
1894
+ } catch (e) {
1895
+ console.warn(` [static] Failed to render ${url}:`, e);
1896
+ }
1897
+ }
1898
+ ctx.copyStaticAssets(outputDir, { excludeHtml: true });
1899
+ console.log(` Static output \u2192 dist/static/
1900
+ `);
1318
1901
  }
1319
- const { readFileSync } = await import(
1902
+ };
1903
+ }
1904
+ async function extractRoutes(ctx, opts) {
1905
+ const routesFile = opts.routesExport ?? "src/lib/bootstrap.ts";
1906
+ const paths = [];
1907
+ try {
1908
+ const { pathToFileURL } = await import(
1320
1909
  /* @vite-ignore */
1321
- "fs"
1910
+ "url"
1322
1911
  );
1323
- const { resolve } = await import(
1912
+ await ctx.vite.build({
1913
+ root: ctx.root,
1914
+ build: {
1915
+ ssr: routesFile,
1916
+ outDir: ctx.path.resolve(ctx.root, "dist/server"),
1917
+ emptyOutDir: false,
1918
+ rollupOptions: {
1919
+ output: { entryFileNames: "_routes.mjs" }
1920
+ }
1921
+ },
1922
+ resolve: ctx.resolvedResolve
1923
+ });
1924
+ const routesPath = pathToFileURL(
1925
+ ctx.path.resolve(ctx.root, "dist/server/_routes.mjs")
1926
+ ).href;
1927
+ const routesMod = await import(
1324
1928
  /* @vite-ignore */
1325
- "path"
1929
+ routesPath
1326
1930
  );
1327
- return readFileSync(resolve(root, "dist/client/index.html"), "utf-8");
1328
- }
1329
- async function loadSSRModule() {
1330
- if (!isProduction && vite) {
1331
- return await vite.ssrLoadModule(ssrEntryPath);
1332
- }
1333
- if (ssrProductionModule) {
1334
- return import(ssrProductionModule);
1931
+ const routes = routesMod.routes ?? routesMod.default;
1932
+ if (Array.isArray(routes)) {
1933
+ for (const r of routes) {
1934
+ if (r.path && !r.path.includes(":")) {
1935
+ paths.push(r.path);
1936
+ }
1937
+ }
1335
1938
  }
1336
- const { resolve } = await import(
1337
- /* @vite-ignore */
1338
- "path"
1339
- );
1340
- const { pathToFileURL } = await import(
1341
- /* @vite-ignore */
1342
- "url"
1939
+ ctx.fs.rmSync(ctx.path.resolve(ctx.root, "dist/server/_routes.mjs"), {
1940
+ force: true
1941
+ });
1942
+ } catch (e) {
1943
+ console.warn(
1944
+ ` [static] Could not load routes from "${routesFile}". Using "/" only.`,
1945
+ e
1343
1946
  );
1344
- const absPath = pathToFileURL(resolve(root, "dist/server/ssr.js")).href;
1345
- return import(absPath);
1947
+ if (paths.length === 0) paths.push("/");
1346
1948
  }
1347
- app.get("*", async (c) => {
1348
- const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
1349
- try {
1350
- const template = await readTemplate(url);
1351
- const { render, serializeServerData: serializeServerData2 } = await loadSSRModule();
1352
- const locale = parseAcceptLanguage(
1353
- c.req.header("accept-language"),
1354
- supportedLocales,
1355
- defaultLocale
1356
- );
1357
- const {
1358
- html: appHtml,
1359
- head,
1360
- css,
1361
- serverData
1362
- } = await render(url, locale);
1363
- const serializedData = serializeServerData2(serverData);
1364
- const finalHtml = injectSSRContent({
1365
- template,
1366
- locale,
1367
- head,
1368
- css,
1369
- html: appHtml,
1370
- serializedData
1949
+ if (opts.dynamicRoutes) {
1950
+ for (const r of opts.dynamicRoutes) {
1951
+ if (!paths.includes(r)) paths.push(r);
1952
+ }
1953
+ }
1954
+ if (paths.length === 0) paths.push("/");
1955
+ return paths;
1956
+ }
1957
+ function inferLocale(url, locales, defaultLocale) {
1958
+ const segments = url.split("/").filter(Boolean);
1959
+ if (segments.length > 0 && locales.includes(segments[0])) {
1960
+ return segments[0];
1961
+ }
1962
+ return defaultLocale;
1963
+ }
1964
+ function injectSSRForStatic(template, locale, head, css, html, serializedData) {
1965
+ return template.replace("<!--ssr-lang-->", locale).replace("<!--ssr-head-->", head + "\n<style>" + css + "</style>").replace("<!--ssr-body-->", html).replace(
1966
+ "<!--ssr-data-->",
1967
+ '<script id="serialized-server-data" type="application/json">' + serializedData + "</script>"
1968
+ );
1969
+ }
1970
+
1971
+ // ../server/src/adapters/vercel.ts
1972
+ function vercelAdapter() {
1973
+ return {
1974
+ name: "vercel",
1975
+ async build(ctx) {
1976
+ const { fs, path, root } = ctx;
1977
+ const outputDir = path.resolve(root, ".vercel/output");
1978
+ fs.rmSync(outputDir, { recursive: true, force: true });
1979
+ const entrySource = generateSSREntry(ctx, {
1980
+ platformImport: `import { handle } from "hono/vercel";`,
1981
+ platformExport: `export default handle(app);`
1371
1982
  });
1372
- return c.html(finalHtml);
1373
- } catch (e) {
1374
- if (!isProduction && vite) {
1375
- vite.ssrFixStacktrace(e);
1983
+ const tempEntry = path.resolve(root, ".vercel-entry.tmp.mjs");
1984
+ fs.writeFileSync(tempEntry, entrySource);
1985
+ try {
1986
+ const funcDir = path.resolve(
1987
+ root,
1988
+ ".vercel/output/functions/ssr.func"
1989
+ );
1990
+ await buildBundle(ctx, {
1991
+ entry: ".vercel-entry.tmp.mjs",
1992
+ outDir: funcDir,
1993
+ target: "node18"
1994
+ });
1995
+ fs.writeFileSync(
1996
+ path.resolve(funcDir, ".vc-config.json"),
1997
+ JSON.stringify(
1998
+ {
1999
+ runtime: "nodejs20.x",
2000
+ handler: "index.mjs",
2001
+ launcherType: "Nodejs"
2002
+ },
2003
+ null,
2004
+ 2
2005
+ )
2006
+ );
2007
+ copyStaticAssets(
2008
+ ctx,
2009
+ path.resolve(root, ".vercel/output/static")
2010
+ );
2011
+ fs.writeFileSync(
2012
+ path.resolve(root, ".vercel/output/config.json"),
2013
+ JSON.stringify(
2014
+ {
2015
+ version: 3,
2016
+ routes: [
2017
+ { handle: "filesystem" },
2018
+ { src: "/(.*)", dest: "/ssr" }
2019
+ ]
2020
+ },
2021
+ null,
2022
+ 2
2023
+ )
2024
+ );
2025
+ } finally {
2026
+ fs.rmSync(tempEntry, { force: true });
1376
2027
  }
1377
- console.error("[SSR Error]", e);
1378
- return c.text("Internal Server Error", 500);
2028
+ console.log(" Vercel output \u2192 .vercel/output/\n");
1379
2029
  }
1380
- });
1381
- return app;
2030
+ };
2031
+ }
2032
+
2033
+ // ../server/src/adapters/resolve.ts
2034
+ function resolveAdapter(value) {
2035
+ if (typeof value !== "string") return value;
2036
+ switch (value) {
2037
+ case "vercel":
2038
+ return vercelAdapter();
2039
+ case "cloudflare":
2040
+ return cloudflareAdapter();
2041
+ case "netlify":
2042
+ return netlifyAdapter();
2043
+ case "node":
2044
+ return nodeAdapter();
2045
+ case "static":
2046
+ return staticAdapter();
2047
+ case "auto":
2048
+ return autoAdapter();
2049
+ default:
2050
+ throw new Error(
2051
+ `[finesoft] Unknown adapter: "${value}". Available: vercel, cloudflare, netlify, node, static, auto`
2052
+ );
2053
+ }
2054
+ }
2055
+
2056
+ // ../server/src/adapters/auto.ts
2057
+ function autoAdapter() {
2058
+ return {
2059
+ name: "auto",
2060
+ async build(ctx) {
2061
+ const detected = detectPlatform();
2062
+ console.log(` [auto] Detected platform: ${detected}
2063
+ `);
2064
+ const adapter = resolveAdapter(detected);
2065
+ return adapter.build(ctx);
2066
+ }
2067
+ };
1382
2068
  }
2069
+ function detectPlatform() {
2070
+ if (process.env.VERCEL) return "vercel";
2071
+ if (process.env.CF_PAGES) return "cloudflare";
2072
+ if (process.env.NETLIFY) return "netlify";
2073
+ return "node";
2074
+ }
2075
+
2076
+ // ../server/src/index.ts
2077
+ init_app();
1383
2078
 
1384
2079
  // ../server/src/create-server.ts
1385
2080
  var import_hono3 = require("hono");
2081
+ init_app();
1386
2082
 
1387
2083
  // ../server/src/runtime.ts
1388
2084
  function detectRuntime() {
@@ -1590,6 +2286,251 @@ async function createServer(config = {}) {
1590
2286
  });
1591
2287
  return { app, vite, runtime };
1592
2288
  }
2289
+
2290
+ // ../server/src/index.ts
2291
+ init_locale();
2292
+
2293
+ // ../server/src/vite-plugin.ts
2294
+ function resolveSetupFn(mod) {
2295
+ if (typeof mod.default === "function") return mod.default;
2296
+ if (typeof mod.setup === "function") return mod.setup;
2297
+ const first = Object.values(mod).find((v) => typeof v === "function");
2298
+ return first ?? null;
2299
+ }
2300
+ function finesoftFrontViteConfig(options = {}) {
2301
+ const ssrEntry = options.ssr?.entry ?? "src/ssr.ts";
2302
+ let root = process.cwd();
2303
+ let resolvedCommand;
2304
+ let resolvedResolve;
2305
+ let resolvedCss;
2306
+ return {
2307
+ name: "finesoft-front",
2308
+ config(userConfig, env) {
2309
+ const overrides = {
2310
+ appType: "custom"
2311
+ };
2312
+ if (env.command === "build" && !process.env.__FINESOFT_SUB_BUILD__) {
2313
+ overrides.build = {
2314
+ outDir: userConfig.build?.outDir ?? "dist/client"
2315
+ };
2316
+ }
2317
+ return overrides;
2318
+ },
2319
+ configResolved(config) {
2320
+ resolvedCommand = config.command;
2321
+ resolvedResolve = config.resolve;
2322
+ resolvedCss = config.css;
2323
+ root = config.root;
2324
+ },
2325
+ // ─── Dev ───────────────────────────────────────────────
2326
+ configureServer(server) {
2327
+ return async () => {
2328
+ const { Hono: HonoClass } = await import(
2329
+ /* @vite-ignore */
2330
+ "hono"
2331
+ );
2332
+ const { createSSRApp: createSSRApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
2333
+ const { getRequestListener } = await import(
2334
+ /* @vite-ignore */
2335
+ "@hono/node-server"
2336
+ );
2337
+ const app = new HonoClass();
2338
+ if (typeof options.setup === "function") {
2339
+ await options.setup(app);
2340
+ } else if (typeof options.setup === "string") {
2341
+ const mod = await server.ssrLoadModule("/" + options.setup);
2342
+ const fn = resolveSetupFn(mod);
2343
+ if (fn) await fn(app);
2344
+ }
2345
+ const ssrApp = createSSRApp2({
2346
+ root,
2347
+ vite: server,
2348
+ isProduction: false,
2349
+ ssrEntryPath: "/" + ssrEntry,
2350
+ supportedLocales: options.locales,
2351
+ defaultLocale: options.defaultLocale
2352
+ });
2353
+ app.route("/", ssrApp);
2354
+ const listener = getRequestListener(app.fetch);
2355
+ server.middlewares.use((req, res) => {
2356
+ listener(req, res);
2357
+ });
2358
+ };
2359
+ },
2360
+ // ─── Preview ───────────────────────────────────────────
2361
+ configurePreviewServer(server) {
2362
+ return async () => {
2363
+ const { readFileSync } = await import(
2364
+ /* @vite-ignore */
2365
+ "fs"
2366
+ );
2367
+ const { resolve } = await import(
2368
+ /* @vite-ignore */
2369
+ "path"
2370
+ );
2371
+ const { pathToFileURL } = await import(
2372
+ /* @vite-ignore */
2373
+ "url"
2374
+ );
2375
+ const { Hono: HonoClass } = await import(
2376
+ /* @vite-ignore */
2377
+ "hono"
2378
+ );
2379
+ const { injectSSRContent: injectSSRContent2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
2380
+ const { parseAcceptLanguage: parseAcceptLanguage2 } = await Promise.resolve().then(() => (init_locale(), locale_exports));
2381
+ const { getRequestListener } = await import(
2382
+ /* @vite-ignore */
2383
+ "@hono/node-server"
2384
+ );
2385
+ const app = new HonoClass();
2386
+ if (typeof options.setup === "function") {
2387
+ await options.setup(app);
2388
+ } else if (typeof options.setup === "string") {
2389
+ try {
2390
+ const setupPath = pathToFileURL(
2391
+ resolve(root, "dist/server/setup.mjs")
2392
+ ).href;
2393
+ const mod = await import(
2394
+ /* @vite-ignore */
2395
+ setupPath
2396
+ );
2397
+ const fn = resolveSetupFn(
2398
+ mod
2399
+ );
2400
+ if (fn) await fn(app);
2401
+ } catch {
2402
+ console.warn(
2403
+ "[finesoft] Could not load setup module for preview. API routes disabled."
2404
+ );
2405
+ }
2406
+ }
2407
+ const templatePath = resolve(root, "dist/client/index.html");
2408
+ const template = readFileSync(templatePath, "utf-8");
2409
+ const ssrPath = pathToFileURL(
2410
+ resolve(root, "dist/server/ssr.js")
2411
+ ).href;
2412
+ const ssrModule = await import(
2413
+ /* @vite-ignore */
2414
+ ssrPath
2415
+ );
2416
+ app.get("*", async (c) => {
2417
+ const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
2418
+ try {
2419
+ const locale = parseAcceptLanguage2(
2420
+ c.req.header("accept-language"),
2421
+ options.locales,
2422
+ options.defaultLocale
2423
+ );
2424
+ const {
2425
+ html: appHtml,
2426
+ head,
2427
+ css,
2428
+ serverData
2429
+ } = await ssrModule.render(url, locale);
2430
+ const serializedData = ssrModule.serializeServerData(serverData);
2431
+ const finalHtml = injectSSRContent2({
2432
+ template,
2433
+ locale,
2434
+ head,
2435
+ css,
2436
+ html: appHtml,
2437
+ serializedData
2438
+ });
2439
+ return c.html(finalHtml);
2440
+ } catch (e) {
2441
+ console.error("[SSR Preview Error]", e);
2442
+ return c.text("Internal Server Error", 500);
2443
+ }
2444
+ });
2445
+ const listener = getRequestListener(app.fetch);
2446
+ server.middlewares.use((req, res) => {
2447
+ listener(req, res);
2448
+ });
2449
+ };
2450
+ },
2451
+ // ─── Build ─────────────────────────────────────────────
2452
+ async closeBundle() {
2453
+ if (process.env.__FINESOFT_SUB_BUILD__) return;
2454
+ if (resolvedCommand !== "build") return;
2455
+ process.env.__FINESOFT_SUB_BUILD__ = "1";
2456
+ try {
2457
+ const vite = await import(
2458
+ /* @vite-ignore */
2459
+ "vite"
2460
+ );
2461
+ const fs = await import(
2462
+ /* @vite-ignore */
2463
+ "fs"
2464
+ );
2465
+ const path = await import(
2466
+ /* @vite-ignore */
2467
+ "path"
2468
+ );
2469
+ console.log("\n Building SSR bundle...\n");
2470
+ await vite.build({
2471
+ root,
2472
+ build: {
2473
+ ssr: ssrEntry,
2474
+ outDir: "dist/server"
2475
+ },
2476
+ resolve: resolvedResolve,
2477
+ css: resolvedCss
2478
+ });
2479
+ if (typeof options.setup === "string") {
2480
+ console.log(" Building setup module...\n");
2481
+ await vite.build({
2482
+ root,
2483
+ build: {
2484
+ ssr: options.setup,
2485
+ outDir: "dist/server",
2486
+ emptyOutDir: false,
2487
+ rollupOptions: {
2488
+ output: { entryFileNames: "setup.mjs" }
2489
+ }
2490
+ },
2491
+ resolve: resolvedResolve
2492
+ });
2493
+ }
2494
+ if (options.adapter) {
2495
+ const adapter = resolveAdapter(options.adapter);
2496
+ const locales = options.locales ?? ["zh", "en"];
2497
+ const defaultLocale = options.defaultLocale ?? locales[0] ?? "en";
2498
+ const templateHtml = fs.readFileSync(
2499
+ path.resolve(root, "dist/client/index.html"),
2500
+ "utf-8"
2501
+ );
2502
+ const ctx = {
2503
+ root,
2504
+ ssrEntry,
2505
+ setupPath: typeof options.setup === "string" ? options.setup : void 0,
2506
+ locales,
2507
+ defaultLocale,
2508
+ templateHtml,
2509
+ resolvedResolve,
2510
+ resolvedCss,
2511
+ vite,
2512
+ fs,
2513
+ path,
2514
+ generateSSREntry(opts) {
2515
+ return generateSSREntry(ctx, opts);
2516
+ },
2517
+ buildBundle(opts) {
2518
+ return buildBundle(ctx, opts);
2519
+ },
2520
+ copyStaticAssets(destDir, opts) {
2521
+ return copyStaticAssets(ctx, destDir, opts);
2522
+ }
2523
+ };
2524
+ console.log(` Running adapter: ${adapter.name}...
2525
+ `);
2526
+ await adapter.build(ctx);
2527
+ }
2528
+ } finally {
2529
+ delete process.env.__FINESOFT_SUB_BUILD__;
2530
+ }
2531
+ }
2532
+ };
2533
+ }
1593
2534
  // Annotate the CommonJS export names for ESM import in node:
1594
2535
  0 && (module.exports = {
1595
2536
  ACTION_KINDS,
@@ -1611,7 +2552,9 @@ async function createServer(config = {}) {
1611
2552
  PrefetchedIntents,
1612
2553
  Router,
1613
2554
  SSR_PLACEHOLDERS,
2555
+ autoAdapter,
1614
2556
  buildUrl,
2557
+ cloudflareAdapter,
1615
2558
  createPrefetchedIntentsFromDom,
1616
2559
  createSSRApp,
1617
2560
  createSSRRender,
@@ -1619,6 +2562,7 @@ async function createServer(config = {}) {
1619
2562
  defineRoutes,
1620
2563
  deserializeServerData,
1621
2564
  detectRuntime,
2565
+ finesoftFrontViteConfig,
1622
2566
  generateUuid,
1623
2567
  getBaseUrl,
1624
2568
  injectSSRContent,
@@ -1631,6 +2575,8 @@ async function createServer(config = {}) {
1631
2575
  makeExternalUrlAction,
1632
2576
  makeFlowAction,
1633
2577
  mapEach,
2578
+ netlifyAdapter,
2579
+ nodeAdapter,
1634
2580
  parseAcceptLanguage,
1635
2581
  pipe,
1636
2582
  pipeAsync,
@@ -1641,6 +2587,7 @@ async function createServer(config = {}) {
1641
2587
  removeQueryParams,
1642
2588
  removeScheme,
1643
2589
  resetFilterCache,
2590
+ resolveAdapter,
1644
2591
  resolveRoot,
1645
2592
  serializeServerData,
1646
2593
  shouldLog,
@@ -1648,6 +2595,8 @@ async function createServer(config = {}) {
1648
2595
  stableStringify,
1649
2596
  startBrowserApp,
1650
2597
  startServer,
1651
- tryScroll
2598
+ staticAdapter,
2599
+ tryScroll,
2600
+ vercelAdapter
1652
2601
  });
1653
2602
  //# sourceMappingURL=index.cjs.map