@finesoft/front 0.5.1 → 0.5.3

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.
Files changed (128) hide show
  1. package/README.md +4 -4
  2. package/dist/Outlet.svelte +39 -0
  3. package/dist/Outlet.svelte.d.ts +7 -0
  4. package/dist/browser-CR5vhgXg.mjs +1317 -0
  5. package/dist/browser-kFMjlLGT.d.mts +262 -0
  6. package/dist/browser.d.mts +7 -2
  7. package/dist/browser.mjs +9 -1
  8. package/dist/controller-types-CgmJ6-le.d.mts +16 -0
  9. package/dist/cookies-BiRlUanX.d.mts +786 -0
  10. package/dist/fetch-policy-BHT8RtrL.mjs +82 -0
  11. package/dist/host-guard-DDWxLpFL.mjs +222 -0
  12. package/dist/http-B6CJqDyf.d.mts +46 -0
  13. package/dist/http-CaxrMD1A.d.mts +1 -0
  14. package/dist/http-D70PL72H.mjs +257 -0
  15. package/dist/http.d.mts +3 -0
  16. package/dist/http.mjs +2 -0
  17. package/dist/index-node.d.mts +15 -0
  18. package/dist/index-node.mjs +15 -0
  19. package/dist/index.d.mts +48 -697
  20. package/dist/index.mjs +44 -261
  21. package/dist/load-node.d.mts +5 -0
  22. package/dist/load-node.mjs +10 -0
  23. package/dist/load-portable.d.mts +5 -0
  24. package/dist/load-portable.mjs +8 -0
  25. package/dist/lru-map-BKoUAySU.mjs +50 -0
  26. package/dist/messages-CAt2QdGr.mjs +140 -0
  27. package/dist/native-contract-DuR25hYB.d.mts +14 -0
  28. package/dist/native-contract.d.mts +2 -0
  29. package/dist/native-contract.mjs +1 -0
  30. package/dist/node-D9hB4dsz.d.mts +35 -0
  31. package/dist/node.d.mts +2 -0
  32. package/dist/node.mjs +59 -0
  33. package/dist/path-CGFl2w7D.mjs +113 -0
  34. package/dist/path-CXT6xGPO.d.mts +261 -0
  35. package/dist/portable-CaxrMD1A.d.mts +1 -0
  36. package/dist/portable.d.mts +11 -0
  37. package/dist/portable.mjs +12 -0
  38. package/dist/proxy-2dSWO-Xw.d.mts +53 -0
  39. package/dist/proxy-z02VvGIj.mjs +7520 -0
  40. package/dist/public-types-BcJM-AYc.mjs +835 -0
  41. package/dist/react-DhwBRw01.d.mts +16 -0
  42. package/dist/react.d.mts +3 -0
  43. package/dist/react.mjs +29 -0
  44. package/dist/rolldown-runtime-B4iAMlE-.mjs +35 -0
  45. package/dist/secure-fetch-Xlht2jd7.d.mts +30 -0
  46. package/dist/server-controller-proxy-BkVuVWVD.d.mts +38 -0
  47. package/dist/session-DnB4ZC3x.d.mts +1279 -0
  48. package/dist/src-BQBfaaPO.mjs +3825 -0
  49. package/dist/src-Ftl_0rhu.mjs +28 -0
  50. package/dist/ssr-BLzYP4wU.d.mts +207 -0
  51. package/dist/ssr-Tn4YkuxM.mjs +357 -0
  52. package/dist/ssr.d.mts +3 -0
  53. package/dist/ssr.mjs +3 -0
  54. package/dist/svelte-Dr5to3SE.d.mts +16 -0
  55. package/dist/svelte.d.mts +3 -0
  56. package/dist/svelte.mjs +13 -0
  57. package/dist/typegen-C-WeJCtf.d.mts +12 -0
  58. package/dist/typegen-cli.d.mts +1 -0
  59. package/dist/typegen-cli.mjs +11 -0
  60. package/dist/typegen.d.mts +3 -0
  61. package/dist/typegen.mjs +2 -0
  62. package/dist/types-B1BT0N3t.mjs +402 -0
  63. package/dist/undici-CPfL25Hr.mjs +22262 -0
  64. package/dist/vite-Cj4SPA8D.d.mts +277 -0
  65. package/dist/vite.d.mts +4 -0
  66. package/dist/vite.mjs +2354 -0
  67. package/dist/vue-DGmzuKho.d.mts +32 -0
  68. package/dist/vue.d.mts +3 -0
  69. package/dist/vue.mjs +56 -0
  70. package/dist/web.d.mts +6 -0
  71. package/dist/web.mjs +8 -0
  72. package/dist/worker.d.mts +2 -0
  73. package/dist/worker.mjs +2 -0
  74. package/docs/01-getting-started.md +67 -199
  75. package/docs/02-routing-and-controllers.md +163 -241
  76. package/docs/03-middleware.md +10 -212
  77. package/docs/04-rendering-and-hydration.md +7 -332
  78. package/docs/05-i18n.md +7 -237
  79. package/docs/06-http-client.md +20 -263
  80. package/docs/07-di-container.md +23 -257
  81. package/docs/08-observability.md +6 -286
  82. package/docs/09-server-and-deployment.md +59 -219
  83. package/docs/10-features-platform-pwa.md +7 -231
  84. package/docs/11-navigation.md +143 -288
  85. package/docs/12-session-restoration.md +6 -214
  86. package/docs/README.md +7 -7
  87. package/docs/advanced/custom-action-handler.md +29 -229
  88. package/docs/advanced/custom-adapter.md +7 -259
  89. package/docs/advanced/custom-event-recorder.md +7 -312
  90. package/docs/advanced/inline-proxy-codegen.md +6 -185
  91. package/docs/advanced/multi-tenant-scopes.md +10 -323
  92. package/docs/engineering/ci-release-flow.md +35 -222
  93. package/docs/engineering/project-structure.md +34 -277
  94. package/docs/engineering/testing.md +8 -310
  95. package/docs/pitfalls/container-scope-leak.md +2 -214
  96. package/docs/pitfalls/i18n-bundle-size.md +6 -176
  97. package/docs/pitfalls/proxy-binary-payloads.md +8 -12
  98. package/docs/pitfalls/ssr-hydration-mismatch.md +9 -155
  99. package/docs/pitfalls/ssr-vs-csr-globals.md +9 -170
  100. package/docs/zh/01-getting-started.md +67 -199
  101. package/docs/zh/02-routing-and-controllers.md +166 -244
  102. package/docs/zh/03-middleware.md +10 -212
  103. package/docs/zh/04-rendering-and-hydration.md +7 -332
  104. package/docs/zh/05-i18n.md +7 -237
  105. package/docs/zh/06-http-client.md +20 -263
  106. package/docs/zh/07-di-container.md +23 -257
  107. package/docs/zh/08-observability.md +6 -283
  108. package/docs/zh/09-server-and-deployment.md +59 -219
  109. package/docs/zh/10-features-platform-pwa.md +7 -231
  110. package/docs/zh/11-navigation.md +130 -290
  111. package/docs/zh/12-session-restoration.md +6 -214
  112. package/docs/zh/README.md +4 -4
  113. package/docs/zh/advanced/custom-action-handler.md +29 -229
  114. package/docs/zh/advanced/custom-adapter.md +7 -259
  115. package/docs/zh/advanced/custom-event-recorder.md +7 -312
  116. package/docs/zh/advanced/inline-proxy-codegen.md +6 -185
  117. package/docs/zh/advanced/multi-tenant-scopes.md +10 -323
  118. package/docs/zh/engineering/ci-release-flow.md +35 -222
  119. package/docs/zh/engineering/project-structure.md +34 -277
  120. package/docs/zh/engineering/testing.md +8 -310
  121. package/docs/zh/pitfalls/container-scope-leak.md +2 -214
  122. package/docs/zh/pitfalls/i18n-bundle-size.md +6 -176
  123. package/docs/zh/pitfalls/proxy-binary-payloads.md +8 -12
  124. package/docs/zh/pitfalls/ssr-hydration-mismatch.md +9 -155
  125. package/docs/zh/pitfalls/ssr-vs-csr-globals.md +9 -170
  126. package/package.json +118 -20
  127. package/dist/browser-BHhVWXik.mjs +0 -2
  128. package/dist/browser-BV2BBXm7.d.mts +0 -2811
package/dist/vite.mjs ADDED
@@ -0,0 +1,2354 @@
1
+ import { a as isPublicSSRResult, i as matchRenderModeOverride, n as registerProxyRoutes, r as createSSRHandler, t as generateProxyCode } from "./proxy-z02VvGIj.mjs";
2
+ import { r as dynamicImport, t as nodeSafeFetchOptions } from "./fetch-policy-BHT8RtrL.mjs";
3
+ import { n as createControllerTypeWatcher, r as generateControllerTypes, t as generateFrontTypes } from "./public-types-BcJM-AYc.mjs";
4
+ import { createRequire } from "node:module";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { Hono } from "hono";
8
+ //#region ../server/src/adapters/auto.ts
9
+ /**
10
+ * Auto 适配器 — 根据环境变量自动选择目标平台
11
+ *
12
+ * 检测顺序:
13
+ * VERCEL → vercel
14
+ * CF_PAGES → cloudflare
15
+ * NETLIFY → netlify
16
+ * (default) → node
17
+ */
18
+ function autoAdapter() {
19
+ return {
20
+ name: "auto",
21
+ async build(ctx) {
22
+ const detected = detectPlatform();
23
+ console.log(` [auto] Detected platform: ${detected}\n`);
24
+ return resolveAdapter(detected).build(ctx);
25
+ }
26
+ };
27
+ }
28
+ function detectPlatform() {
29
+ if (process.env.VERCEL) return "vercel";
30
+ if (process.env.CF_PAGES) return "cloudflare";
31
+ if (process.env.NETLIFY) return "netlify";
32
+ return "node";
33
+ }
34
+ //#endregion
35
+ //#region ../server/src/adapters/shared.ts
36
+ /**
37
+ * 适配器共享工具函数
38
+ *
39
+ * 提供 generateSSREntry / buildBundle / copyStaticAssets 三个方法,
40
+ * 避免各适配器重复实现相同逻辑。
41
+ */
42
+ const BUILD_TOOL_EXTERNALS = [
43
+ "vite",
44
+ "esbuild",
45
+ "rollup",
46
+ "fsevents",
47
+ "lightningcss"
48
+ ];
49
+ /**
50
+ * Common Node.js built-in modules. Listed explicitly so that Rolldown's
51
+ * vite-resolve plugin does not emit "Automatically externalized" warnings.
52
+ */
53
+ const NODE_BUILTINS = [
54
+ "node:async_hooks",
55
+ "node:buffer",
56
+ "node:crypto",
57
+ "node:fs",
58
+ "node:dns/promises",
59
+ "node:http",
60
+ "node:http2",
61
+ "node:module",
62
+ "node:net",
63
+ "node:os",
64
+ "node:path",
65
+ "node:stream",
66
+ "node:url",
67
+ "node:util",
68
+ "node:zlib",
69
+ "crypto",
70
+ "http",
71
+ "http2",
72
+ "stream"
73
+ ];
74
+ /** Generated hosts compose routing/capabilities; HTML response semantics live in one portable owner. */
75
+ function generateSSREntry(ctx, opts) {
76
+ return `
77
+ import { Hono } from "hono";
78
+ import { createSSRHandler, registerProxyRoutes } from "@finesoft/front";
79
+ ${opts.platformImport}
80
+ ${opts.dnsPolicy === "hostname" ? "" : "import { nodeSafeFetchOptions as _safeFetchOptions } from \"@finesoft/front\";"}
81
+ import { render, serializeServerData } from "./${ctx.ssrEntry}";
82
+ ${ctx.setupPath ? `import _setupDefault from "./${ctx.setupPath}";` : ""}
83
+ const TEMPLATE = ${JSON.stringify(ctx.templateHtml)};
84
+ const RENDER_MODES = ${JSON.stringify(ctx.renderModes ?? {})};
85
+ const DEFAULT_LOCALE = ${JSON.stringify(ctx.defaultLocale ?? null)};
86
+ ${opts.platformCache ?? ""}
87
+ const app = new Hono();
88
+ ${generateProxyCode(ctx.proxies ?? [])}
89
+ ${ctx.setupPath ? "await _setupDefault(app);" : ""}
90
+ ${opts.platformMiddleware ?? ""}
91
+ const ssr = createSSRHandler({
92
+ ownRenderers: true,
93
+ template: TEMPLATE,
94
+ render,
95
+ serializeServerData,
96
+ renderModes: RENDER_MODES,
97
+ defaultLocale: DEFAULT_LOCALE,
98
+ safeFetch: ${opts.dnsPolicy === "hostname" ? "{ validateDns: false }" : "_safeFetchOptions"},
99
+ fetch: (request, bindings) => app.fetch(request, bindings),
100
+ ${opts.platformCache ? "cache: {get: platformCacheGet, set: platformCacheSet}," : ""}
101
+ ${opts.publicCacheHeaders ? `publicCacheHeaders: ${JSON.stringify(opts.publicCacheHeaders)},` : ""}
102
+ });
103
+ app.all("*", c => ssr.fetch(c.req.raw, c.env));
104
+ ${opts.platformExport}
105
+ `;
106
+ }
107
+ /** 用 Vite SSR 模式构建 bundle */
108
+ async function buildBundle(ctx, opts) {
109
+ await ctx.vite.build({
110
+ root: ctx.root,
111
+ build: {
112
+ ssr: opts.entry,
113
+ outDir: opts.outDir,
114
+ emptyOutDir: opts.emptyOutDir ?? true,
115
+ target: opts.target ?? "node18",
116
+ rollupOptions: { output: { entryFileNames: opts.fileName ?? "index.mjs" } }
117
+ },
118
+ ssr: {
119
+ noExternal: opts.noExternal !== false,
120
+ external: [...opts.external ?? BUILD_TOOL_EXTERNALS, ...NODE_BUILTINS]
121
+ },
122
+ resolve: ctx.resolvedResolve,
123
+ css: ctx.resolvedCss
124
+ });
125
+ }
126
+ /** 复制 dist/client 静态资源到目标目录 */
127
+ function copyStaticAssets(ctx, destDir, opts) {
128
+ const { fs, path } = ctx;
129
+ fs.cpSync(path.resolve(ctx.root, "dist/client"), destDir, { recursive: true });
130
+ if (opts?.excludeHtml !== false) fs.rmSync(path.join(destDir, "index.html"), { force: true });
131
+ }
132
+ /** Build a generated platform entry and remove it once Vite has consumed it. */
133
+ async function buildGeneratedEntry(ctx, entry, source, options) {
134
+ const temporaryPath = ctx.path.resolve(ctx.root, entry);
135
+ ctx.fs.writeFileSync(temporaryPath, source);
136
+ try {
137
+ await buildBundle(ctx, {
138
+ ...options,
139
+ entry
140
+ });
141
+ } finally {
142
+ ctx.fs.rmSync(temporaryPath, { force: true });
143
+ }
144
+ }
145
+ /** Materialize prerendered pages with the path layout used by every request-host adapter. */
146
+ function writePrerenderedPages(ctx, outputDir, pages) {
147
+ for (const { url, html } of pages) {
148
+ const file = url === "/" ? ctx.path.join(outputDir, "index.html") : ctx.path.join(outputDir, url, "index.html");
149
+ ctx.fs.mkdirSync(ctx.path.resolve(file, ".."), { recursive: true });
150
+ ctx.fs.writeFileSync(file, html);
151
+ }
152
+ }
153
+ /**
154
+ * 构建时预渲染 prerender 路由。
155
+ *
156
+ * 1. 加载路由定义文件,找出 renderMode === "prerender" 的路由
157
+ * 2. 合并 ctx.renderModes 配置覆盖
158
+ * 3. 渲染每个 URL × locale
159
+ */
160
+ async function prerenderRoutes(ctx) {
161
+ const { fs, path, root } = ctx;
162
+ const { pathToFileURL } = await dynamicImport("node:url");
163
+ const importVersion = ctx.buildId ? `?finesoft-build=${encodeURIComponent(ctx.buildId)}` : "";
164
+ const routes = [];
165
+ const ssrFile = path.resolve(root, "dist/server/ssr.js");
166
+ let ssrModule;
167
+ if (fs.existsSync(ssrFile)) {
168
+ ssrModule = await dynamicImport(pathToFileURL(ssrFile).href + importVersion);
169
+ routes.push(...ssrModule.render.routes ?? []);
170
+ }
171
+ try {
172
+ const prerenderPaths = /* @__PURE__ */ new Set();
173
+ for (const r of routes) if (r.renderMode === "prerender" && r.path && !r.path.includes(":")) prerenderPaths.add(r.path);
174
+ if (ctx.renderModes) {
175
+ for (const [pattern, mode] of Object.entries(ctx.renderModes)) if (mode === "prerender" && !pattern.includes("*") && !pattern.includes(":")) prerenderPaths.add(pattern);
176
+ }
177
+ if (ctx.locales?.length) {
178
+ const basePaths = [...prerenderPaths];
179
+ for (const locale of ctx.locales) for (const basePath of basePaths) {
180
+ const localePath = basePath === "/" ? `/${locale}` : `/${locale}${basePath}`;
181
+ prerenderPaths.add(localePath);
182
+ }
183
+ }
184
+ if (prerenderPaths.size === 0) return [];
185
+ ssrModule ??= await dynamicImport(pathToFileURL(ssrFile).href + importVersion);
186
+ const results = [];
187
+ for (const url of prerenderPaths) try {
188
+ let eligible = false;
189
+ const response = await createSSRHandler({
190
+ template: ctx.templateHtml,
191
+ render: async (path, context) => {
192
+ const result = await ssrModule.render(path, context);
193
+ eligible = isPublicSSRResult(result);
194
+ return result;
195
+ },
196
+ serializeServerData: ssrModule.serializeServerData,
197
+ defaultLocale: ctx.defaultLocale,
198
+ renderModes: ctx.renderModes,
199
+ safeFetch: nodeSafeFetchOptions,
200
+ onError: (error) => console.warn(` [prerender] Failed to render ${url}:`, error)
201
+ }).fetch(new Request(new URL(url, "http://prerender.local")));
202
+ if (eligible && response.status === 200) results.push({
203
+ url,
204
+ html: await response.text()
205
+ });
206
+ } catch (e) {
207
+ console.warn(` [prerender] Failed to render ${url}:`, e);
208
+ }
209
+ if (results.length > 0) console.log(` Pre-rendered ${results.length} pages (${prerenderPaths.size} routes)\n`);
210
+ return results;
211
+ } finally {
212
+ await ssrModule?.render.dispose?.();
213
+ }
214
+ }
215
+ //#endregion
216
+ //#region ../server/src/adapters/cloudflare.ts
217
+ /**
218
+ * Cloudflare Pages 适配器
219
+ *
220
+ * 生成 dist/cloudflare/ 目录:
221
+ * - _worker.js — Workers 入口(Hono 原生支持 CF fetch 接口)
222
+ * - assets/ — 静态资源
223
+ *
224
+ * 注意:Cloudflare Workers 不支持原生 Node.js API。
225
+ * 若 setup 代理使用了 process.env,需在 wrangler.toml 启用 nodejs_compat。
226
+ */
227
+ function cloudflareAdapter() {
228
+ return {
229
+ name: "cloudflare",
230
+ async build(ctx) {
231
+ const { fs, path, root } = ctx;
232
+ const outputDir = path.resolve(root, "dist/cloudflare");
233
+ fs.rmSync(outputDir, {
234
+ recursive: true,
235
+ force: true
236
+ });
237
+ await buildGeneratedEntry(ctx, ".cf-entry.tmp.mjs", generateSSREntry(ctx, {
238
+ dnsPolicy: "hostname",
239
+ platformImport: ``,
240
+ platformExport: `export default app;`,
241
+ platformCache: `
242
+ const ISR_CACHE_TTL = 3600; // 1 hour
243
+ async function platformCacheGet(url) {
244
+ try {
245
+ const cache = caches.default;
246
+ const cacheKey = new Request("https://isr-cache/" + encodeURIComponent(url));
247
+ const resp = await cache.match(cacheKey);
248
+ if (resp) return await resp.text();
249
+ } catch {}
250
+ return null;
251
+ }
252
+ async function platformCacheSet(url, html) {
253
+ try {
254
+ const cache = caches.default;
255
+ const cacheKey = new Request("https://isr-cache/" + encodeURIComponent(url));
256
+ const resp = new Response(html, {
257
+ headers: { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "public, max-age=" + ISR_CACHE_TTL },
258
+ });
259
+ await cache.put(cacheKey, resp);
260
+ } catch {}
261
+ }`
262
+ }), {
263
+ outDir: outputDir,
264
+ target: "es2022",
265
+ fileName: "_worker.js"
266
+ });
267
+ copyStaticAssets(ctx, path.resolve(outputDir, "assets"));
268
+ writePrerenderedPages(ctx, path.resolve(outputDir, "assets"), await prerenderRoutes(ctx));
269
+ console.log(" Cloudflare output → dist/cloudflare/\n");
270
+ }
271
+ };
272
+ }
273
+ //#endregion
274
+ //#region ../server/src/adapters/netlify.ts
275
+ /**
276
+ * Netlify 适配器 — Netlify Functions v2
277
+ *
278
+ * 生成:
279
+ * - .netlify/functions-internal/ssr/index.mjs — Serverless Function
280
+ * - dist/client/_redirects — 路由重写规则
281
+ */
282
+ function netlifyAdapter() {
283
+ return {
284
+ name: "netlify",
285
+ async build(ctx) {
286
+ const { fs, path, root } = ctx;
287
+ const funcDir = path.resolve(root, ".netlify/functions-internal/ssr");
288
+ fs.rmSync(path.resolve(root, ".netlify"), {
289
+ recursive: true,
290
+ force: true
291
+ });
292
+ await buildGeneratedEntry(ctx, ".netlify-entry.tmp.mjs", generateSSREntry(ctx, {
293
+ platformImport: `import { handle } from "hono/netlify";`,
294
+ platformExport: `export default handle(app);
295
+ export const config = { path: "/*", preferStatic: true };`,
296
+ platformCache: `
297
+ const ISR_SWR_TTL = 3600;
298
+ const ISR_CACHE_MAX = 1000;
299
+ const _isrMap = new Map();
300
+ async function platformCacheGet(url) {
301
+ return _isrMap.get(url) ?? null;
302
+ }
303
+ async function platformCacheSet(url, html) {
304
+ if (_isrMap.size >= ISR_CACHE_MAX) {
305
+ const first = _isrMap.keys().next().value;
306
+ _isrMap.delete(first);
307
+ }
308
+ _isrMap.set(url, html);
309
+ }`,
310
+ publicCacheHeaders: { "Netlify-CDN-Cache-Control": "public, max-age=3600, stale-while-revalidate=86400" }
311
+ }), {
312
+ outDir: funcDir,
313
+ target: "node18"
314
+ });
315
+ fs.writeFileSync(path.resolve(root, "dist/client/_redirects"), `/* /.netlify/functions/ssr 200\n`);
316
+ writePrerenderedPages(ctx, path.resolve(root, "dist/client"), await prerenderRoutes(ctx));
317
+ console.log(" Netlify output → .netlify/functions-internal/ssr/\n Publish dir: dist/client/\n");
318
+ }
319
+ };
320
+ }
321
+ //#endregion
322
+ //#region ../server/src/adapters/node.ts
323
+ /**
324
+ * Node 适配器 — 独立 HTTP 服务器
325
+ *
326
+ * 生成 dist/server/index.mjs,使用 @hono/node-server 监听端口。
327
+ * 运行:node dist/server/index.mjs
328
+ */
329
+ function nodeAdapter() {
330
+ return {
331
+ name: "node",
332
+ async build(ctx) {
333
+ const { path, root } = ctx;
334
+ await buildGeneratedEntry(ctx, ".node-entry.tmp.mjs", generateSSREntry(ctx, {
335
+ platformImport: `import { startNodeHandler } from "@finesoft/front";
336
+ import { readFileSync, existsSync } from "node:fs";
337
+ import { resolve, dirname } from "node:path";
338
+ import { fileURLToPath } from "node:url";`,
339
+ platformMiddleware: `
340
+ // 预渲染文件中间件:检查 dist/prerender/ 下是否有对应的静态 HTML
341
+ const __entry_dirname = dirname(fileURLToPath(import.meta.url));
342
+ const prerenderDir = resolve(__entry_dirname, "../prerender");
343
+
344
+ app.use("*", async (c, next) => {
345
+ const urlPath = c.req.path;
346
+ const candidates = [
347
+ resolve(prerenderDir, "." + urlPath, "index.html"),
348
+ resolve(prerenderDir, "." + urlPath + ".html"),
349
+ ];
350
+ if (urlPath === "/") candidates.unshift(resolve(prerenderDir, "index.html"));
351
+ for (const f of candidates) {
352
+ if (existsSync(f)) {
353
+ const html = readFileSync(f, "utf-8");
354
+ return c.html(html);
355
+ }
356
+ }
357
+ await next();
358
+ });
359
+ `,
360
+ platformExport: `
361
+ const port = +(process.env.PORT || 3000);
362
+ const server = await startNodeHandler({ handler: { fetch: async request => app.fetch(request) }, port, disposeApp: ssr.dispose });
363
+ console.log(\`Server running at http://localhost:\${port}\`);
364
+ export { server };
365
+ `
366
+ }), {
367
+ outDir: path.resolve(root, "dist/server"),
368
+ target: "node18",
369
+ emptyOutDir: false
370
+ });
371
+ const prerendered = await prerenderRoutes(ctx);
372
+ writePrerenderedPages(ctx, path.resolve(root, "dist/prerender"), prerendered);
373
+ console.log(" Node output → dist/server/index.mjs\n Run: node dist/server/index.mjs\n");
374
+ }
375
+ };
376
+ }
377
+ //#endregion
378
+ //#region ../server/src/adapters/static.ts
379
+ /** Build static HTML through the same SSR response assembler used by request hosts. */
380
+ function staticAdapter(options = {}) {
381
+ return {
382
+ name: "static",
383
+ async build(context) {
384
+ const { fs, path, root } = context;
385
+ context = {
386
+ ...context,
387
+ buildId: context.buildId ?? crypto.randomUUID()
388
+ };
389
+ const { pathToFileURL } = await dynamicImport("node:url");
390
+ const module = await dynamicImport(`${pathToFileURL(path.resolve(root, "dist/server/ssr.js")).href}?build=${encodeURIComponent(context.buildId)}`);
391
+ const modes = { ...context.renderModes };
392
+ const host = createSSRHandler({
393
+ ownRenderers: true,
394
+ ...module,
395
+ template: context.templateHtml,
396
+ renderModes: modes,
397
+ defaultLocale: context.defaultLocale
398
+ });
399
+ try {
400
+ const routes = await discoverRoutes(context, options, module);
401
+ const urls = /* @__PURE__ */ new Set([...routes.filter((route) => !/[:*]/.test(route.path)).map((route) => route.path), ...options.dynamicRoutes ?? []]);
402
+ if (!urls.size) throw Error("Static build requires at least one concrete route");
403
+ const pages = /* @__PURE__ */ new Map();
404
+ for (const url of urls) {
405
+ if (!url.startsWith("/") || new URL(url, "https://static.local").pathname !== url) throw Error(`Static route must be a normalized pathname: ${url}`);
406
+ const mode = matchRenderModeOverride(url, context.renderModes) ?? routes.find((route) => route.path === url)?.renderMode;
407
+ if (mode) modes[url] = mode;
408
+ const response = await host.fetch(new Request("https://static.local" + url));
409
+ const html = await response.text();
410
+ if (response.status !== 200) throw Error(`Static route ${url} returned HTTP ${response.status}; use a request host for redirects/errors`);
411
+ for (const name of response.headers.keys()) if (name !== "content-type") throw Error(`Static route ${url} requires HTTP header ${name}; configure a request host instead`);
412
+ pages.set(url, html);
413
+ }
414
+ const output = path.resolve(root, "dist/static");
415
+ fs.rmSync(output, {
416
+ recursive: true,
417
+ force: true
418
+ });
419
+ fs.mkdirSync(output, { recursive: true });
420
+ context.copyStaticAssets(output, { excludeHtml: true });
421
+ for (const [url, html] of pages) {
422
+ const file = path.join(output, url, "index.html");
423
+ fs.mkdirSync(path.resolve(file, ".."), { recursive: true });
424
+ fs.writeFileSync(file, html);
425
+ }
426
+ console.log(` Static output → dist/static/ (${pages.size} pages)\n`);
427
+ } finally {
428
+ await host.dispose();
429
+ }
430
+ }
431
+ };
432
+ }
433
+ async function discoverRoutes(context, options, module) {
434
+ if (!options.routesExport) {
435
+ if (!module.render.routes) throw Error("Static renderer must expose routes, or supply routesExport");
436
+ return module.render.routes;
437
+ }
438
+ const output = context.path.resolve(context.root, "dist/server/_routes.mjs");
439
+ try {
440
+ await context.vite.build({
441
+ root: context.root,
442
+ build: {
443
+ ssr: options.routesExport,
444
+ outDir: context.path.resolve(context.root, "dist/server"),
445
+ emptyOutDir: false,
446
+ rollupOptions: { output: { entryFileNames: "_routes.mjs" } }
447
+ },
448
+ resolve: context.resolvedResolve
449
+ });
450
+ const { pathToFileURL } = await dynamicImport("node:url");
451
+ const loaded = await dynamicImport(`${pathToFileURL(output).href}?build=${encodeURIComponent(context.buildId)}`);
452
+ const routes = loaded.routes ?? loaded.app?.routes ?? loaded.default?.routes ?? loaded.default;
453
+ if (!Array.isArray(routes)) throw Error("routesExport must expose a route array or Web definition");
454
+ return routes;
455
+ } finally {
456
+ context.fs.rmSync(output, { force: true });
457
+ }
458
+ }
459
+ //#endregion
460
+ //#region ../server/src/adapters/vercel.ts
461
+ /**
462
+ * Vercel 适配器 — Build Output API v3
463
+ *
464
+ * 生成 .vercel/output/ 目录:
465
+ * - config.json — 路由规则
466
+ * - static/ — 静态资源
467
+ * - functions/ssr.func/ — Serverless Function
468
+ */
469
+ function vercelAdapter() {
470
+ return {
471
+ name: "vercel",
472
+ async build(ctx) {
473
+ const { fs, path, root } = ctx;
474
+ const outputDir = path.resolve(root, ".vercel/output");
475
+ fs.rmSync(outputDir, {
476
+ recursive: true,
477
+ force: true
478
+ });
479
+ const entrySource = generateSSREntry(ctx, {
480
+ platformImport: `import { getRequestListener } from "@hono/node-server";`,
481
+ platformExport: [
482
+ `const _listener = getRequestListener(app.fetch);`,
483
+ `export default (req, res) => {`,
484
+ ` const m = req.headers["x-now-route-matches"];`,
485
+ ` if (typeof m === "string") {`,
486
+ ` try {`,
487
+ ` const p = new URLSearchParams(m);`,
488
+ ` const c = p.get("1");`,
489
+ ` if (c != null) {`,
490
+ ` const qi = (req.url || "").indexOf("?");`,
491
+ ` const qs = qi !== -1 ? req.url.slice(qi) : "";`,
492
+ ` req.url = "/" + decodeURIComponent(c) + qs;`,
493
+ ` }`,
494
+ ` } catch {}`,
495
+ ` }`,
496
+ ` return _listener(req, res);`,
497
+ `};`
498
+ ].join("\n")
499
+ });
500
+ const funcDir = path.resolve(root, ".vercel/output/functions/ssr.func");
501
+ await buildGeneratedEntry(ctx, ".vercel-entry.tmp.mjs", entrySource, {
502
+ outDir: funcDir,
503
+ target: "node18"
504
+ });
505
+ fs.writeFileSync(path.resolve(funcDir, ".vc-config.json"), JSON.stringify({
506
+ runtime: "nodejs20.x",
507
+ handler: "index.mjs",
508
+ launcherType: "Nodejs"
509
+ }, null, 2));
510
+ copyStaticAssets(ctx, path.resolve(root, ".vercel/output/static"));
511
+ fs.writeFileSync(path.resolve(root, ".vercel/output/config.json"), JSON.stringify({
512
+ version: 3,
513
+ routes: [{ handle: "filesystem" }, {
514
+ src: "/(.*)",
515
+ dest: "/ssr"
516
+ }]
517
+ }, null, 2));
518
+ const prerendered = await prerenderRoutes(ctx);
519
+ writePrerenderedPages(ctx, path.resolve(root, ".vercel/output/static"), prerendered);
520
+ if (prerendered.length > 0) {
521
+ const configPath = path.resolve(root, ".vercel/output/config.json");
522
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
523
+ config.overrides = config.overrides ?? {};
524
+ for (const { url } of prerendered) {
525
+ const key = url === "/" ? "index.html" : `${url.replace(/^\//, "")}/index.html`;
526
+ config.overrides[key] = {
527
+ path: url === "/" ? "/" : url,
528
+ contentType: "text/html; charset=utf-8"
529
+ };
530
+ }
531
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
532
+ }
533
+ console.log(" Vercel output → .vercel/output/\n");
534
+ }
535
+ };
536
+ }
537
+ //#endregion
538
+ //#region ../server/src/adapters/resolve.ts
539
+ /**
540
+ * resolveAdapter — 字符串 → Adapter 映射
541
+ */
542
+ function resolveAdapter(value) {
543
+ if (typeof value !== "string") return value;
544
+ switch (value) {
545
+ case "vercel": return vercelAdapter();
546
+ case "cloudflare": return cloudflareAdapter();
547
+ case "netlify": return netlifyAdapter();
548
+ case "node": return nodeAdapter();
549
+ case "static": return staticAdapter();
550
+ case "auto": return autoAdapter();
551
+ default: throw new Error(`[finesoft] Unknown adapter: "${value}". Available: vercel, cloudflare, netlify, node, static, auto`);
552
+ }
553
+ }
554
+ //#endregion
555
+ //#region ../server/src/app.ts
556
+ function createSSRApp(options) {
557
+ const { root, vite, ssrEntryPath = "/src/ssr.ts", parentFetch, renderModes, defaultLocale } = options;
558
+ const app = new Hono();
559
+ const owner = createSSRHandler({
560
+ ownRenderers: true,
561
+ template: async (request) => {
562
+ const { readFileSync } = await dynamicImport("node:fs");
563
+ const raw = readFileSync((await dynamicImport("node:path")).resolve(root, "index.html"), "utf-8");
564
+ const url = new URL(request.url);
565
+ return vite.transformIndexHtml(url.pathname + url.search, raw);
566
+ },
567
+ loadModule: async () => await vite.ssrLoadModule(ssrEntryPath),
568
+ renderModes,
569
+ defaultLocale,
570
+ fetch: parentFetch,
571
+ safeFetch: nodeSafeFetchOptions,
572
+ onError: (error) => {
573
+ vite.ssrFixStacktrace(error);
574
+ console.error("[SSR Error]", error);
575
+ }
576
+ });
577
+ app.all("*", (context) => owner.fetch(context.req.raw, context.env));
578
+ return Object.assign(app, { dispose: owner.dispose });
579
+ }
580
+ //#endregion
581
+ //#region ../server/src/server-controller-plugin.ts
582
+ const serverEntries = /* @__PURE__ */ new Set(["@finesoft/ssr"]);
583
+ /** Class inheritance is the boundary. No directory names or application module execution are involved. */
584
+ function serverControllerModules(getRoot) {
585
+ let compiler;
586
+ const sources = /* @__PURE__ */ new Map();
587
+ const privateFiles = /* @__PURE__ */ new Set();
588
+ const pending = /* @__PURE__ */ new Set();
589
+ let initialized = false;
590
+ let indexing;
591
+ const getCompiler = () => compiler ??= createRequire(path.join(getRoot(), "package.json"))("typescript");
592
+ const read = (file) => {
593
+ if (!path.isAbsolute(file) || file.includes("\0") || !/\.[cm]?[jt]sx?$/.test(file) || file.includes("/node_modules/")) return;
594
+ const stat = fs.statSync(file, { throwIfNoEntry: false });
595
+ if (!stat?.isFile()) return;
596
+ const stamp = `${stat.mtimeMs}:${stat.size}`;
597
+ const old = sources.get(file);
598
+ if (old?.stamp === stamp) return old.source;
599
+ const source = getCompiler().createSourceFile(file, fs.readFileSync(file, "utf8"), getCompiler().ScriptTarget.Latest, true);
600
+ sources.set(file, {
601
+ stamp,
602
+ source
603
+ });
604
+ return source;
605
+ };
606
+ const has = (node, kind) => getCompiler().canHaveModifiers(node) && getCompiler().getModifiers(node)?.some((m) => m.kind === kind);
607
+ async function exported(context, specifier, importer, name, seen) {
608
+ if (specifier === "@finesoft/front" || serverEntries.has(specifier)) return name === "BaseServerController";
609
+ if (specifier.startsWith("@finesoft/")) return false;
610
+ const resolved = await context.resolve(specifier, importer, { skipSelf: true });
611
+ if (!resolved) return false;
612
+ const file = resolved.id.split("?")[0];
613
+ const key = `${file}#${name}`;
614
+ if (seen.has(key)) return false;
615
+ seen.add(key);
616
+ const source = read(file);
617
+ if (!source) return false;
618
+ context.addWatchFile(file);
619
+ const c = getCompiler();
620
+ for (const statement of source.statements) {
621
+ if (c.isClassDeclaration(statement) && has(statement, c.SyntaxKind.ExportKeyword)) {
622
+ if ((has(statement, c.SyntaxKind.DefaultKeyword) ? "default" : statement.name?.text) === name) return serverClass(context, source, statement, seen);
623
+ }
624
+ if (c.isExportDeclaration(statement) && !statement.isTypeOnly) {
625
+ const module = statement.moduleSpecifier && c.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : void 0;
626
+ if (!statement.exportClause && module && await exported(context, module, file, name, new Set(seen))) return true;
627
+ if (statement.exportClause && c.isNamedExports(statement.exportClause)) for (const item of statement.exportClause.elements) {
628
+ if (item.isTypeOnly || item.name.text !== name) continue;
629
+ const local = (item.propertyName ?? item.name).text;
630
+ return module ? exported(context, module, file, local, seen) : identifier(context, source, local, seen);
631
+ }
632
+ }
633
+ if (name === "default" && c.isExportAssignment(statement)) return expression(context, source, statement.expression, seen);
634
+ }
635
+ return false;
636
+ }
637
+ async function identifier(context, source, name, seen) {
638
+ const key = `${source.fileName}:local:${name}`;
639
+ if (seen.has(key)) return false;
640
+ seen.add(key);
641
+ const c = getCompiler();
642
+ for (const statement of source.statements) {
643
+ if (c.isClassDeclaration(statement) && statement.name?.text === name) return serverClass(context, source, statement, seen);
644
+ if (c.isVariableStatement(statement)) {
645
+ for (const item of statement.declarationList.declarations) if (c.isIdentifier(item.name) && item.name.text === name && item.initializer) return expression(context, source, item.initializer, seen);
646
+ }
647
+ if (!c.isImportDeclaration(statement) || !c.isStringLiteral(statement.moduleSpecifier) || statement.importClause?.isTypeOnly) continue;
648
+ const clause = statement.importClause;
649
+ if (clause?.name?.text === name) return exported(context, statement.moduleSpecifier.text, source.fileName, "default", seen);
650
+ if (clause?.namedBindings && c.isNamedImports(clause.namedBindings)) {
651
+ for (const item of clause.namedBindings.elements) if (!item.isTypeOnly && item.name.text === name) return exported(context, statement.moduleSpecifier.text, source.fileName, (item.propertyName ?? item.name).text, seen);
652
+ }
653
+ }
654
+ return false;
655
+ }
656
+ async function expression(context, source, node, seen) {
657
+ const c = getCompiler();
658
+ if (c.isIdentifier(node)) return identifier(context, source, node.text, seen);
659
+ if (c.isPropertyAccessExpression(node) && c.isIdentifier(node.expression)) for (const statement of source.statements) {
660
+ if (!c.isImportDeclaration(statement) || !c.isStringLiteral(statement.moduleSpecifier)) continue;
661
+ const binding = statement.importClause?.namedBindings;
662
+ if (binding && c.isNamespaceImport(binding) && binding.name.text === node.expression.text) return exported(context, statement.moduleSpecifier.text, source.fileName, node.name.text, seen);
663
+ }
664
+ if (c.isClassExpression(node)) return serverClass(context, source, node, seen);
665
+ if (c.isCallExpression(node)) {
666
+ if (await expression(context, source, node.expression, new Set(seen))) return true;
667
+ for (const argument of node.arguments) if (await expression(context, source, argument, new Set(seen))) return true;
668
+ }
669
+ return false;
670
+ }
671
+ async function serverClass(context, source, node, seen) {
672
+ const base = node.heritageClauses?.find((clause) => clause.token === getCompiler().SyntaxKind.ExtendsKeyword)?.types[0];
673
+ return !!base && expression(context, source, base.expression, seen);
674
+ }
675
+ async function protectDependencies(context, file, seen = /* @__PURE__ */ new Set()) {
676
+ if (seen.has(file)) return;
677
+ seen.add(file);
678
+ const source = read(file);
679
+ if (!source) return;
680
+ const c = getCompiler();
681
+ const specifiers = /* @__PURE__ */ new Set();
682
+ const visit = (node) => {
683
+ if (c.isImportDeclaration(node) && !node.importClause?.isTypeOnly && c.isStringLiteral(node.moduleSpecifier)) {
684
+ const bindings = node.importClause?.namedBindings;
685
+ if (!(bindings && c.isNamedImports(bindings) && !node.importClause?.name && bindings.elements.every((item) => item.isTypeOnly))) specifiers.add(node.moduleSpecifier.text);
686
+ } else if (c.isExportDeclaration(node) && !node.isTypeOnly && node.moduleSpecifier && c.isStringLiteral(node.moduleSpecifier)) specifiers.add(node.moduleSpecifier.text);
687
+ else if (c.isCallExpression(node) && (node.expression.kind === c.SyntaxKind.ImportKeyword || c.isIdentifier(node.expression) && node.expression.text === "require")) {
688
+ if (node.arguments[0] && c.isStringLiteral(node.arguments[0])) specifiers.add(node.arguments[0].text);
689
+ }
690
+ c.forEachChild(node, visit);
691
+ };
692
+ visit(source);
693
+ for (const specifier of specifiers) {
694
+ if (specifier.startsWith("@finesoft/") || specifier.startsWith("node:")) continue;
695
+ const dependency = (await context.resolve(specifier, file, { skipSelf: true }))?.id.split("?")[0];
696
+ if (!dependency || !path.isAbsolute(dependency) || dependency.includes("/node_modules/")) continue;
697
+ privateFiles.add(dependency);
698
+ context.addWatchFile(dependency);
699
+ await protectDependencies(context, dependency, seen);
700
+ }
701
+ }
702
+ async function index(context) {
703
+ if (indexing) await indexing;
704
+ if (!initialized) {
705
+ initialized = true;
706
+ const walk = (directory) => {
707
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
708
+ if (entry.name.startsWith(".") || [
709
+ "node_modules",
710
+ "dist",
711
+ "reports"
712
+ ].includes(entry.name)) continue;
713
+ const file = path.join(directory, entry.name);
714
+ if (entry.isDirectory()) walk(file);
715
+ else if (entry.isFile() && /\.[cm]?[jt]sx?$/.test(file)) pending.add(file);
716
+ }
717
+ };
718
+ walk(getRoot());
719
+ }
720
+ if (!pending.size) return;
721
+ indexing = (async () => {
722
+ const c = getCompiler();
723
+ for (const file of pending) {
724
+ pending.delete(file);
725
+ const source = read(file);
726
+ if (!source) continue;
727
+ if (privateFiles.has(file) || (await Promise.all(source.statements.filter(c.isClassDeclaration).map((node) => serverClass(context, source, node, /* @__PURE__ */ new Set())))).some(Boolean)) await protectDependencies(context, file);
728
+ }
729
+ })();
730
+ try {
731
+ await indexing;
732
+ } finally {
733
+ indexing = void 0;
734
+ }
735
+ }
736
+ return {
737
+ async start(context) {
738
+ if (context.environment?.config?.consumer !== "server") await index(context);
739
+ },
740
+ async load(context, id, ssr) {
741
+ if (ssr || context.environment?.config?.consumer === "server") return null;
742
+ const file = id.split("?")[0];
743
+ if (!path.isAbsolute(file) || file.includes("\0")) return null;
744
+ await index(context);
745
+ const source = read(file);
746
+ if (!source) {
747
+ if (privateFiles.has(file)) throw Error(`Server controller dependency cannot be loaded by the browser: ${file}`);
748
+ return null;
749
+ }
750
+ const c = getCompiler();
751
+ const names = /* @__PURE__ */ new Map();
752
+ for (const statement of source.statements) if (c.isClassDeclaration(statement) && await serverClass(context, source, statement, /* @__PURE__ */ new Set())) {
753
+ const name = statement.name?.text ?? "__ServerController";
754
+ names.set(name, name);
755
+ }
756
+ if (!names.size) {
757
+ if (privateFiles.has(file)) throw Error(`Server controller dependency cannot be loaded by the browser: ${file}`);
758
+ return null;
759
+ }
760
+ await protectDependencies(context, file);
761
+ if ([...new URLSearchParams(id.split("?")[1]).keys()].some((key) => ![
762
+ "t",
763
+ "v",
764
+ "import"
765
+ ].includes(key))) throw Error(`Server controller source cannot be loaded as an asset: ${file}`);
766
+ const exports = [];
767
+ for (const statement of source.statements) {
768
+ if (c.isInterfaceDeclaration(statement) || c.isTypeAliasDeclaration(statement)) continue;
769
+ if (c.isClassDeclaration(statement) && has(statement, c.SyntaxKind.ExportKeyword)) {
770
+ const name = statement.name?.text ?? "__ServerController";
771
+ if (!names.has(name)) throw Error(`Server controller modules cannot export shared implementations: ${file}`);
772
+ exports.push(has(statement, c.SyntaxKind.DefaultKeyword) ? `export default ${name};` : `export { ${name} };`);
773
+ } else if (c.isExportDeclaration(statement) && !statement.isTypeOnly) {
774
+ if (statement.moduleSpecifier || !statement.exportClause || !c.isNamedExports(statement.exportClause)) throw Error(`Move re-exports out of the server controller implementation module: ${file}`);
775
+ for (const item of statement.exportClause.elements) {
776
+ if (item.isTypeOnly) continue;
777
+ const name = (item.propertyName ?? item.name).text;
778
+ if (!names.has(name)) throw Error(`Server controller modules can only export controllers and types: ${file}`);
779
+ exports.push(`export { ${name} as ${item.name.text} };`);
780
+ }
781
+ } else if (c.isExportAssignment(statement)) {
782
+ if (!c.isIdentifier(statement.expression) || !names.has(statement.expression.text)) throw Error(`Invalid server controller default export: ${file}`);
783
+ exports.push(`export default ${statement.expression.text};`);
784
+ } else if (has(statement, c.SyntaxKind.ExportKeyword)) throw Error(`Server controller modules can only export controllers and types: ${file}`);
785
+ }
786
+ return {
787
+ code: `import { ServerControllerProxy as __Proxy } from "@finesoft/front";\n${[...names].map(([name]) => `class ${name} extends __Proxy {}`).join("\n")}\n${exports.join("\n")}`,
788
+ map: {
789
+ version: 3,
790
+ sources: [],
791
+ names: [],
792
+ mappings: "",
793
+ sourcesContent: []
794
+ }
795
+ };
796
+ },
797
+ guard(id, ssr, context) {
798
+ if (!ssr && context?.environment?.config?.consumer !== "server" && serverEntries.has(id)) throw Error("The SSR entry is server-only. Import BaseServerController only in a controller implementation module; the Vite plugin generates its browser reference.");
799
+ },
800
+ invalidate(file) {
801
+ sources.delete(file);
802
+ pending.add(file);
803
+ }
804
+ };
805
+ }
806
+ //#endregion
807
+ //#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
808
+ var comma = ",".charCodeAt(0);
809
+ var semicolon = ";".charCodeAt(0);
810
+ var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
811
+ var intToChar = /* @__PURE__ */ new Uint8Array(64);
812
+ var charToInt = /* @__PURE__ */ new Uint8Array(128);
813
+ for (let i = 0; i < chars.length; i++) {
814
+ const c = chars.charCodeAt(i);
815
+ intToChar[i] = c;
816
+ charToInt[c] = i;
817
+ }
818
+ function encodeInteger(builder, num, relative) {
819
+ let delta = num - relative;
820
+ delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
821
+ do {
822
+ let clamped = delta & 31;
823
+ delta >>>= 5;
824
+ if (delta > 0) clamped |= 32;
825
+ builder.write(intToChar[clamped]);
826
+ } while (delta > 0);
827
+ return num;
828
+ }
829
+ var bufLength = 16384;
830
+ var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? { decode(buf) {
831
+ return Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength).toString();
832
+ } } : { decode(buf) {
833
+ let out = "";
834
+ for (let i = 0; i < buf.length; i++) out += String.fromCharCode(buf[i]);
835
+ return out;
836
+ } };
837
+ var StringWriter = class {
838
+ constructor() {
839
+ this.pos = 0;
840
+ this.out = "";
841
+ this.buffer = new Uint8Array(bufLength);
842
+ }
843
+ write(v) {
844
+ const { buffer } = this;
845
+ buffer[this.pos++] = v;
846
+ if (this.pos === bufLength) {
847
+ this.out += td.decode(buffer);
848
+ this.pos = 0;
849
+ }
850
+ }
851
+ flush() {
852
+ const { buffer, out, pos } = this;
853
+ return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
854
+ }
855
+ };
856
+ function encode(decoded) {
857
+ const writer = new StringWriter();
858
+ let sourcesIndex = 0;
859
+ let sourceLine = 0;
860
+ let sourceColumn = 0;
861
+ let namesIndex = 0;
862
+ for (let i = 0; i < decoded.length; i++) {
863
+ const line = decoded[i];
864
+ if (i > 0) writer.write(semicolon);
865
+ if (line.length === 0) continue;
866
+ let genColumn = 0;
867
+ for (let j = 0; j < line.length; j++) {
868
+ const segment = line[j];
869
+ if (j > 0) writer.write(comma);
870
+ genColumn = encodeInteger(writer, segment[0], genColumn);
871
+ if (segment.length === 1) continue;
872
+ sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
873
+ sourceLine = encodeInteger(writer, segment[2], sourceLine);
874
+ sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
875
+ if (segment.length === 4) continue;
876
+ namesIndex = encodeInteger(writer, segment[4], namesIndex);
877
+ }
878
+ }
879
+ return writer.flush();
880
+ }
881
+ //#endregion
882
+ //#region ../../node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.mjs
883
+ var BitSet = class BitSet {
884
+ constructor(arg) {
885
+ this.bits = arg instanceof BitSet ? arg.bits.slice() : [];
886
+ }
887
+ add(n) {
888
+ this.bits[n >> 5] |= 1 << (n & 31);
889
+ }
890
+ has(n) {
891
+ return !!(this.bits[n >> 5] & 1 << (n & 31));
892
+ }
893
+ };
894
+ var Chunk = class Chunk {
895
+ constructor(start, end, content) {
896
+ this.start = start;
897
+ this.end = end;
898
+ this.original = content;
899
+ this.intro = "";
900
+ this.outro = "";
901
+ this.content = content;
902
+ this.storeName = false;
903
+ this.edited = false;
904
+ this.previous = null;
905
+ this.next = null;
906
+ }
907
+ appendLeft(content) {
908
+ this.outro += content;
909
+ }
910
+ appendRight(content) {
911
+ this.intro = this.intro + content;
912
+ }
913
+ clone() {
914
+ const chunk = new Chunk(this.start, this.end, this.original);
915
+ chunk.intro = this.intro;
916
+ chunk.outro = this.outro;
917
+ chunk.content = this.content;
918
+ chunk.storeName = this.storeName;
919
+ chunk.edited = this.edited;
920
+ return chunk;
921
+ }
922
+ contains(index) {
923
+ return this.start < index && index < this.end;
924
+ }
925
+ eachNext(fn) {
926
+ let chunk = this;
927
+ while (chunk) {
928
+ fn(chunk);
929
+ chunk = chunk.next;
930
+ }
931
+ }
932
+ eachPrevious(fn) {
933
+ let chunk = this;
934
+ while (chunk) {
935
+ fn(chunk);
936
+ chunk = chunk.previous;
937
+ }
938
+ }
939
+ edit(content, storeName, contentOnly) {
940
+ this.content = content;
941
+ if (!contentOnly) {
942
+ this.intro = "";
943
+ this.outro = "";
944
+ }
945
+ this.storeName = storeName;
946
+ this.edited = true;
947
+ return this;
948
+ }
949
+ prependLeft(content) {
950
+ this.outro = content + this.outro;
951
+ }
952
+ prependRight(content) {
953
+ this.intro = content + this.intro;
954
+ }
955
+ reset() {
956
+ this.intro = "";
957
+ this.outro = "";
958
+ if (this.edited) {
959
+ this.content = this.original;
960
+ this.storeName = false;
961
+ this.edited = false;
962
+ }
963
+ }
964
+ split(index) {
965
+ const sliceIndex = index - this.start;
966
+ const originalBefore = this.original.slice(0, sliceIndex);
967
+ const originalAfter = this.original.slice(sliceIndex);
968
+ this.original = originalBefore;
969
+ const newChunk = new Chunk(index, this.end, originalAfter);
970
+ newChunk.outro = this.outro;
971
+ this.outro = "";
972
+ this.end = index;
973
+ if (this.edited) {
974
+ newChunk.edit("", false);
975
+ this.content = "";
976
+ } else this.content = originalBefore;
977
+ newChunk.next = this.next;
978
+ if (newChunk.next) newChunk.next.previous = newChunk;
979
+ newChunk.previous = this;
980
+ this.next = newChunk;
981
+ return newChunk;
982
+ }
983
+ toString() {
984
+ return this.intro + this.content + this.outro;
985
+ }
986
+ trimEnd(rx) {
987
+ this.outro = this.outro.replace(rx, "");
988
+ if (this.outro.length) return true;
989
+ const trimmed = this.content.replace(rx, "");
990
+ if (trimmed.length) {
991
+ if (trimmed !== this.content) {
992
+ this.split(this.start + trimmed.length).edit("", void 0, true);
993
+ if (this.edited) this.edit(trimmed, this.storeName, true);
994
+ }
995
+ return true;
996
+ } else {
997
+ this.edit("", void 0, true);
998
+ this.intro = this.intro.replace(rx, "");
999
+ if (this.intro.length) return true;
1000
+ }
1001
+ }
1002
+ trimStart(rx) {
1003
+ this.intro = this.intro.replace(rx, "");
1004
+ if (this.intro.length) return true;
1005
+ const trimmed = this.content.replace(rx, "");
1006
+ if (trimmed.length) {
1007
+ if (trimmed !== this.content) {
1008
+ const newChunk = this.split(this.end - trimmed.length);
1009
+ if (this.edited) newChunk.edit(trimmed, this.storeName, true);
1010
+ this.edit("", void 0, true);
1011
+ }
1012
+ return true;
1013
+ } else {
1014
+ this.edit("", void 0, true);
1015
+ this.outro = this.outro.replace(rx, "");
1016
+ if (this.outro.length) return true;
1017
+ }
1018
+ }
1019
+ };
1020
+ function getBtoa() {
1021
+ if (typeof globalThis !== "undefined" && typeof globalThis.btoa === "function") return (str) => globalThis.btoa(unescape(encodeURIComponent(str)));
1022
+ else if (typeof Buffer === "function") return (str) => Buffer.from(str, "utf-8").toString("base64");
1023
+ else return () => {
1024
+ throw new Error("Unsupported environment: `window.btoa` or `Buffer` should be supported.");
1025
+ };
1026
+ }
1027
+ const btoa = /*#__PURE__*/ getBtoa();
1028
+ var SourceMap = class {
1029
+ constructor(properties) {
1030
+ this.version = 3;
1031
+ this.file = properties.file;
1032
+ this.sources = properties.sources;
1033
+ this.sourcesContent = properties.sourcesContent;
1034
+ this.names = properties.names;
1035
+ this.mappings = encode(properties.mappings);
1036
+ if (typeof properties.x_google_ignoreList !== "undefined") this.x_google_ignoreList = properties.x_google_ignoreList;
1037
+ if (typeof properties.debugId !== "undefined") this.debugId = properties.debugId;
1038
+ }
1039
+ toString() {
1040
+ return JSON.stringify(this);
1041
+ }
1042
+ toUrl() {
1043
+ return "data:application/json;charset=utf-8;base64," + btoa(this.toString());
1044
+ }
1045
+ };
1046
+ function guessIndent(code) {
1047
+ const lines = code.split("\n");
1048
+ const tabbed = lines.filter((line) => /^\t+/.test(line));
1049
+ const spaced = lines.filter((line) => /^ {2,}/.test(line));
1050
+ if (tabbed.length === 0 && spaced.length === 0) return null;
1051
+ if (tabbed.length >= spaced.length) return " ";
1052
+ const min = spaced.reduce((previous, current) => {
1053
+ const numSpaces = /^ +/.exec(current)[0].length;
1054
+ return Math.min(numSpaces, previous);
1055
+ }, Infinity);
1056
+ return new Array(min + 1).join(" ");
1057
+ }
1058
+ function getRelativePath(from, to) {
1059
+ const fromParts = from.split(/[/\\]/);
1060
+ const toParts = to.split(/[/\\]/);
1061
+ fromParts.pop();
1062
+ while (fromParts[0] === toParts[0]) {
1063
+ fromParts.shift();
1064
+ toParts.shift();
1065
+ }
1066
+ if (fromParts.length) {
1067
+ let i = fromParts.length;
1068
+ while (i--) fromParts[i] = "..";
1069
+ }
1070
+ return fromParts.concat(toParts).join("/");
1071
+ }
1072
+ const toString = Object.prototype.toString;
1073
+ function isObject(thing) {
1074
+ return toString.call(thing) === "[object Object]";
1075
+ }
1076
+ function getLocator(source) {
1077
+ const originalLines = source.split("\n");
1078
+ const lineOffsets = [];
1079
+ for (let i = 0, pos = 0; i < originalLines.length; i++) {
1080
+ lineOffsets.push(pos);
1081
+ pos += originalLines[i].length + 1;
1082
+ }
1083
+ return function locate(index) {
1084
+ let i = 0;
1085
+ let j = lineOffsets.length;
1086
+ while (i < j) {
1087
+ const m = i + j >> 1;
1088
+ if (index < lineOffsets[m]) j = m;
1089
+ else i = m + 1;
1090
+ }
1091
+ const line = i - 1;
1092
+ return {
1093
+ line,
1094
+ column: index - lineOffsets[line]
1095
+ };
1096
+ };
1097
+ }
1098
+ const wordRegex = /\w/;
1099
+ var Mappings = class {
1100
+ constructor(hires) {
1101
+ this.hires = hires;
1102
+ this.generatedCodeLine = 0;
1103
+ this.generatedCodeColumn = 0;
1104
+ this.raw = [];
1105
+ this.rawSegments = this.raw[this.generatedCodeLine] = [];
1106
+ this.pending = null;
1107
+ }
1108
+ addEdit(sourceIndex, content, loc, nameIndex) {
1109
+ if (content.length) {
1110
+ const contentLengthMinusOne = content.length - 1;
1111
+ let contentLineEnd = content.indexOf("\n", 0);
1112
+ let previousContentLineEnd = -1;
1113
+ while (contentLineEnd >= 0 && contentLengthMinusOne > contentLineEnd) {
1114
+ const segment = [
1115
+ this.generatedCodeColumn,
1116
+ sourceIndex,
1117
+ loc.line,
1118
+ loc.column
1119
+ ];
1120
+ if (nameIndex >= 0) segment.push(nameIndex);
1121
+ this.rawSegments.push(segment);
1122
+ this.generatedCodeLine += 1;
1123
+ this.raw[this.generatedCodeLine] = this.rawSegments = [];
1124
+ this.generatedCodeColumn = 0;
1125
+ previousContentLineEnd = contentLineEnd;
1126
+ contentLineEnd = content.indexOf("\n", contentLineEnd + 1);
1127
+ }
1128
+ const segment = [
1129
+ this.generatedCodeColumn,
1130
+ sourceIndex,
1131
+ loc.line,
1132
+ loc.column
1133
+ ];
1134
+ if (nameIndex >= 0) segment.push(nameIndex);
1135
+ this.rawSegments.push(segment);
1136
+ this.advance(content.slice(previousContentLineEnd + 1));
1137
+ } else if (this.pending) {
1138
+ this.rawSegments.push(this.pending);
1139
+ this.advance(content);
1140
+ }
1141
+ this.pending = null;
1142
+ }
1143
+ addUneditedChunk(sourceIndex, chunk, original, loc, sourcemapLocations) {
1144
+ let originalCharIndex = chunk.start;
1145
+ let first = true;
1146
+ let charInHiresBoundary = false;
1147
+ while (originalCharIndex < chunk.end) {
1148
+ if (original[originalCharIndex] === "\n") {
1149
+ loc.line += 1;
1150
+ loc.column = 0;
1151
+ this.generatedCodeLine += 1;
1152
+ this.raw[this.generatedCodeLine] = this.rawSegments = [];
1153
+ this.generatedCodeColumn = 0;
1154
+ first = true;
1155
+ charInHiresBoundary = false;
1156
+ } else {
1157
+ if (this.hires || first || sourcemapLocations.has(originalCharIndex)) {
1158
+ const segment = [
1159
+ this.generatedCodeColumn,
1160
+ sourceIndex,
1161
+ loc.line,
1162
+ loc.column
1163
+ ];
1164
+ if (this.hires === "boundary") if (wordRegex.test(original[originalCharIndex])) {
1165
+ if (!charInHiresBoundary) {
1166
+ this.rawSegments.push(segment);
1167
+ charInHiresBoundary = true;
1168
+ }
1169
+ } else {
1170
+ this.rawSegments.push(segment);
1171
+ charInHiresBoundary = false;
1172
+ }
1173
+ else this.rawSegments.push(segment);
1174
+ }
1175
+ loc.column += 1;
1176
+ this.generatedCodeColumn += 1;
1177
+ first = false;
1178
+ }
1179
+ originalCharIndex += 1;
1180
+ }
1181
+ this.pending = null;
1182
+ }
1183
+ advance(str) {
1184
+ if (!str) return;
1185
+ const lines = str.split("\n");
1186
+ if (lines.length > 1) {
1187
+ for (let i = 0; i < lines.length - 1; i++) {
1188
+ this.generatedCodeLine++;
1189
+ this.raw[this.generatedCodeLine] = this.rawSegments = [];
1190
+ }
1191
+ this.generatedCodeColumn = 0;
1192
+ }
1193
+ this.generatedCodeColumn += lines[lines.length - 1].length;
1194
+ }
1195
+ };
1196
+ const n = "\n";
1197
+ const warned = {
1198
+ insertLeft: false,
1199
+ insertRight: false,
1200
+ storeName: false
1201
+ };
1202
+ var MagicString = class MagicString {
1203
+ constructor(string, options = {}) {
1204
+ const chunk = new Chunk(0, string.length, string);
1205
+ Object.defineProperties(this, {
1206
+ original: {
1207
+ writable: true,
1208
+ value: string
1209
+ },
1210
+ outro: {
1211
+ writable: true,
1212
+ value: ""
1213
+ },
1214
+ intro: {
1215
+ writable: true,
1216
+ value: ""
1217
+ },
1218
+ firstChunk: {
1219
+ writable: true,
1220
+ value: chunk
1221
+ },
1222
+ lastChunk: {
1223
+ writable: true,
1224
+ value: chunk
1225
+ },
1226
+ lastSearchedChunk: {
1227
+ writable: true,
1228
+ value: chunk
1229
+ },
1230
+ byStart: {
1231
+ writable: true,
1232
+ value: {}
1233
+ },
1234
+ byEnd: {
1235
+ writable: true,
1236
+ value: {}
1237
+ },
1238
+ filename: {
1239
+ writable: true,
1240
+ value: options.filename
1241
+ },
1242
+ indentExclusionRanges: {
1243
+ writable: true,
1244
+ value: options.indentExclusionRanges
1245
+ },
1246
+ sourcemapLocations: {
1247
+ writable: true,
1248
+ value: new BitSet()
1249
+ },
1250
+ storedNames: {
1251
+ writable: true,
1252
+ value: {}
1253
+ },
1254
+ indentStr: {
1255
+ writable: true,
1256
+ value: void 0
1257
+ },
1258
+ ignoreList: {
1259
+ writable: true,
1260
+ value: options.ignoreList
1261
+ },
1262
+ offset: {
1263
+ writable: true,
1264
+ value: options.offset || 0
1265
+ }
1266
+ });
1267
+ this.byStart[0] = chunk;
1268
+ this.byEnd[string.length] = chunk;
1269
+ }
1270
+ addSourcemapLocation(char) {
1271
+ this.sourcemapLocations.add(char);
1272
+ }
1273
+ append(content) {
1274
+ if (typeof content !== "string") throw new TypeError("outro content must be a string");
1275
+ this.outro += content;
1276
+ return this;
1277
+ }
1278
+ appendLeft(index, content) {
1279
+ index = index + this.offset;
1280
+ if (typeof content !== "string") throw new TypeError("inserted content must be a string");
1281
+ this._split(index);
1282
+ const chunk = this.byEnd[index];
1283
+ if (chunk) chunk.appendLeft(content);
1284
+ else this.intro += content;
1285
+ return this;
1286
+ }
1287
+ appendRight(index, content) {
1288
+ index = index + this.offset;
1289
+ if (typeof content !== "string") throw new TypeError("inserted content must be a string");
1290
+ this._split(index);
1291
+ const chunk = this.byStart[index];
1292
+ if (chunk) chunk.appendRight(content);
1293
+ else this.outro += content;
1294
+ return this;
1295
+ }
1296
+ clone() {
1297
+ const cloned = new MagicString(this.original, {
1298
+ filename: this.filename,
1299
+ offset: this.offset
1300
+ });
1301
+ let originalChunk = this.firstChunk;
1302
+ let clonedChunk = cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone();
1303
+ while (originalChunk) {
1304
+ cloned.byStart[clonedChunk.start] = clonedChunk;
1305
+ cloned.byEnd[clonedChunk.end] = clonedChunk;
1306
+ const nextOriginalChunk = originalChunk.next;
1307
+ const nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();
1308
+ if (nextClonedChunk) {
1309
+ clonedChunk.next = nextClonedChunk;
1310
+ nextClonedChunk.previous = clonedChunk;
1311
+ clonedChunk = nextClonedChunk;
1312
+ }
1313
+ originalChunk = nextOriginalChunk;
1314
+ }
1315
+ cloned.lastChunk = clonedChunk;
1316
+ if (this.indentExclusionRanges) cloned.indentExclusionRanges = this.indentExclusionRanges.slice();
1317
+ cloned.sourcemapLocations = new BitSet(this.sourcemapLocations);
1318
+ cloned.intro = this.intro;
1319
+ cloned.outro = this.outro;
1320
+ return cloned;
1321
+ }
1322
+ generateDecodedMap(options) {
1323
+ options = options || {};
1324
+ const sourceIndex = 0;
1325
+ const names = Object.keys(this.storedNames);
1326
+ const mappings = new Mappings(options.hires);
1327
+ const locate = getLocator(this.original);
1328
+ if (this.intro) mappings.advance(this.intro);
1329
+ this.firstChunk.eachNext((chunk) => {
1330
+ const loc = locate(chunk.start);
1331
+ if (chunk.intro.length) mappings.advance(chunk.intro);
1332
+ if (chunk.edited) mappings.addEdit(sourceIndex, chunk.content, loc, chunk.storeName ? names.indexOf(chunk.original) : -1);
1333
+ else mappings.addUneditedChunk(sourceIndex, chunk, this.original, loc, this.sourcemapLocations);
1334
+ if (chunk.outro.length) mappings.advance(chunk.outro);
1335
+ });
1336
+ if (this.outro) mappings.advance(this.outro);
1337
+ return {
1338
+ file: options.file ? options.file.split(/[/\\]/).pop() : void 0,
1339
+ sources: [options.source ? getRelativePath(options.file || "", options.source) : options.file || ""],
1340
+ sourcesContent: options.includeContent ? [this.original] : void 0,
1341
+ names,
1342
+ mappings: mappings.raw,
1343
+ x_google_ignoreList: this.ignoreList ? [sourceIndex] : void 0
1344
+ };
1345
+ }
1346
+ generateMap(options) {
1347
+ return new SourceMap(this.generateDecodedMap(options));
1348
+ }
1349
+ _ensureindentStr() {
1350
+ if (this.indentStr === void 0) this.indentStr = guessIndent(this.original);
1351
+ }
1352
+ _getRawIndentString() {
1353
+ this._ensureindentStr();
1354
+ return this.indentStr;
1355
+ }
1356
+ getIndentString() {
1357
+ this._ensureindentStr();
1358
+ return this.indentStr === null ? " " : this.indentStr;
1359
+ }
1360
+ indent(indentStr, options) {
1361
+ const pattern = /^[^\r\n]/gm;
1362
+ if (isObject(indentStr)) {
1363
+ options = indentStr;
1364
+ indentStr = void 0;
1365
+ }
1366
+ if (indentStr === void 0) {
1367
+ this._ensureindentStr();
1368
+ indentStr = this.indentStr || " ";
1369
+ }
1370
+ if (indentStr === "") return this;
1371
+ options = options || {};
1372
+ const isExcluded = {};
1373
+ if (options.exclude) (typeof options.exclude[0] === "number" ? [options.exclude] : options.exclude).forEach((exclusion) => {
1374
+ for (let i = exclusion[0]; i < exclusion[1]; i += 1) isExcluded[i] = true;
1375
+ });
1376
+ let shouldIndentNextCharacter = options.indentStart !== false;
1377
+ const replacer = (match) => {
1378
+ if (shouldIndentNextCharacter) return `${indentStr}${match}`;
1379
+ shouldIndentNextCharacter = true;
1380
+ return match;
1381
+ };
1382
+ this.intro = this.intro.replace(pattern, replacer);
1383
+ let charIndex = 0;
1384
+ let chunk = this.firstChunk;
1385
+ while (chunk) {
1386
+ const end = chunk.end;
1387
+ if (chunk.edited) {
1388
+ if (!isExcluded[charIndex]) {
1389
+ chunk.content = chunk.content.replace(pattern, replacer);
1390
+ if (chunk.content.length) shouldIndentNextCharacter = chunk.content[chunk.content.length - 1] === "\n";
1391
+ }
1392
+ } else {
1393
+ charIndex = chunk.start;
1394
+ while (charIndex < end) {
1395
+ if (!isExcluded[charIndex]) {
1396
+ const char = this.original[charIndex];
1397
+ if (char === "\n") shouldIndentNextCharacter = true;
1398
+ else if (char !== "\r" && shouldIndentNextCharacter) {
1399
+ shouldIndentNextCharacter = false;
1400
+ if (charIndex === chunk.start) chunk.prependRight(indentStr);
1401
+ else {
1402
+ this._splitChunk(chunk, charIndex);
1403
+ chunk = chunk.next;
1404
+ chunk.prependRight(indentStr);
1405
+ }
1406
+ }
1407
+ }
1408
+ charIndex += 1;
1409
+ }
1410
+ }
1411
+ charIndex = chunk.end;
1412
+ chunk = chunk.next;
1413
+ }
1414
+ this.outro = this.outro.replace(pattern, replacer);
1415
+ return this;
1416
+ }
1417
+ insert() {
1418
+ throw new Error("magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)");
1419
+ }
1420
+ insertLeft(index, content) {
1421
+ if (!warned.insertLeft) {
1422
+ console.warn("magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead");
1423
+ warned.insertLeft = true;
1424
+ }
1425
+ return this.appendLeft(index, content);
1426
+ }
1427
+ insertRight(index, content) {
1428
+ if (!warned.insertRight) {
1429
+ console.warn("magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead");
1430
+ warned.insertRight = true;
1431
+ }
1432
+ return this.prependRight(index, content);
1433
+ }
1434
+ move(start, end, index) {
1435
+ start = start + this.offset;
1436
+ end = end + this.offset;
1437
+ index = index + this.offset;
1438
+ if (index >= start && index <= end) throw new Error("Cannot move a selection inside itself");
1439
+ this._split(start);
1440
+ this._split(end);
1441
+ this._split(index);
1442
+ const first = this.byStart[start];
1443
+ const last = this.byEnd[end];
1444
+ const oldLeft = first.previous;
1445
+ const oldRight = last.next;
1446
+ const newRight = this.byStart[index];
1447
+ if (!newRight && last === this.lastChunk) return this;
1448
+ const newLeft = newRight ? newRight.previous : this.lastChunk;
1449
+ if (oldLeft) oldLeft.next = oldRight;
1450
+ if (oldRight) oldRight.previous = oldLeft;
1451
+ if (newLeft) newLeft.next = first;
1452
+ if (newRight) newRight.previous = last;
1453
+ if (!first.previous) this.firstChunk = last.next;
1454
+ if (!last.next) {
1455
+ this.lastChunk = first.previous;
1456
+ this.lastChunk.next = null;
1457
+ }
1458
+ first.previous = newLeft;
1459
+ last.next = newRight || null;
1460
+ if (!newLeft) this.firstChunk = first;
1461
+ if (!newRight) this.lastChunk = last;
1462
+ return this;
1463
+ }
1464
+ overwrite(start, end, content, options) {
1465
+ options = options || {};
1466
+ return this.update(start, end, content, {
1467
+ ...options,
1468
+ overwrite: !options.contentOnly
1469
+ });
1470
+ }
1471
+ update(start, end, content, options) {
1472
+ start = start + this.offset;
1473
+ end = end + this.offset;
1474
+ if (typeof content !== "string") throw new TypeError("replacement content must be a string");
1475
+ if (this.original.length !== 0) {
1476
+ while (start < 0) start += this.original.length;
1477
+ while (end < 0) end += this.original.length;
1478
+ }
1479
+ if (end > this.original.length) throw new Error("end is out of bounds");
1480
+ if (start === end) throw new Error("Cannot overwrite a zero-length range – use appendLeft or prependRight instead");
1481
+ this._split(start);
1482
+ this._split(end);
1483
+ if (options === true) {
1484
+ if (!warned.storeName) {
1485
+ console.warn("The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string");
1486
+ warned.storeName = true;
1487
+ }
1488
+ options = { storeName: true };
1489
+ }
1490
+ const storeName = options !== void 0 ? options.storeName : false;
1491
+ const overwrite = options !== void 0 ? options.overwrite : false;
1492
+ if (storeName) {
1493
+ const original = this.original.slice(start, end);
1494
+ Object.defineProperty(this.storedNames, original, {
1495
+ writable: true,
1496
+ value: true,
1497
+ enumerable: true
1498
+ });
1499
+ }
1500
+ const first = this.byStart[start];
1501
+ const last = this.byEnd[end];
1502
+ if (first) {
1503
+ let chunk = first;
1504
+ while (chunk !== last) {
1505
+ if (chunk.next !== this.byStart[chunk.end]) throw new Error("Cannot overwrite across a split point");
1506
+ chunk = chunk.next;
1507
+ chunk.edit("", false);
1508
+ }
1509
+ first.edit(content, storeName, !overwrite);
1510
+ } else {
1511
+ const newChunk = new Chunk(start, end, "").edit(content, storeName);
1512
+ last.next = newChunk;
1513
+ newChunk.previous = last;
1514
+ }
1515
+ return this;
1516
+ }
1517
+ prepend(content) {
1518
+ if (typeof content !== "string") throw new TypeError("outro content must be a string");
1519
+ this.intro = content + this.intro;
1520
+ return this;
1521
+ }
1522
+ prependLeft(index, content) {
1523
+ index = index + this.offset;
1524
+ if (typeof content !== "string") throw new TypeError("inserted content must be a string");
1525
+ this._split(index);
1526
+ const chunk = this.byEnd[index];
1527
+ if (chunk) chunk.prependLeft(content);
1528
+ else this.intro = content + this.intro;
1529
+ return this;
1530
+ }
1531
+ prependRight(index, content) {
1532
+ index = index + this.offset;
1533
+ if (typeof content !== "string") throw new TypeError("inserted content must be a string");
1534
+ this._split(index);
1535
+ const chunk = this.byStart[index];
1536
+ if (chunk) chunk.prependRight(content);
1537
+ else this.outro = content + this.outro;
1538
+ return this;
1539
+ }
1540
+ remove(start, end) {
1541
+ start = start + this.offset;
1542
+ end = end + this.offset;
1543
+ if (this.original.length !== 0) {
1544
+ while (start < 0) start += this.original.length;
1545
+ while (end < 0) end += this.original.length;
1546
+ }
1547
+ if (start === end) return this;
1548
+ if (start < 0 || end > this.original.length) throw new Error("Character is out of bounds");
1549
+ if (start > end) throw new Error("end must be greater than start");
1550
+ this._split(start);
1551
+ this._split(end);
1552
+ let chunk = this.byStart[start];
1553
+ while (chunk) {
1554
+ chunk.intro = "";
1555
+ chunk.outro = "";
1556
+ chunk.edit("");
1557
+ chunk = end > chunk.end ? this.byStart[chunk.end] : null;
1558
+ }
1559
+ return this;
1560
+ }
1561
+ reset(start, end) {
1562
+ start = start + this.offset;
1563
+ end = end + this.offset;
1564
+ if (this.original.length !== 0) {
1565
+ while (start < 0) start += this.original.length;
1566
+ while (end < 0) end += this.original.length;
1567
+ }
1568
+ if (start === end) return this;
1569
+ if (start < 0 || end > this.original.length) throw new Error("Character is out of bounds");
1570
+ if (start > end) throw new Error("end must be greater than start");
1571
+ this._split(start);
1572
+ this._split(end);
1573
+ let chunk = this.byStart[start];
1574
+ while (chunk) {
1575
+ chunk.reset();
1576
+ chunk = end > chunk.end ? this.byStart[chunk.end] : null;
1577
+ }
1578
+ return this;
1579
+ }
1580
+ lastChar() {
1581
+ if (this.outro.length) return this.outro[this.outro.length - 1];
1582
+ let chunk = this.lastChunk;
1583
+ do {
1584
+ if (chunk.outro.length) return chunk.outro[chunk.outro.length - 1];
1585
+ if (chunk.content.length) return chunk.content[chunk.content.length - 1];
1586
+ if (chunk.intro.length) return chunk.intro[chunk.intro.length - 1];
1587
+ } while (chunk = chunk.previous);
1588
+ if (this.intro.length) return this.intro[this.intro.length - 1];
1589
+ return "";
1590
+ }
1591
+ lastLine() {
1592
+ let lineIndex = this.outro.lastIndexOf(n);
1593
+ if (lineIndex !== -1) return this.outro.substr(lineIndex + 1);
1594
+ let lineStr = this.outro;
1595
+ let chunk = this.lastChunk;
1596
+ do {
1597
+ if (chunk.outro.length > 0) {
1598
+ lineIndex = chunk.outro.lastIndexOf(n);
1599
+ if (lineIndex !== -1) return chunk.outro.substr(lineIndex + 1) + lineStr;
1600
+ lineStr = chunk.outro + lineStr;
1601
+ }
1602
+ if (chunk.content.length > 0) {
1603
+ lineIndex = chunk.content.lastIndexOf(n);
1604
+ if (lineIndex !== -1) return chunk.content.substr(lineIndex + 1) + lineStr;
1605
+ lineStr = chunk.content + lineStr;
1606
+ }
1607
+ if (chunk.intro.length > 0) {
1608
+ lineIndex = chunk.intro.lastIndexOf(n);
1609
+ if (lineIndex !== -1) return chunk.intro.substr(lineIndex + 1) + lineStr;
1610
+ lineStr = chunk.intro + lineStr;
1611
+ }
1612
+ } while (chunk = chunk.previous);
1613
+ lineIndex = this.intro.lastIndexOf(n);
1614
+ if (lineIndex !== -1) return this.intro.substr(lineIndex + 1) + lineStr;
1615
+ return this.intro + lineStr;
1616
+ }
1617
+ slice(start = 0, end = this.original.length - this.offset) {
1618
+ start = start + this.offset;
1619
+ end = end + this.offset;
1620
+ if (this.original.length !== 0) {
1621
+ while (start < 0) start += this.original.length;
1622
+ while (end < 0) end += this.original.length;
1623
+ }
1624
+ let result = "";
1625
+ let chunk = this.firstChunk;
1626
+ while (chunk && (chunk.start > start || chunk.end <= start)) {
1627
+ if (chunk.start < end && chunk.end >= end) return result;
1628
+ chunk = chunk.next;
1629
+ }
1630
+ if (chunk && chunk.edited && chunk.start !== start) throw new Error(`Cannot use replaced character ${start} as slice start anchor.`);
1631
+ const startChunk = chunk;
1632
+ while (chunk) {
1633
+ if (chunk.intro && (startChunk !== chunk || chunk.start === start)) result += chunk.intro;
1634
+ const containsEnd = chunk.start < end && chunk.end >= end;
1635
+ if (containsEnd && chunk.edited && chunk.end !== end) throw new Error(`Cannot use replaced character ${end} as slice end anchor.`);
1636
+ const sliceStart = startChunk === chunk ? start - chunk.start : 0;
1637
+ const sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;
1638
+ result += chunk.content.slice(sliceStart, sliceEnd);
1639
+ if (chunk.outro && (!containsEnd || chunk.end === end)) result += chunk.outro;
1640
+ if (containsEnd) break;
1641
+ chunk = chunk.next;
1642
+ }
1643
+ return result;
1644
+ }
1645
+ snip(start, end) {
1646
+ const clone = this.clone();
1647
+ clone.remove(0, start);
1648
+ clone.remove(end, clone.original.length);
1649
+ return clone;
1650
+ }
1651
+ _split(index) {
1652
+ if (this.byStart[index] || this.byEnd[index]) return;
1653
+ let chunk = this.lastSearchedChunk;
1654
+ let previousChunk = chunk;
1655
+ const searchForward = index > chunk.end;
1656
+ while (chunk) {
1657
+ if (chunk.contains(index)) return this._splitChunk(chunk, index);
1658
+ chunk = searchForward ? this.byStart[chunk.end] : this.byEnd[chunk.start];
1659
+ if (chunk === previousChunk) return;
1660
+ previousChunk = chunk;
1661
+ }
1662
+ }
1663
+ _splitChunk(chunk, index) {
1664
+ if (chunk.edited && chunk.content.length) {
1665
+ const loc = getLocator(this.original)(index);
1666
+ throw new Error(`Cannot split a chunk that has already been edited (${loc.line}:${loc.column} – "${chunk.original}")`);
1667
+ }
1668
+ const newChunk = chunk.split(index);
1669
+ this.byEnd[index] = chunk;
1670
+ this.byStart[index] = newChunk;
1671
+ this.byEnd[newChunk.end] = newChunk;
1672
+ if (chunk === this.lastChunk) this.lastChunk = newChunk;
1673
+ this.lastSearchedChunk = chunk;
1674
+ return true;
1675
+ }
1676
+ toString() {
1677
+ let str = this.intro;
1678
+ let chunk = this.firstChunk;
1679
+ while (chunk) {
1680
+ str += chunk.toString();
1681
+ chunk = chunk.next;
1682
+ }
1683
+ return str + this.outro;
1684
+ }
1685
+ isEmpty() {
1686
+ let chunk = this.firstChunk;
1687
+ do
1688
+ if (chunk.intro.length && chunk.intro.trim() || chunk.content.length && chunk.content.trim() || chunk.outro.length && chunk.outro.trim()) return false;
1689
+ while (chunk = chunk.next);
1690
+ return true;
1691
+ }
1692
+ length() {
1693
+ let chunk = this.firstChunk;
1694
+ let length = 0;
1695
+ do
1696
+ length += chunk.intro.length + chunk.content.length + chunk.outro.length;
1697
+ while (chunk = chunk.next);
1698
+ return length;
1699
+ }
1700
+ trimLines() {
1701
+ return this.trim("[\\r\\n]");
1702
+ }
1703
+ trim(charType) {
1704
+ return this.trimStart(charType).trimEnd(charType);
1705
+ }
1706
+ trimEndAborted(charType) {
1707
+ const rx = new RegExp((charType || "\\s") + "+$");
1708
+ this.outro = this.outro.replace(rx, "");
1709
+ if (this.outro.length) return true;
1710
+ let chunk = this.lastChunk;
1711
+ do {
1712
+ const end = chunk.end;
1713
+ const aborted = chunk.trimEnd(rx);
1714
+ if (chunk.end !== end) {
1715
+ if (this.lastChunk === chunk) this.lastChunk = chunk.next;
1716
+ this.byEnd[chunk.end] = chunk;
1717
+ this.byStart[chunk.next.start] = chunk.next;
1718
+ this.byEnd[chunk.next.end] = chunk.next;
1719
+ }
1720
+ if (aborted) return true;
1721
+ chunk = chunk.previous;
1722
+ } while (chunk);
1723
+ return false;
1724
+ }
1725
+ trimEnd(charType) {
1726
+ this.trimEndAborted(charType);
1727
+ return this;
1728
+ }
1729
+ trimStartAborted(charType) {
1730
+ const rx = new RegExp("^" + (charType || "\\s") + "+");
1731
+ this.intro = this.intro.replace(rx, "");
1732
+ if (this.intro.length) return true;
1733
+ let chunk = this.firstChunk;
1734
+ do {
1735
+ const end = chunk.end;
1736
+ const aborted = chunk.trimStart(rx);
1737
+ if (chunk.end !== end) {
1738
+ if (chunk === this.lastChunk) this.lastChunk = chunk.next;
1739
+ this.byEnd[chunk.end] = chunk;
1740
+ this.byStart[chunk.next.start] = chunk.next;
1741
+ this.byEnd[chunk.next.end] = chunk.next;
1742
+ }
1743
+ if (aborted) return true;
1744
+ chunk = chunk.next;
1745
+ } while (chunk);
1746
+ return false;
1747
+ }
1748
+ trimStart(charType) {
1749
+ this.trimStartAborted(charType);
1750
+ return this;
1751
+ }
1752
+ hasChanged() {
1753
+ return this.original !== this.toString();
1754
+ }
1755
+ _replaceRegexp(searchValue, replacement) {
1756
+ function getReplacement(match, str) {
1757
+ if (typeof replacement === "string") return replacement.replace(/\$(\$|&|\d+)/g, (_, i) => {
1758
+ if (i === "$") return "$";
1759
+ if (i === "&") return match[0];
1760
+ if (+i < match.length) return match[+i];
1761
+ return `$${i}`;
1762
+ });
1763
+ else return replacement(...match, match.index, str, match.groups);
1764
+ }
1765
+ function matchAll(re, str) {
1766
+ let match;
1767
+ const matches = [];
1768
+ while (match = re.exec(str)) matches.push(match);
1769
+ return matches;
1770
+ }
1771
+ if (searchValue.global) matchAll(searchValue, this.original).forEach((match) => {
1772
+ if (match.index != null) {
1773
+ const replacement = getReplacement(match, this.original);
1774
+ if (replacement !== match[0]) this.overwrite(match.index, match.index + match[0].length, replacement);
1775
+ }
1776
+ });
1777
+ else {
1778
+ const match = this.original.match(searchValue);
1779
+ if (match && match.index != null) {
1780
+ const replacement = getReplacement(match, this.original);
1781
+ if (replacement !== match[0]) this.overwrite(match.index, match.index + match[0].length, replacement);
1782
+ }
1783
+ }
1784
+ return this;
1785
+ }
1786
+ _replaceString(string, replacement) {
1787
+ const { original } = this;
1788
+ const index = original.indexOf(string);
1789
+ if (index !== -1) {
1790
+ if (typeof replacement === "function") replacement = replacement(string, index, original);
1791
+ if (string !== replacement) this.overwrite(index, index + string.length, replacement);
1792
+ }
1793
+ return this;
1794
+ }
1795
+ replace(searchValue, replacement) {
1796
+ if (typeof searchValue === "string") return this._replaceString(searchValue, replacement);
1797
+ return this._replaceRegexp(searchValue, replacement);
1798
+ }
1799
+ _replaceAllString(string, replacement) {
1800
+ const { original } = this;
1801
+ const stringLength = string.length;
1802
+ for (let index = original.indexOf(string); index !== -1; index = original.indexOf(string, index + stringLength)) {
1803
+ const previous = original.slice(index, index + stringLength);
1804
+ let _replacement = replacement;
1805
+ if (typeof replacement === "function") _replacement = replacement(previous, index, original);
1806
+ if (previous !== _replacement) this.overwrite(index, index + stringLength, _replacement);
1807
+ }
1808
+ return this;
1809
+ }
1810
+ replaceAll(searchValue, replacement) {
1811
+ if (typeof searchValue === "string") return this._replaceAllString(searchValue, replacement);
1812
+ if (!searchValue.global) throw new TypeError("MagicString.prototype.replaceAll called with a non-global RegExp argument");
1813
+ return this._replaceRegexp(searchValue, replacement);
1814
+ }
1815
+ };
1816
+ //#endregion
1817
+ //#region ../server/src/native-bindings.ts
1818
+ const PREFIX = "virtual:finesoft-front/native/";
1819
+ const renderers = /* @__PURE__ */ new Set([
1820
+ "react",
1821
+ "vue",
1822
+ "svelte"
1823
+ ]);
1824
+ const selectors = /* @__PURE__ */ new Set(["Outlet", "useSnapshot"]);
1825
+ function scriptBlocks(code, id, require) {
1826
+ const file = id.split("?")[0];
1827
+ if (file.endsWith(".vue") && code.includes("<script")) {
1828
+ const parsed = require("vue/compiler-sfc").parse(code, { filename: id });
1829
+ if (parsed.errors.length) throw parsed.errors[0];
1830
+ return [parsed.descriptor.script, parsed.descriptor.scriptSetup].filter((block) => !!block).map((block) => ({
1831
+ start: block.loc.start.offset,
1832
+ end: block.loc.end.offset,
1833
+ tsx: block.lang === "tsx"
1834
+ }));
1835
+ }
1836
+ if (file.endsWith(".svelte") && code.includes("<script")) {
1837
+ const parsed = require("svelte/compiler").parse(code, {
1838
+ filename: id,
1839
+ modern: true
1840
+ });
1841
+ return [parsed.module?.content, parsed.instance?.content].filter((block) => !!block);
1842
+ }
1843
+ return [{
1844
+ start: 0,
1845
+ end: code.length,
1846
+ tsx: /\.[jt]sx(?:\?|$)/.test(id)
1847
+ }];
1848
+ }
1849
+ /** Compile literal renderer selections to native imports, without a runtime registry. */
1850
+ function nativeBindings(getRoot) {
1851
+ let compiler;
1852
+ return {
1853
+ resolve(id, importer) {
1854
+ if (!id.startsWith(PREFIX)) return null;
1855
+ const renderer = id.slice(30);
1856
+ if (!renderers.has(renderer)) throw Error(`Unknown native renderer: ${renderer}`);
1857
+ const from = importer && path.isAbsolute(importer) ? importer.split("?")[0] : path.join(getRoot(), "package.json");
1858
+ const front = createRequire(from).resolve("@finesoft/front");
1859
+ return path.join(path.dirname(front), `${renderer}.mjs`);
1860
+ },
1861
+ transform(code, id) {
1862
+ if (!code.includes("@finesoft/front") || !/Outlet|useSnapshot/.test(code)) return null;
1863
+ const require = createRequire(path.join(getRoot(), "package.json"));
1864
+ const c = compiler ??= require("typescript");
1865
+ const output = new MagicString(code);
1866
+ let changed = false;
1867
+ const compile = (code, offset, tsx) => {
1868
+ const fileName = `${id}.${offset}.${tsx ? "tsx" : "ts"}`;
1869
+ const source = c.createSourceFile(fileName, code, c.ScriptTarget.Latest, true, tsx ? c.ScriptKind.TSX : c.ScriptKind.TS);
1870
+ const checker = c.createProgram([fileName], {
1871
+ noResolve: true,
1872
+ noLib: true,
1873
+ allowJs: true
1874
+ }, {
1875
+ getSourceFile: (name) => name === fileName ? source : void 0,
1876
+ getDefaultLibFileName: () => "",
1877
+ writeFile() {},
1878
+ getCurrentDirectory: getRoot,
1879
+ getDirectories: () => [],
1880
+ fileExists: (name) => name === fileName,
1881
+ readFile: (name) => name === fileName ? code : void 0,
1882
+ getCanonicalFileName: (name) => name,
1883
+ useCaseSensitiveFileNames: () => true,
1884
+ getNewLine: () => "\n"
1885
+ }).getTypeChecker();
1886
+ const named = /* @__PURE__ */ new Map();
1887
+ const namespaces = /* @__PURE__ */ new Set();
1888
+ const imports = [];
1889
+ for (const statement of source.statements) {
1890
+ if (!c.isImportDeclaration(statement) || statement.importClause?.isTypeOnly || !c.isStringLiteral(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@finesoft/front") continue;
1891
+ const bindings = statement.importClause?.namedBindings;
1892
+ if (!bindings) continue;
1893
+ if (c.isNamespaceImport(bindings)) {
1894
+ const symbol = checker.getSymbolAtLocation(bindings.name);
1895
+ if (symbol) namespaces.add(symbol);
1896
+ } else {
1897
+ for (const item of bindings.elements) {
1898
+ if (item.isTypeOnly) continue;
1899
+ const name = (item.propertyName ?? item.name).text;
1900
+ const symbol = checker.getSymbolAtLocation(item.name);
1901
+ if (selectors.has(name) && symbol) named.set(symbol, name);
1902
+ }
1903
+ imports.push(statement);
1904
+ }
1905
+ }
1906
+ if (!named.size && !namespaces.size) return null;
1907
+ const nativeImports = /* @__PURE__ */ new Map();
1908
+ const bindingFor = (node) => {
1909
+ if (c.isIdentifier(node)) {
1910
+ const symbol = checker.getSymbolAtLocation(node);
1911
+ if (symbol) return named.get(symbol);
1912
+ }
1913
+ if (c.isPropertyAccessExpression(node) && c.isIdentifier(node.expression)) {
1914
+ const symbol = checker.getSymbolAtLocation(node.expression);
1915
+ if (symbol && namespaces.has(symbol) && selectors.has(node.name.text)) return node.name.text;
1916
+ }
1917
+ };
1918
+ const visit = (node) => {
1919
+ if (c.isImportDeclaration(node) || c.isTypeNode(node)) return;
1920
+ const binding = bindingFor(node);
1921
+ if (binding) {
1922
+ const call = node.parent;
1923
+ if (!c.isCallExpression(call) || call.expression !== node) throw Error(`[finesoft] Call ${binding} directly with a literal renderer name (${id}).`);
1924
+ const renderer = call.arguments[0];
1925
+ if (!renderer || !c.isStringLiteral(renderer) || !renderers.has(renderer.text) || call.arguments.length !== (binding === "Outlet" ? 1 : 2)) throw Error(`[finesoft] Use ${binding}("react" | "vue" | "svelte"${binding === "useSnapshot" ? ", app" : ""}) (${id}).`);
1926
+ const key = `${renderer.text}/${binding}`;
1927
+ let local = nativeImports.get(key);
1928
+ if (!local) {
1929
+ local = binding === "useSnapshot" ? `useFinesoftSnapshot${offset}_${nativeImports.size}` : `__finesoft_native_${offset}_${nativeImports.size}`;
1930
+ while (code.includes(local)) local += "_";
1931
+ nativeImports.set(key, local);
1932
+ }
1933
+ if (binding === "Outlet") output.overwrite(offset + call.getStart(source), offset + call.end, local);
1934
+ else {
1935
+ output.overwrite(offset + node.getStart(source), offset + node.end, local);
1936
+ output.remove(offset + renderer.getStart(source), offset + call.arguments[1].getStart(source));
1937
+ }
1938
+ return;
1939
+ }
1940
+ c.forEachChild(node, visit);
1941
+ };
1942
+ visit(source);
1943
+ if (!nativeImports.size) return null;
1944
+ for (const declaration of imports) {
1945
+ const clause = declaration.importClause;
1946
+ const names = clause.namedBindings.elements.filter((item) => item.isTypeOnly || !selectors.has((item.propertyName ?? item.name).text)).map((item) => item.getText(source)).join(", ");
1947
+ const parts = [clause.name?.text, names && `{ ${names} }`].filter(Boolean);
1948
+ output.overwrite(offset + declaration.getStart(source), offset + declaration.end, parts.length ? `import ${parts.join(", ")} from "@finesoft/front";` : "");
1949
+ }
1950
+ output.appendLeft(offset, [...nativeImports].map(([key, local]) => {
1951
+ const [renderer, binding] = key.split("/");
1952
+ return `import { ${binding} as ${local} } from "${PREFIX}${renderer}";\n`;
1953
+ }).join(""));
1954
+ changed = true;
1955
+ };
1956
+ for (const block of scriptBlocks(code, id, require)) compile(code.slice(block.start, block.end), block.start, block.tsx);
1957
+ return changed ? {
1958
+ code: output.toString(),
1959
+ map: output.generateMap({
1960
+ hires: true,
1961
+ source: id,
1962
+ includeContent: true
1963
+ })
1964
+ } : null;
1965
+ }
1966
+ };
1967
+ }
1968
+ //#endregion
1969
+ //#region ../server/src/vite-plugin.ts
1970
+ /**
1971
+ * finesoftFrontViteConfig — Vite 插件
1972
+ *
1973
+ * 将 Hono SSR 服务器集成到 Vite 的 dev / build / preview 生命周期中,
1974
+ * 使 template-project 只需 `vite` / `vite build` / `vite preview` 即可运行。
1975
+ *
1976
+ * 支持多平台 adapter: "vercel" | "cloudflare" | "netlify" | "node" | "static" | "auto"
1977
+ * 或自定义 Adapter 对象。
1978
+ */
1979
+ const GENERATED_I18N_LOADER_ID = "virtual:finesoft-front/i18n-loader";
1980
+ const RESOLVED_GENERATED_I18N_LOADER_ID = `\0${GENERATED_I18N_LOADER_ID}`;
1981
+ /**
1982
+ * 匹配 Vite 配置级别的 renderMode 覆盖。
1983
+ * 精确路径优先,然后 glob 模式。
1984
+ */
1985
+ function normalizePathForGlob(pathname) {
1986
+ return pathname.replace(/\\/g, "/");
1987
+ }
1988
+ let devSafetyBannerPrinted = false;
1989
+ /**
1990
+ * 在 dev 启动时打印一次安全提示:dev 模式会通过 `/src/*` 和 `/@fs/*` 暴露源码(HMR
1991
+ * 必需),切勿对公网开放。Vite preview / `vp build` 产物不受影响。
1992
+ */
1993
+ function printDevSafetyBanner() {
1994
+ if (devSafetyBannerPrinted) return;
1995
+ devSafetyBannerPrinted = true;
1996
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
1997
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
1998
+ console.log(`\n${yellow("[finesoft]")} dev server is exposing source via /src/* and /@fs/* (HMR).\n` + dim(" Do NOT expose this server to untrusted networks; run `vp build && vp preview` for production.\n"));
1999
+ }
2000
+ async function resolveMessagesDir(root, messagesDir) {
2001
+ const { existsSync } = await dynamicImport("node:fs");
2002
+ const path = await dynamicImport("node:path");
2003
+ const absoluteDir = path.isAbsolute(messagesDir) ? messagesDir : path.resolve(root, messagesDir);
2004
+ if (!existsSync(absoluteDir)) throw new Error(`[finesoftFrontViteConfig] i18n.messagesDir not found: ${messagesDir}`);
2005
+ const relativeDir = normalizePathForGlob(path.relative(root, absoluteDir));
2006
+ if (!relativeDir || relativeDir.startsWith("..")) throw new Error(`[finesoftFrontViteConfig] i18n.messagesDir must stay inside the project root: ${messagesDir}`);
2007
+ return relativeDir.replace(/^\.\/+/, "");
2008
+ }
2009
+ function finesoftFrontViteConfig(options = {}) {
2010
+ if (!process.env.__FINESOFT_SUB_BUILD__) generateFrontTypes(options.controllerTypes || {});
2011
+ if (options.controllerTypes !== false && !process.env.__FINESOFT_SUB_BUILD__) generateControllerTypes(options.controllerTypes);
2012
+ const ssrEntry = options.ssr?.entry ?? "src/ssr.ts";
2013
+ let root = process.cwd();
2014
+ const serverControllers = serverControllerModules(() => root);
2015
+ const native = nativeBindings(() => root);
2016
+ let buildId = options.buildId ?? crypto.randomUUID();
2017
+ let resolvedCommand;
2018
+ let resolvedResolve;
2019
+ let resolvedCss;
2020
+ const CSS_EXTENSIONS = /\.(css|scss|less|sass|styl|stylus|pcss|postcss)($|\?)/;
2021
+ return {
2022
+ name: "finesoft-front",
2023
+ enforce: "pre",
2024
+ config(userConfig) {
2025
+ const inherited = userConfig.define?.__FINESOFT_BUILD_ID__;
2026
+ if (typeof inherited === "string") buildId = JSON.parse(inherited);
2027
+ const overrides = {
2028
+ appType: "custom",
2029
+ ssr: { noExternal: [
2030
+ "@finesoft/front",
2031
+ "@finesoft/web",
2032
+ "@finesoft/ssr"
2033
+ ] },
2034
+ define: { __FINESOFT_BUILD_ID__: JSON.stringify(buildId) }
2035
+ };
2036
+ if (!process.env.__FINESOFT_SUB_BUILD__) overrides.build = { outDir: userConfig.build?.outDir ?? "dist/client" };
2037
+ return overrides;
2038
+ },
2039
+ configResolved(config) {
2040
+ if (!process.env.__FINESOFT_SUB_BUILD__) generateFrontTypes({
2041
+ root: config.root,
2042
+ ...options.controllerTypes
2043
+ });
2044
+ if (options.controllerTypes !== false && !process.env.__FINESOFT_SUB_BUILD__) generateControllerTypes({
2045
+ ...options.controllerTypes,
2046
+ root: options.controllerTypes?.root ?? config.root
2047
+ });
2048
+ resolvedCommand = config.command;
2049
+ resolvedResolve = config.resolve;
2050
+ resolvedCss = config.css;
2051
+ root = config.root;
2052
+ },
2053
+ resolveId(id, importer, buildOptions) {
2054
+ if (id.startsWith("virtual:finesoft-front/native/")) return native.resolve(id, importer);
2055
+ serverControllers.guard(id, buildOptions?.ssr, this);
2056
+ if (id === "@finesoft/front") return (async () => {
2057
+ const resolveOptions = {
2058
+ ...buildOptions,
2059
+ skipSelf: true
2060
+ };
2061
+ const resolved = await this.resolve(id, importer, resolveOptions);
2062
+ if (!resolved || normalizePathForGlob(resolved.id.split("?")[0]) !== normalizePathForGlob(path.resolve(root, ".finesoft/front.d.ts"))) return resolved;
2063
+ const front = createRequire(path.join(root, "package.json")).resolve(id);
2064
+ const server = buildOptions?.ssr ?? this.environment?.config?.consumer === "server";
2065
+ const conditions = this.environment?.config?.resolve?.conditions;
2066
+ const node = server && (!conditions || conditions.includes("node"));
2067
+ return this.resolve(path.join(path.dirname(front), node ? "index-node.mjs" : "index.mjs"), importer, resolveOptions);
2068
+ })();
2069
+ if (id === GENERATED_I18N_LOADER_ID && options.i18n?.messagesDir) return RESOLVED_GENERATED_I18N_LOADER_ID;
2070
+ if (buildOptions?.scan) return (async () => {
2071
+ const resolved = await this.resolve(id, importer, { skipSelf: true });
2072
+ if (resolved && await serverControllers.load(this, resolved.id, buildOptions.ssr)) return `\0finesoft:server-controller-scan:${resolved.id}`;
2073
+ return resolved;
2074
+ })();
2075
+ return null;
2076
+ },
2077
+ async load(id, buildOptions) {
2078
+ const server = await serverControllers.load(this, id, buildOptions?.ssr);
2079
+ if (server) return server;
2080
+ if (id !== RESOLVED_GENERATED_I18N_LOADER_ID || !options.i18n?.messagesDir) return null;
2081
+ const baseDir = `/${await resolveMessagesDir(root, options.i18n.messagesDir)}`;
2082
+ const globPattern = `${baseDir}/*.json`;
2083
+ const filePrefix = `${baseDir}/`;
2084
+ return `
2085
+ const localeModules = import.meta.glob(${JSON.stringify(globPattern)}, { import: "default" });
2086
+
2087
+ export async function loadMessages(locale) {
2088
+ const loader = localeModules[${JSON.stringify(filePrefix)} + locale + ".json"];
2089
+ if (!loader) return undefined;
2090
+ const messages = await loader();
2091
+ return messages ?? undefined;
2092
+ }
2093
+ `;
2094
+ },
2095
+ async buildStart() {
2096
+ await serverControllers.start(this);
2097
+ },
2098
+ transform: (code, id) => native.transform(code, id),
2099
+ watchChange(file) {
2100
+ serverControllers.invalidate(file);
2101
+ },
2102
+ /**
2103
+ * Dev 模式 CSS 内联 — 消除 SSR 首屏布局抖动
2104
+ *
2105
+ * Vite dev 模式下,global.scss 等非组件 CSS 通过 JS 模块系统异步加载,
2106
+ * 导致 SSR HTML 初次渲染缺少布局关键样式(box-sizing、flex 布局、padding-top 等)。
2107
+ *
2108
+ * 此 hook 在 HTML 模板变换阶段(SSR 渲染之前):
2109
+ * 1. 找到浏览器入口脚本(排除 /@vite/client 等内部脚本)
2110
+ * 2. 编译入口脚本,填充 Vite 模块图
2111
+ * 3. 遍历模块图收集所有 CSS 依赖(排除 .svelte 组件 CSS,由 SSR 渲染自行处理)
2112
+ * 4. 通过 ssrLoadModule 获取编译后 CSS(SCSS→CSS)
2113
+ * 5. 注入 <style data-vite-dev-id> 标签到 <head>
2114
+ *
2115
+ * data-vite-dev-id 确保 Vite HMR 客户端复用已有标签,避免重复注入。
2116
+ */
2117
+ transformIndexHtml: {
2118
+ order: "pre",
2119
+ async handler(html, ctx) {
2120
+ const server = ctx.server;
2121
+ if (!server) return;
2122
+ const urlPath = (ctx.originalUrl || ctx.path || "").split("?")[0];
2123
+ if (/\.\w+$/.test(urlPath) && !urlPath.endsWith(".html")) return;
2124
+ const appEntry = [...html.matchAll(/<script\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/g)].find((m) => !m[1].startsWith("/@"));
2125
+ if (!appEntry) return;
2126
+ const browserEntry = appEntry[1];
2127
+ try {
2128
+ await server.transformRequest(browserEntry);
2129
+ } catch {
2130
+ return;
2131
+ }
2132
+ const cssUrls = [];
2133
+ const visited = /* @__PURE__ */ new Set();
2134
+ function walk(mod, depth = 0) {
2135
+ if (depth > 100) return;
2136
+ if (!mod?.url || visited.has(mod.url)) return;
2137
+ visited.add(mod.url);
2138
+ if (CSS_EXTENSIONS.test(mod.url) && !mod.url.includes(".svelte")) cssUrls.push(mod.url);
2139
+ if (mod.importedModules) for (const imported of mod.importedModules) walk(imported, depth + 1);
2140
+ }
2141
+ const browserMod = await server.moduleGraph.getModuleByUrl(browserEntry);
2142
+ if (browserMod) walk(browserMod);
2143
+ if (cssUrls.length === 0) return;
2144
+ const tags = [];
2145
+ for (const url of cssUrls) try {
2146
+ const css = (await server.ssrLoadModule(url))?.default;
2147
+ if (typeof css === "string" && css.length > 0) tags.push({
2148
+ tag: "style",
2149
+ attrs: { "data-vite-dev-id": url },
2150
+ children: css,
2151
+ injectTo: "head"
2152
+ });
2153
+ } catch {}
2154
+ return tags;
2155
+ }
2156
+ },
2157
+ configureServer(server) {
2158
+ let timer;
2159
+ const typeWatcher = options.controllerTypes === false ? void 0 : createControllerTypeWatcher({
2160
+ ...options.controllerTypes,
2161
+ root: options.controllerTypes?.root ?? root
2162
+ });
2163
+ const pending = /* @__PURE__ */ new Set();
2164
+ const refreshTypes = (event, file) => {
2165
+ if (event !== "dependency" && (!/\.(?:[cm]?tsx?|json)$/.test(file) || file.includes("/.finesoft/"))) return;
2166
+ clearTimeout(timer);
2167
+ pending.add(file);
2168
+ try {
2169
+ if (typeWatcher?.update([...pending], true)) {
2170
+ pending.clear();
2171
+ return;
2172
+ }
2173
+ } catch (error) {
2174
+ server.config.logger.error(`[finesoft] ${String(error)}`);
2175
+ pending.clear();
2176
+ return;
2177
+ }
2178
+ timer = setTimeout(() => {
2179
+ const files = [...pending];
2180
+ pending.clear();
2181
+ try {
2182
+ typeWatcher?.update(files);
2183
+ } catch (error) {
2184
+ server.config.logger.error(`[finesoft] ${String(error)}`);
2185
+ }
2186
+ }, 30);
2187
+ };
2188
+ if (options.controllerTypes !== false) {
2189
+ typeWatcher?.watch((file) => refreshTypes("dependency", file));
2190
+ server.watcher.on("all", refreshTypes);
2191
+ const close = server.close.bind(server);
2192
+ server.close = async () => {
2193
+ clearTimeout(timer);
2194
+ pending.clear();
2195
+ server.watcher.off("all", refreshTypes);
2196
+ typeWatcher?.close();
2197
+ return await close();
2198
+ };
2199
+ }
2200
+ return async () => {
2201
+ const { Hono: HonoClass } = await dynamicImport("hono");
2202
+ const { getRequestListener } = await dynamicImport("@hono/node-server");
2203
+ printDevSafetyBanner();
2204
+ const app = new HonoClass();
2205
+ if (options.proxies?.length) registerProxyRoutes(app, options.proxies);
2206
+ if (typeof options.setup === "function") await options.setup(app);
2207
+ else if (typeof options.setup === "string") await (await server.ssrLoadModule("/" + options.setup)).default(app);
2208
+ const ssrApp = createSSRApp({
2209
+ root,
2210
+ vite: server,
2211
+ ssrEntryPath: "/" + ssrEntry,
2212
+ parentFetch: app.fetch.bind(app),
2213
+ renderModes: options.renderModes,
2214
+ defaultLocale: options.defaultLocale
2215
+ });
2216
+ app.route("/", ssrApp);
2217
+ const close = server.close.bind(server);
2218
+ server.close = async () => {
2219
+ try {
2220
+ await close();
2221
+ } finally {
2222
+ await ssrApp.dispose();
2223
+ }
2224
+ };
2225
+ const listener = getRequestListener(app.fetch);
2226
+ server.middlewares.use((req, res) => {
2227
+ listener(req, res);
2228
+ });
2229
+ };
2230
+ },
2231
+ configurePreviewServer(server) {
2232
+ return async () => {
2233
+ const { readFileSync } = await dynamicImport("node:fs");
2234
+ const path = await dynamicImport("node:path");
2235
+ const { pathToFileURL } = await dynamicImport("node:url");
2236
+ const { Hono: HonoClass } = await dynamicImport("hono");
2237
+ const { getRequestListener } = await dynamicImport("@hono/node-server");
2238
+ const app = new HonoClass();
2239
+ if (options.proxies?.length) registerProxyRoutes(app, options.proxies);
2240
+ if (typeof options.setup === "function") await options.setup(app);
2241
+ else if (typeof options.setup === "string") try {
2242
+ const setupPath = pathToFileURL(path.resolve(root, "dist/server/setup.mjs")).href;
2243
+ await (await dynamicImport(setupPath)).default(app);
2244
+ } catch {
2245
+ console.warn("[finesoft] Could not load setup module for preview. API routes disabled.");
2246
+ }
2247
+ const template = readFileSync(path.resolve(root, "dist/client/index.html"), "utf-8");
2248
+ const ssrPath = pathToFileURL(path.resolve(root, "dist/server/ssr.js")).href;
2249
+ const ssrModule = await dynamicImport(ssrPath);
2250
+ const owner = createSSRHandler({
2251
+ ownRenderers: true,
2252
+ template,
2253
+ ...ssrModule,
2254
+ fetch: (request, bindings) => app.fetch(request, bindings),
2255
+ safeFetch: nodeSafeFetchOptions,
2256
+ renderModes: options.renderModes,
2257
+ defaultLocale: options.defaultLocale,
2258
+ onError: (error) => console.error("[SSR Preview Error]", error)
2259
+ });
2260
+ app.all("*", (c) => owner.fetch(c.req.raw, c.env));
2261
+ const close = server.httpServer.close.bind(server.httpServer);
2262
+ server.httpServer.close = (callback) => close((error) => {
2263
+ owner.dispose().then(() => callback?.(error), (cleanupError) => callback?.(cleanupError));
2264
+ });
2265
+ const listener = getRequestListener(app.fetch);
2266
+ server.middlewares.use((req, res) => {
2267
+ listener(req, res);
2268
+ });
2269
+ };
2270
+ },
2271
+ async closeBundle() {
2272
+ if (process.env.__FINESOFT_SUB_BUILD__) return;
2273
+ if (resolvedCommand !== "build") return;
2274
+ process.env.__FINESOFT_SUB_BUILD__ = "1";
2275
+ try {
2276
+ const vite = await dynamicImport("vite");
2277
+ const fs = await dynamicImport("node:fs");
2278
+ const path = await dynamicImport("node:path");
2279
+ console.log("\n Building SSR bundle...\n");
2280
+ await vite.build({
2281
+ root,
2282
+ define: { __FINESOFT_BUILD_ID__: JSON.stringify(buildId) },
2283
+ build: {
2284
+ ssr: ssrEntry,
2285
+ outDir: "dist/server"
2286
+ },
2287
+ ssr: { external: NODE_BUILTINS },
2288
+ resolve: resolvedResolve,
2289
+ css: resolvedCss
2290
+ });
2291
+ if (typeof options.setup === "string") {
2292
+ console.log(" Building setup module...\n");
2293
+ await vite.build({
2294
+ root,
2295
+ define: { __FINESOFT_BUILD_ID__: JSON.stringify(buildId) },
2296
+ build: {
2297
+ ssr: options.setup,
2298
+ outDir: "dist/server",
2299
+ emptyOutDir: false,
2300
+ rollupOptions: { output: { entryFileNames: "setup.mjs" } }
2301
+ },
2302
+ resolve: resolvedResolve
2303
+ });
2304
+ }
2305
+ if (options.adapter) {
2306
+ const adapter = resolveAdapter(options.adapter);
2307
+ const templateHtml = fs.readFileSync(path.resolve(root, "dist/client/index.html"), "utf-8");
2308
+ const ctx = {
2309
+ root,
2310
+ buildId,
2311
+ ssrEntry,
2312
+ setupPath: typeof options.setup === "string" ? options.setup : void 0,
2313
+ templateHtml,
2314
+ renderModes: options.renderModes,
2315
+ proxies: options.proxies,
2316
+ locales: options.locales,
2317
+ defaultLocale: options.defaultLocale,
2318
+ resolvedResolve,
2319
+ resolvedCss,
2320
+ vite: {
2321
+ ...vite,
2322
+ build: (config) => vite.build({
2323
+ ...config,
2324
+ define: {
2325
+ ...config.define,
2326
+ __FINESOFT_BUILD_ID__: JSON.stringify(buildId)
2327
+ }
2328
+ })
2329
+ },
2330
+ fs,
2331
+ path,
2332
+ generateSSREntry(opts) {
2333
+ return generateSSREntry(ctx, opts);
2334
+ },
2335
+ buildBundle(opts) {
2336
+ return buildBundle(ctx, opts);
2337
+ },
2338
+ copyStaticAssets(destDir, opts) {
2339
+ return copyStaticAssets(ctx, destDir, opts);
2340
+ }
2341
+ };
2342
+ console.log(` Running adapter: ${adapter.name}...\n`);
2343
+ await adapter.build(ctx);
2344
+ }
2345
+ } finally {
2346
+ delete process.env.__FINESOFT_SUB_BUILD__;
2347
+ }
2348
+ }
2349
+ };
2350
+ }
2351
+ //#endregion
2352
+ export { autoAdapter, cloudflareAdapter, finesoftFrontViteConfig, generateControllerTypes, generateProxyCode, netlifyAdapter, nodeAdapter, resolveAdapter, staticAdapter, vercelAdapter };
2353
+
2354
+ //# sourceMappingURL=vite.mjs.map