@finesoft/front 0.1.12 → 0.1.14
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/app-MYBG3TGV.js +10 -0
- package/dist/app-MYBG3TGV.js.map +1 -0
- package/dist/browser.js +12 -10
- package/dist/chunk-2VETWTN5.js +88 -0
- package/dist/chunk-2VETWTN5.js.map +1 -0
- package/dist/chunk-FYP2ZYYV.js +25 -0
- package/dist/chunk-FYP2ZYYV.js.map +1 -0
- package/dist/{chunk-OVGQ4NUA.js → chunk-RVKDILGM.js} +2 -327
- package/dist/chunk-RVKDILGM.js.map +1 -0
- package/dist/chunk-T2AQHAYK.js +337 -0
- package/dist/chunk-T2AQHAYK.js.map +1 -0
- package/dist/chunk-Z4MHYAS3.js +108 -0
- package/dist/chunk-Z4MHYAS3.js.map +1 -0
- package/dist/index.cjs +1801 -833
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -1
- package/dist/index.d.ts +202 -1
- package/dist/index.js +702 -170
- package/dist/index.js.map +1 -1
- package/dist/locale-YK3THSI6.js +7 -0
- package/dist/locale-YK3THSI6.js.map +1 -0
- package/dist/src-7D236CLJ.js +19 -0
- package/dist/src-7D236CLJ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-OVGQ4NUA.js.map +0 -1
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
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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,479 +323,983 @@ 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
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
-
|
|
433
|
-
|
|
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
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
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
|
+
};
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// ../core/src/logger/composite.ts
|
|
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
|
+
};
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// ../core/src/prefetched-intents/stable-stringify.ts
|
|
508
|
+
function stableStringify(obj) {
|
|
509
|
+
if (obj === null || obj === void 0) return String(obj);
|
|
510
|
+
if (typeof obj !== "object") return JSON.stringify(obj);
|
|
511
|
+
if (Array.isArray(obj)) {
|
|
512
|
+
return "[" + obj.map(stableStringify).join(",") + "]";
|
|
513
|
+
}
|
|
514
|
+
const keys = Object.keys(obj).sort();
|
|
515
|
+
const parts = keys.filter((k) => obj[k] !== void 0).map(
|
|
516
|
+
(k) => JSON.stringify(k) + ":" + stableStringify(obj[k])
|
|
517
|
+
);
|
|
518
|
+
return "{" + parts.join(",") + "}";
|
|
519
|
+
}
|
|
520
|
+
var init_stable_stringify = __esm({
|
|
521
|
+
"../core/src/prefetched-intents/stable-stringify.ts"() {
|
|
522
|
+
"use strict";
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// ../core/src/prefetched-intents/prefetched-intents.ts
|
|
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;
|
|
434
622
|
}
|
|
435
|
-
|
|
436
|
-
intent: {
|
|
437
|
-
|
|
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 });
|
|
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
|
|
438
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();
|
|
439
731
|
}
|
|
440
|
-
|
|
441
|
-
|
|
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
|
+
};
|
|
442
748
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
+
};
|
|
446
787
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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);
|
|
453
799
|
}
|
|
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";
|
|
454
809
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return {};
|
|
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);
|
|
465
819
|
}
|
|
820
|
+
framework.router.add(def.path, def.intentId);
|
|
466
821
|
}
|
|
467
|
-
}
|
|
822
|
+
}
|
|
823
|
+
var init_define_routes = __esm({
|
|
824
|
+
"../core/src/bootstrap/define-routes.ts"() {
|
|
825
|
+
"use strict";
|
|
826
|
+
}
|
|
827
|
+
});
|
|
468
828
|
|
|
469
|
-
// ../core/src/
|
|
470
|
-
var
|
|
471
|
-
|
|
472
|
-
|
|
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
|
+
};
|
|
473
872
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
873
|
+
});
|
|
874
|
+
|
|
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";
|
|
478
885
|
}
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
+
}
|
|
483
913
|
}
|
|
484
|
-
|
|
485
|
-
|
|
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";
|
|
486
920
|
}
|
|
487
|
-
|
|
488
|
-
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// ../core/src/utils/uuid.ts
|
|
924
|
+
function generateUuid() {
|
|
925
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
926
|
+
return crypto.randomUUID();
|
|
489
927
|
}
|
|
490
|
-
|
|
491
|
-
|
|
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";
|
|
492
937
|
}
|
|
493
|
-
|
|
494
|
-
|
|
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();
|
|
495
965
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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");
|
|
499
984
|
}
|
|
500
|
-
|
|
985
|
+
} else {
|
|
986
|
+
page = getErrorPage(404, "Page not found");
|
|
501
987
|
}
|
|
502
|
-
|
|
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
|
+
});
|
|
503
1003
|
|
|
504
|
-
// ../
|
|
505
|
-
function
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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();
|
|
510
1019
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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>`
|
|
514
1030
|
);
|
|
515
|
-
return "{" + parts.join(",") + "}";
|
|
516
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
|
+
});
|
|
517
1044
|
|
|
518
|
-
// ../
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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;
|
|
532
1109
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
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);
|
|
549
1147
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
return this.intents.has(stableStringify(intent));
|
|
555
|
-
}
|
|
556
|
-
/** 缓存中的条目数 */
|
|
557
|
-
get size() {
|
|
558
|
-
return this.intents.size;
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
|
|
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
|
|
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
|
-
|
|
599
|
-
|
|
600
|
-
|
|
1154
|
+
const { readFileSync } = await import(
|
|
1155
|
+
/* @vite-ignore */
|
|
1156
|
+
"fs"
|
|
601
1157
|
);
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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
|
-
|
|
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
|
-
|
|
702
|
-
|
|
703
|
-
|
|
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 (
|
|
712
|
-
return
|
|
1168
|
+
if (ssrProductionModule) {
|
|
1169
|
+
return import(ssrProductionModule);
|
|
713
1170
|
}
|
|
714
|
-
|
|
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
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
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
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
|
|
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
|
-
|
|
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
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
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
|
-
|
|
855
|
-
return qs ? `${path}?${qs}` : path;
|
|
856
|
-
}
|
|
1227
|
+
});
|
|
857
1228
|
|
|
858
|
-
//
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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,194 +1626,459 @@ async function startBrowserApp(config) {
|
|
|
1184
1626
|
}
|
|
1185
1627
|
}
|
|
1186
1628
|
|
|
1187
|
-
// ../
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
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;
|
|
1667
|
+
}
|
|
1668
|
+
return DEFAULT_LOCALE;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
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>");
|
|
1215
1677
|
}
|
|
1216
1678
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
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
|
|
1226
1716
|
});
|
|
1227
1717
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
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
|
-
);
|
|
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
|
-
// ../
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
};
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
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: []
|
|
1749
|
+
// CF Workers 需全部打包
|
|
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/
|
|
1264
|
-
|
|
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/
|
|
1267
|
-
function
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
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/
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
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
|
-
"
|
|
1846
|
+
"url"
|
|
1305
1847
|
);
|
|
1306
|
-
const
|
|
1848
|
+
const ssrPath = pathToFileURL(
|
|
1849
|
+
path.resolve(root, "dist/server/ssr.js")
|
|
1850
|
+
).href;
|
|
1851
|
+
const ssrModule = await import(
|
|
1307
1852
|
/* @vite-ignore */
|
|
1308
|
-
|
|
1853
|
+
ssrPath
|
|
1309
1854
|
);
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
1910
|
+
"url"
|
|
1322
1911
|
);
|
|
1323
|
-
|
|
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
|
-
|
|
1929
|
+
routesPath
|
|
1326
1930
|
);
|
|
1327
|
-
|
|
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
|
+
}
|
|
1938
|
+
}
|
|
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
|
|
1946
|
+
);
|
|
1947
|
+
if (paths.length === 0) paths.push("/");
|
|
1328
1948
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1949
|
+
if (opts.dynamicRoutes) {
|
|
1950
|
+
for (const r of opts.dynamicRoutes) {
|
|
1951
|
+
if (!paths.includes(r)) paths.push(r);
|
|
1332
1952
|
}
|
|
1333
|
-
const modulePath = ssrProductionModule ?? "../dist/server/ssr.js";
|
|
1334
|
-
return import(modulePath);
|
|
1335
1953
|
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
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);`
|
|
1360
1982
|
});
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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 });
|
|
1365
2027
|
}
|
|
1366
|
-
console.
|
|
1367
|
-
return c.text("Internal Server Error", 500);
|
|
2028
|
+
console.log(" Vercel output \u2192 .vercel/output/\n");
|
|
1368
2029
|
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
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
|
+
}
|
|
1371
2054
|
}
|
|
1372
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
|
+
};
|
|
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();
|
|
2078
|
+
|
|
1373
2079
|
// ../server/src/create-server.ts
|
|
1374
2080
|
var import_hono3 = require("hono");
|
|
2081
|
+
init_app();
|
|
1375
2082
|
|
|
1376
2083
|
// ../server/src/runtime.ts
|
|
1377
2084
|
function detectRuntime() {
|
|
@@ -1490,7 +2197,15 @@ async function startServer(options) {
|
|
|
1490
2197
|
"path"
|
|
1491
2198
|
);
|
|
1492
2199
|
const prodApp = new import_hono2.Hono();
|
|
1493
|
-
|
|
2200
|
+
const clientDir = resolve(root, "dist/client");
|
|
2201
|
+
prodApp.use(
|
|
2202
|
+
"/*",
|
|
2203
|
+
serveStatic({
|
|
2204
|
+
root: clientDir,
|
|
2205
|
+
// 禁止目录路径自动提供 index.html,让其 fall through 到 SSR
|
|
2206
|
+
rewriteRequestPath: (path) => path.endsWith("/") ? "/__nosuchfile__" : path
|
|
2207
|
+
})
|
|
2208
|
+
);
|
|
1494
2209
|
prodApp.route("/", app);
|
|
1495
2210
|
const { serve } = await import(
|
|
1496
2211
|
/* @vite-ignore */
|
|
@@ -1571,6 +2286,251 @@ async function createServer(config = {}) {
|
|
|
1571
2286
|
});
|
|
1572
2287
|
return { app, vite, runtime };
|
|
1573
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
|
+
}
|
|
1574
2534
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1575
2535
|
0 && (module.exports = {
|
|
1576
2536
|
ACTION_KINDS,
|
|
@@ -1592,7 +2552,9 @@ async function createServer(config = {}) {
|
|
|
1592
2552
|
PrefetchedIntents,
|
|
1593
2553
|
Router,
|
|
1594
2554
|
SSR_PLACEHOLDERS,
|
|
2555
|
+
autoAdapter,
|
|
1595
2556
|
buildUrl,
|
|
2557
|
+
cloudflareAdapter,
|
|
1596
2558
|
createPrefetchedIntentsFromDom,
|
|
1597
2559
|
createSSRApp,
|
|
1598
2560
|
createSSRRender,
|
|
@@ -1600,6 +2562,7 @@ async function createServer(config = {}) {
|
|
|
1600
2562
|
defineRoutes,
|
|
1601
2563
|
deserializeServerData,
|
|
1602
2564
|
detectRuntime,
|
|
2565
|
+
finesoftFrontViteConfig,
|
|
1603
2566
|
generateUuid,
|
|
1604
2567
|
getBaseUrl,
|
|
1605
2568
|
injectSSRContent,
|
|
@@ -1612,6 +2575,8 @@ async function createServer(config = {}) {
|
|
|
1612
2575
|
makeExternalUrlAction,
|
|
1613
2576
|
makeFlowAction,
|
|
1614
2577
|
mapEach,
|
|
2578
|
+
netlifyAdapter,
|
|
2579
|
+
nodeAdapter,
|
|
1615
2580
|
parseAcceptLanguage,
|
|
1616
2581
|
pipe,
|
|
1617
2582
|
pipeAsync,
|
|
@@ -1622,6 +2587,7 @@ async function createServer(config = {}) {
|
|
|
1622
2587
|
removeQueryParams,
|
|
1623
2588
|
removeScheme,
|
|
1624
2589
|
resetFilterCache,
|
|
2590
|
+
resolveAdapter,
|
|
1625
2591
|
resolveRoot,
|
|
1626
2592
|
serializeServerData,
|
|
1627
2593
|
shouldLog,
|
|
@@ -1629,6 +2595,8 @@ async function createServer(config = {}) {
|
|
|
1629
2595
|
stableStringify,
|
|
1630
2596
|
startBrowserApp,
|
|
1631
2597
|
startServer,
|
|
1632
|
-
|
|
2598
|
+
staticAdapter,
|
|
2599
|
+
tryScroll,
|
|
2600
|
+
vercelAdapter
|
|
1633
2601
|
});
|
|
1634
2602
|
//# sourceMappingURL=index.cjs.map
|