nukejs 0.0.5 → 0.0.7

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 (42) hide show
  1. package/README.md +96 -8
  2. package/dist/Link.js +16 -0
  3. package/dist/Link.js.map +7 -0
  4. package/dist/build-common.d.ts +57 -80
  5. package/dist/build-common.js +156 -168
  6. package/dist/build-common.js.map +2 -2
  7. package/dist/build-node.d.ts +14 -0
  8. package/dist/build-node.js +50 -51
  9. package/dist/build-node.js.map +2 -2
  10. package/dist/build-vercel.d.ts +18 -0
  11. package/dist/build-vercel.js +76 -63
  12. package/dist/build-vercel.js.map +2 -2
  13. package/dist/builder.d.ts +10 -0
  14. package/dist/builder.js +31 -62
  15. package/dist/builder.js.map +3 -3
  16. package/dist/bundle.js +69 -6
  17. package/dist/bundle.js.map +2 -2
  18. package/dist/component-analyzer.d.ts +13 -10
  19. package/dist/component-analyzer.js +26 -17
  20. package/dist/component-analyzer.js.map +2 -2
  21. package/dist/hmr-bundle.js +17 -4
  22. package/dist/hmr-bundle.js.map +2 -2
  23. package/dist/html-store.d.ts +7 -0
  24. package/dist/html-store.js.map +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +2 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/renderer.js +2 -7
  29. package/dist/renderer.js.map +2 -2
  30. package/dist/router.js +16 -4
  31. package/dist/router.js.map +2 -2
  32. package/dist/ssr.js +21 -4
  33. package/dist/ssr.js.map +2 -2
  34. package/dist/use-html.js +5 -1
  35. package/dist/use-html.js.map +2 -2
  36. package/dist/use-router.js +28 -0
  37. package/dist/use-router.js.map +7 -0
  38. package/package.json +1 -1
  39. package/dist/as-is/Link.tsx +0 -20
  40. package/dist/as-is/useRouter.ts +0 -33
  41. /package/dist/{as-is/Link.d.ts → Link.d.ts} +0 -0
  42. /package/dist/{as-is/useRouter.d.ts → use-router.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import crypto from "crypto";
3
+ import { randomBytes } from "node:crypto";
4
4
  import { build } from "esbuild";
5
5
  import { loadConfig } from "./config.js";
6
6
  import {
@@ -18,14 +18,49 @@ import {
18
18
  const OUTPUT_DIR = path.resolve(".vercel/output");
19
19
  const FUNCTIONS_DIR = path.join(OUTPUT_DIR, "functions");
20
20
  const STATIC_DIR = path.join(OUTPUT_DIR, "static");
21
- fs.mkdirSync(FUNCTIONS_DIR, { recursive: true });
22
- fs.mkdirSync(STATIC_DIR, { recursive: true });
21
+ for (const dir of [FUNCTIONS_DIR, STATIC_DIR])
22
+ fs.mkdirSync(dir, { recursive: true });
23
23
  const config = await loadConfig();
24
24
  const SERVER_DIR = path.resolve(config.serverDir);
25
25
  const PAGES_DIR = path.resolve("./app/pages");
26
26
  const PUBLIC_DIR = path.resolve("./app/public");
27
+ const NODE_BUILTINS = [
28
+ "node:*",
29
+ "http",
30
+ "https",
31
+ "fs",
32
+ "path",
33
+ "url",
34
+ "crypto",
35
+ "stream",
36
+ "buffer",
37
+ "events",
38
+ "util",
39
+ "os",
40
+ "net",
41
+ "tls",
42
+ "child_process",
43
+ "worker_threads",
44
+ "cluster",
45
+ "dgram",
46
+ "dns",
47
+ "readline",
48
+ "zlib",
49
+ "assert",
50
+ "module",
51
+ "perf_hooks",
52
+ "string_decoder",
53
+ "timers",
54
+ "async_hooks",
55
+ "v8",
56
+ "vm"
57
+ ];
58
+ const CJS_COMPAT_BANNER = {
59
+ js: `import { createRequire } from 'module';
60
+ const require = createRequire(import.meta.url);`
61
+ };
27
62
  function emitVercelFunction(name, bundleText) {
28
- const funcDir = path.join(FUNCTIONS_DIR, name + ".func");
63
+ const funcDir = path.join(FUNCTIONS_DIR, `${name}.func`);
29
64
  fs.mkdirSync(funcDir, { recursive: true });
30
65
  fs.writeFileSync(path.join(funcDir, "index.mjs"), bundleText);
31
66
  fs.writeFileSync(
@@ -107,15 +142,16 @@ export default async function handler(req: IncomingMessage, res: ServerResponse)
107
142
  function makePagesDispatcherSource(routes) {
108
143
  const imports = routes.map((r, i) => `import __page_${i}__ from ${JSON.stringify(r.adapterPath)};`).join("\n");
109
144
  const routeEntries = routes.map(
110
- (r, i) => ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, handler: __page_${i}__ },`
145
+ (r, i) => ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, catchAll: ${JSON.stringify(r.catchAllNames)}, handler: __page_${i}__ },`
111
146
  ).join("\n");
112
147
  return `import type { IncomingMessage, ServerResponse } from 'http';
113
148
  ${imports}
114
149
 
115
150
  const ROUTES: Array<{
116
- regex: string;
117
- params: string[];
118
- handler: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
151
+ regex: string;
152
+ params: string[];
153
+ catchAll: string[];
154
+ handler: (req: IncomingMessage, res: ServerResponse) => Promise<void>;
119
155
  }> = [
120
156
  ${routeEntries}
121
157
  ];
@@ -128,9 +164,16 @@ export default async function handler(req: IncomingMessage, res: ServerResponse)
128
164
  const m = pathname.match(new RegExp(route.regex));
129
165
  if (!m) continue;
130
166
 
131
- // Inject dynamic params as query-string values so page handlers can read
132
- // them via new URL(req.url).searchParams \u2014 the same way they always have.
133
- route.params.forEach((name, i) => url.searchParams.set(name, m[i + 1]));
167
+ const catchAllSet = new Set(route.catchAll);
168
+ route.params.forEach((name, i) => {
169
+ const raw = m[i + 1] ?? '';
170
+ if (catchAllSet.has(name)) {
171
+ // Encode catch-all as repeated keys so the handler can getAll() \u2192 string[]
172
+ raw.split('/').filter(Boolean).forEach(seg => url.searchParams.append(name, seg));
173
+ } else {
174
+ url.searchParams.set(name, raw);
175
+ }
176
+ });
134
177
  req.url = pathname + (url.search || '');
135
178
 
136
179
  return route.handler(req, res);
@@ -147,9 +190,8 @@ const apiFiles = walkFiles(SERVER_DIR);
147
190
  if (apiFiles.length === 0) console.warn(`\u26A0 No server files found in ${SERVER_DIR}`);
148
191
  const apiRoutes = apiFiles.map((relPath) => ({ ...analyzeFile(relPath, "api"), absPath: path.join(SERVER_DIR, relPath) })).sort((a, b) => b.specificity - a.specificity);
149
192
  if (apiRoutes.length > 0) {
150
- const dispatcherSource = makeApiDispatcherSource(apiRoutes);
151
- const dispatcherPath = path.join(SERVER_DIR, `_api_dispatcher_${crypto.randomBytes(4).toString("hex")}.ts`);
152
- fs.writeFileSync(dispatcherPath, dispatcherSource);
193
+ const dispatcherPath = path.join(SERVER_DIR, `_api_dispatcher_${randomBytes(4).toString("hex")}.ts`);
194
+ fs.writeFileSync(dispatcherPath, makeApiDispatcherSource(apiRoutes));
153
195
  try {
154
196
  const result = await build({
155
197
  entryPoints: [dispatcherPath],
@@ -157,7 +199,8 @@ if (apiRoutes.length > 0) {
157
199
  format: "esm",
158
200
  platform: "node",
159
201
  target: "node20",
160
- packages: "external",
202
+ banner: CJS_COMPAT_BANNER,
203
+ external: NODE_BUILTINS,
161
204
  write: false
162
205
  });
163
206
  emitVercelFunction("api", result.outputFiles[0].text);
@@ -165,22 +208,20 @@ if (apiRoutes.length > 0) {
165
208
  } finally {
166
209
  fs.unlinkSync(dispatcherPath);
167
210
  }
168
- for (const { srcRegex } of apiRoutes) {
211
+ for (const { srcRegex } of apiRoutes)
169
212
  vercelRoutes.push({ src: srcRegex, dest: "/api" });
170
- }
171
213
  }
172
214
  const serverPages = collectServerPages(PAGES_DIR);
173
215
  if (serverPages.length > 0) {
174
- const globalClientRegistry = collectGlobalClientRegistry(serverPages, PAGES_DIR);
175
- const prerenderedHtml = await bundleClientComponents(globalClientRegistry, PAGES_DIR, STATIC_DIR);
176
- const prerenderedHtmlRecord = Object.fromEntries(prerenderedHtml);
216
+ const globalRegistry = collectGlobalClientRegistry(serverPages, PAGES_DIR);
217
+ const prerenderedHtml = await bundleClientComponents(globalRegistry, PAGES_DIR, STATIC_DIR);
218
+ const prerenderedRecord = Object.fromEntries(prerenderedHtml);
177
219
  const tempAdapterPaths = [];
178
220
  for (const page of serverPages) {
179
- const { absPath } = page;
180
- const adapterDir = path.dirname(absPath);
181
- const adapterPath = path.join(adapterDir, `_page_adapter_${crypto.randomBytes(4).toString("hex")}.ts`);
182
- const layoutPaths = findPageLayouts(absPath, PAGES_DIR);
183
- const { registry, clientComponentNames } = buildPerPageRegistry(absPath, layoutPaths, PAGES_DIR);
221
+ const adapterDir = path.dirname(page.absPath);
222
+ const adapterPath = path.join(adapterDir, `_page_adapter_${randomBytes(4).toString("hex")}.ts`);
223
+ const layoutPaths = findPageLayouts(page.absPath, PAGES_DIR);
224
+ const { registry, clientComponentNames } = buildPerPageRegistry(page.absPath, layoutPaths, PAGES_DIR);
184
225
  const layoutImports = layoutPaths.map((lp, i) => {
185
226
  const rel = path.relative(adapterDir, lp).replace(/\\/g, "/");
186
227
  return `import __layout_${i}__ from ${JSON.stringify(rel.startsWith(".") ? rel : "./" + rel)};`;
@@ -188,23 +229,25 @@ if (serverPages.length > 0) {
188
229
  fs.writeFileSync(
189
230
  adapterPath,
190
231
  makePageAdapterSource({
191
- pageImport: JSON.stringify("./" + path.basename(absPath)),
232
+ pageImport: JSON.stringify("./" + path.basename(page.absPath)),
192
233
  layoutImports,
193
234
  clientComponentNames,
194
235
  allClientIds: [...registry.keys()],
195
236
  layoutArrayItems: layoutPaths.map((_, i) => `__layout_${i}__`).join(", "),
196
- prerenderedHtml: prerenderedHtmlRecord
237
+ prerenderedHtml: prerenderedRecord,
238
+ catchAllNames: page.catchAllNames
197
239
  })
198
240
  );
199
241
  tempAdapterPaths.push(adapterPath);
200
- console.log(` prepared ${path.relative(PAGES_DIR, absPath)} \u2192 ${page.funcPath} [page]`);
242
+ console.log(` prepared ${path.relative(PAGES_DIR, page.absPath)} \u2192 ${page.funcPath} [page]`);
201
243
  }
202
244
  const dispatcherRoutes = serverPages.map((page, i) => ({
203
245
  adapterPath: tempAdapterPaths[i],
204
246
  srcRegex: page.srcRegex,
205
- paramNames: page.paramNames
247
+ paramNames: page.paramNames,
248
+ catchAllNames: page.catchAllNames
206
249
  }));
207
- const dispatcherPath = path.join(PAGES_DIR, `_pages_dispatcher_${crypto.randomBytes(4).toString("hex")}.ts`);
250
+ const dispatcherPath = path.join(PAGES_DIR, `_pages_dispatcher_${randomBytes(4).toString("hex")}.ts`);
208
251
  fs.writeFileSync(dispatcherPath, makePagesDispatcherSource(dispatcherRoutes));
209
252
  try {
210
253
  const result = await build({
@@ -214,37 +257,8 @@ if (serverPages.length > 0) {
214
257
  platform: "node",
215
258
  target: "node20",
216
259
  jsx: "automatic",
217
- external: [
218
- "node:*",
219
- "http",
220
- "https",
221
- "fs",
222
- "path",
223
- "url",
224
- "crypto",
225
- "stream",
226
- "buffer",
227
- "events",
228
- "util",
229
- "os",
230
- "net",
231
- "tls",
232
- "child_process",
233
- "worker_threads",
234
- "cluster",
235
- "dgram",
236
- "dns",
237
- "readline",
238
- "zlib",
239
- "assert",
240
- "module",
241
- "perf_hooks",
242
- "string_decoder",
243
- "timers",
244
- "async_hooks",
245
- "v8",
246
- "vm"
247
- ],
260
+ banner: CJS_COMPAT_BANNER,
261
+ external: NODE_BUILTINS,
248
262
  define: { "process.env.NODE_ENV": '"production"' },
249
263
  write: false
250
264
  });
@@ -254,9 +268,8 @@ if (serverPages.length > 0) {
254
268
  fs.unlinkSync(dispatcherPath);
255
269
  for (const p of tempAdapterPaths) if (fs.existsSync(p)) fs.unlinkSync(p);
256
270
  }
257
- for (const { srcRegex } of serverPages) {
271
+ for (const { srcRegex } of serverPages)
258
272
  vercelRoutes.push({ src: srcRegex, dest: "/pages" });
259
- }
260
273
  }
261
274
  fs.writeFileSync(
262
275
  path.join(OUTPUT_DIR, "config.json"),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/build-vercel.ts"],
4
- "sourcesContent": ["import fs from 'fs';\r\nimport path from 'path';\r\nimport crypto from 'crypto';\r\nimport { build } from 'esbuild';\r\n\r\nimport { loadConfig } from './config';\r\nimport {\r\n walkFiles,\r\n analyzeFile,\r\n collectServerPages,\r\n collectGlobalClientRegistry,\r\n bundleClientComponents,\r\n findPageLayouts,\r\n buildPerPageRegistry,\r\n makePageAdapterSource,\r\n buildCombinedBundle,\r\n copyPublicFiles,\r\n} from './build-common';\r\n\r\n// \u2500\u2500\u2500 Output directories \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst OUTPUT_DIR = path.resolve('.vercel/output');\r\nconst FUNCTIONS_DIR = path.join(OUTPUT_DIR, 'functions');\r\nconst STATIC_DIR = path.join(OUTPUT_DIR, 'static');\r\n\r\nfs.mkdirSync(FUNCTIONS_DIR, { recursive: true });\r\nfs.mkdirSync(STATIC_DIR, { recursive: true });\r\n\r\n// \u2500\u2500\u2500 Config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst config = await loadConfig();\r\nconst SERVER_DIR = path.resolve(config.serverDir);\r\nconst PAGES_DIR = path.resolve('./app/pages');\r\nconst PUBLIC_DIR = path.resolve('./app/public');\r\n\r\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\ntype VercelRoute = { src: string; dest: string };\r\n\r\n/** Writes a bundled dispatcher into a Vercel .func directory. */\r\nfunction emitVercelFunction(name: string, bundleText: string): void {\r\n const funcDir = path.join(FUNCTIONS_DIR, name + '.func');\r\n fs.mkdirSync(funcDir, { recursive: true });\r\n fs.writeFileSync(path.join(funcDir, 'index.mjs'), bundleText);\r\n fs.writeFileSync(\r\n path.join(funcDir, '.vc-config.json'),\r\n JSON.stringify({ runtime: 'nodejs20.x', handler: 'index.mjs', launcherType: 'Nodejs' }, null, 2),\r\n );\r\n}\r\n\r\n// \u2500\u2500\u2500 API dispatcher source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * Generates a single dispatcher that imports every API route module directly,\r\n * matches the incoming URL against each route's regex, injects captured params,\r\n * and calls the right HTTP-method export (GET, POST, \u2026) or default export.\r\n *\r\n * enhance / parseBody helpers are included once rather than once per route.\r\n */\r\nfunction makeApiDispatcherSource(\r\n routes: Array<{ absPath: string; srcRegex: string; paramNames: string[] }>,\r\n): string {\r\n const imports = routes\r\n .map((r, i) => `import * as __api_${i}__ from ${JSON.stringify(r.absPath)};`)\r\n .join('\\n');\r\n\r\n const routeEntries = routes\r\n .map((r, i) =>\r\n ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, mod: __api_${i}__ },`,\r\n )\r\n .join('\\n');\r\n\r\n return `\\\r\nimport type { IncomingMessage, ServerResponse } from 'http';\r\n${imports}\r\n\r\nfunction enhance(res: ServerResponse) {\r\n (res as any).json = function(data: any, status = 200) {\r\n this.statusCode = status;\r\n this.setHeader('Content-Type', 'application/json');\r\n this.end(JSON.stringify(data));\r\n };\r\n (res as any).status = function(code: number) { this.statusCode = code; return this; };\r\n return res;\r\n}\r\n\r\nasync function parseBody(req: IncomingMessage): Promise<any> {\r\n return new Promise((resolve, reject) => {\r\n let body = '';\r\n req.on('data', (chunk: any) => { body += chunk.toString(); });\r\n req.on('end', () => {\r\n try {\r\n resolve(\r\n body && req.headers['content-type']?.includes('application/json')\r\n ? JSON.parse(body)\r\n : body,\r\n );\r\n } catch (e) { reject(e); }\r\n });\r\n req.on('error', reject);\r\n });\r\n}\r\n\r\nconst ROUTES = [\r\n${routeEntries}\r\n];\r\n\r\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\r\n const url = new URL(req.url || '/', 'http://localhost');\r\n const pathname = url.pathname;\r\n\r\n for (const route of ROUTES) {\r\n const m = pathname.match(new RegExp(route.regex));\r\n if (!m) continue;\r\n\r\n const method = (req.method || 'GET').toUpperCase();\r\n const apiRes = enhance(res);\r\n const apiReq = req as any;\r\n\r\n apiReq.body = await parseBody(req);\r\n apiReq.query = Object.fromEntries(url.searchParams);\r\n apiReq.params = {};\r\n route.params.forEach((name: string, i: number) => { apiReq.params[name] = m[i + 1]; });\r\n\r\n const fn = (route.mod as any)[method] ?? (route.mod as any)['default'];\r\n if (typeof fn !== 'function') {\r\n (apiRes as any).json({ error: \\`Method \\${method} not allowed\\` }, 405);\r\n return;\r\n }\r\n await fn(apiReq, apiRes);\r\n return;\r\n }\r\n\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Not Found' }));\r\n}\r\n`;\r\n}\r\n\r\n// \u2500\u2500\u2500 Pages dispatcher source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * Generates a dispatcher that imports each page's pre-generated adapter by its\r\n * temp file path, matches the incoming URL, injects captured dynamic params as\r\n * query-string values (page handlers read params from req.url searchParams),\r\n * then delegates to the matching handler.\r\n */\r\nfunction makePagesDispatcherSource(\r\n routes: Array<{ adapterPath: string; srcRegex: string; paramNames: string[] }>,\r\n): string {\r\n const imports = routes\r\n .map((r, i) => `import __page_${i}__ from ${JSON.stringify(r.adapterPath)};`)\r\n .join('\\n');\r\n\r\n const routeEntries = routes\r\n .map((r, i) =>\r\n ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, handler: __page_${i}__ },`,\r\n )\r\n .join('\\n');\r\n\r\n return `\\\r\nimport type { IncomingMessage, ServerResponse } from 'http';\r\n${imports}\r\n\r\nconst ROUTES: Array<{\r\n regex: string;\r\n params: string[];\r\n handler: (req: IncomingMessage, res: ServerResponse) => Promise<void>;\r\n}> = [\r\n${routeEntries}\r\n];\r\n\r\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\r\n const url = new URL(req.url || '/', 'http://localhost');\r\n const pathname = url.pathname;\r\n\r\n for (const route of ROUTES) {\r\n const m = pathname.match(new RegExp(route.regex));\r\n if (!m) continue;\r\n\r\n // Inject dynamic params as query-string values so page handlers can read\r\n // them via new URL(req.url).searchParams \u2014 the same way they always have.\r\n route.params.forEach((name, i) => url.searchParams.set(name, m[i + 1]));\r\n req.url = pathname + (url.search || '');\r\n\r\n return route.handler(req, res);\r\n }\r\n\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('Not Found');\r\n}\r\n`;\r\n}\r\n\r\n// \u2500\u2500\u2500 Build API function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst vercelRoutes: VercelRoute[] = [];\r\n\r\nconst apiFiles = walkFiles(SERVER_DIR);\r\nif (apiFiles.length === 0) console.warn(`\u26A0 No server files found in ${SERVER_DIR}`);\r\n\r\nconst apiRoutes = apiFiles\r\n .map(relPath => ({ ...analyzeFile(relPath, 'api'), absPath: path.join(SERVER_DIR, relPath) }))\r\n .sort((a, b) => b.specificity - a.specificity);\r\n\r\nif (apiRoutes.length > 0) {\r\n const dispatcherSource = makeApiDispatcherSource(apiRoutes);\r\n const dispatcherPath = path.join(SERVER_DIR, `_api_dispatcher_${crypto.randomBytes(4).toString('hex')}.ts`);\r\n fs.writeFileSync(dispatcherPath, dispatcherSource);\r\n\r\n try {\r\n const result = await build({\r\n entryPoints: [dispatcherPath],\r\n bundle: true,\r\n format: 'esm',\r\n platform: 'node',\r\n target: 'node20',\r\n packages: 'external',\r\n write: false,\r\n });\r\n emitVercelFunction('api', result.outputFiles[0].text);\r\n console.log(` built API dispatcher \u2192 api.func (${apiRoutes.length} route(s))`);\r\n } finally {\r\n fs.unlinkSync(dispatcherPath);\r\n }\r\n\r\n // API routes are listed first \u2014 they win on any URL collision with pages.\r\n for (const { srcRegex } of apiRoutes) {\r\n vercelRoutes.push({ src: srcRegex, dest: '/api' });\r\n }\r\n}\r\n\r\n// \u2500\u2500\u2500 Build Pages function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst serverPages = collectServerPages(PAGES_DIR);\r\n\r\nif (serverPages.length > 0) {\r\n // Pass 1 \u2014 bundle all client components to static files.\r\n const globalClientRegistry = collectGlobalClientRegistry(serverPages, PAGES_DIR);\r\n const prerenderedHtml = await bundleClientComponents(globalClientRegistry, PAGES_DIR, STATIC_DIR);\r\n const prerenderedHtmlRecord = Object.fromEntries(prerenderedHtml);\r\n\r\n // Pass 2 \u2014 write one temp adapter per page next to its source file (so\r\n // relative imports inside the component resolve correctly), then\r\n // bundle everything in one esbuild pass via the dispatcher.\r\n const tempAdapterPaths: string[] = [];\r\n\r\n for (const page of serverPages) {\r\n const { absPath } = page;\r\n const adapterDir = path.dirname(absPath);\r\n const adapterPath = path.join(adapterDir, `_page_adapter_${crypto.randomBytes(4).toString('hex')}.ts`);\r\n\r\n const layoutPaths = findPageLayouts(absPath, PAGES_DIR);\r\n const { registry, clientComponentNames } = buildPerPageRegistry(absPath, layoutPaths, PAGES_DIR);\r\n\r\n const layoutImports = layoutPaths\r\n .map((lp, i) => {\r\n const rel = path.relative(adapterDir, lp).replace(/\\\\/g, '/');\r\n return `import __layout_${i}__ from ${JSON.stringify(rel.startsWith('.') ? rel : './' + rel)};`;\r\n })\r\n .join('\\n');\r\n\r\n fs.writeFileSync(\r\n adapterPath,\r\n makePageAdapterSource({\r\n pageImport: JSON.stringify('./' + path.basename(absPath)),\r\n layoutImports,\r\n clientComponentNames,\r\n allClientIds: [...registry.keys()],\r\n layoutArrayItems: layoutPaths.map((_, i) => `__layout_${i}__`).join(', '),\r\n prerenderedHtml: prerenderedHtmlRecord,\r\n }),\r\n );\r\n\r\n tempAdapterPaths.push(adapterPath);\r\n console.log(` prepared ${path.relative(PAGES_DIR, absPath)} \u2192 ${page.funcPath} [page]`);\r\n }\r\n\r\n // Write the dispatcher and let esbuild bundle all adapters in one pass.\r\n const dispatcherRoutes = serverPages.map((page, i) => ({\r\n adapterPath: tempAdapterPaths[i],\r\n srcRegex: page.srcRegex,\r\n paramNames: page.paramNames,\r\n }));\r\n\r\n const dispatcherPath = path.join(PAGES_DIR, `_pages_dispatcher_${crypto.randomBytes(4).toString('hex')}.ts`);\r\n fs.writeFileSync(dispatcherPath, makePagesDispatcherSource(dispatcherRoutes));\r\n\r\n try {\r\n const result = await build({\r\n entryPoints: [dispatcherPath],\r\n bundle: true,\r\n format: 'esm',\r\n platform: 'node',\r\n target: 'node20',\r\n jsx: 'automatic',\r\n external: [\r\n 'node:*',\r\n 'http', 'https', 'fs', 'path', 'url', 'crypto', 'stream', 'buffer',\r\n 'events', 'util', 'os', 'net', 'tls', 'child_process', 'worker_threads',\r\n 'cluster', 'dgram', 'dns', 'readline', 'zlib', 'assert', 'module',\r\n 'perf_hooks', 'string_decoder', 'timers', 'async_hooks', 'v8', 'vm',\r\n ],\r\n define: { 'process.env.NODE_ENV': '\"production\"' },\r\n write: false,\r\n });\r\n emitVercelFunction('pages', result.outputFiles[0].text);\r\n console.log(` built Pages dispatcher \u2192 pages.func (${serverPages.length} page(s))`);\r\n } finally {\r\n fs.unlinkSync(dispatcherPath);\r\n for (const p of tempAdapterPaths) if (fs.existsSync(p)) fs.unlinkSync(p);\r\n }\r\n\r\n for (const { srcRegex } of serverPages) {\r\n vercelRoutes.push({ src: srcRegex, dest: '/pages' });\r\n }\r\n}\r\n\r\n// \u2500\u2500\u2500 Vercel config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfs.writeFileSync(\r\n path.join(OUTPUT_DIR, 'config.json'),\r\n JSON.stringify({ version: 3, routes: vercelRoutes }, null, 2),\r\n);\r\n\r\nfs.writeFileSync(\r\n path.resolve('vercel.json'),\r\n JSON.stringify({ runtime: 'nodejs20.x' }, null, 2),\r\n);\r\n\r\n// \u2500\u2500\u2500 Static assets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nawait buildCombinedBundle(STATIC_DIR);\r\ncopyPublicFiles(PUBLIC_DIR, STATIC_DIR);\r\n\r\nconst fnCount = (apiRoutes.length > 0 ? 1 : 0) + (serverPages.length > 0 ? 1 : 0);\r\nconsole.log(`\\n\u2713 Vercel build complete \u2014 ${fnCount} function(s) \u2192 .vercel/output`);"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\r\n * build-vercel.ts \u2014 Vercel Production Build\r\n *\r\n * Produces a .vercel/output/ directory conforming to the Vercel Build Output\r\n * API v3. Two serverless functions are emitted:\r\n *\r\n * api.func/ \u2190 single dispatcher bundling all API route handlers\r\n * pages.func/ \u2190 single dispatcher bundling all SSR page handlers\r\n *\r\n * Static assets (React runtime, client components, public files) go to\r\n * .vercel/output/static/ and are served by Vercel's CDN directly.\r\n *\r\n * Notes on bundling strategy:\r\n * - npm packages are FULLY BUNDLED (no node_modules at Vercel runtime).\r\n * - Node built-ins are kept external (available in the nodejs20.x runtime).\r\n * - A createRequire banner lets CJS packages (mongoose, etc.) resolve Node\r\n * built-ins correctly inside the ESM output bundle.\r\n */\r\n\r\nimport fs from 'fs';\r\nimport path from 'path';\r\nimport { randomBytes } from 'node:crypto';\r\nimport { build } from 'esbuild';\r\n\r\nimport { loadConfig } from './config';\r\nimport {\r\n walkFiles,\r\n analyzeFile,\r\n collectServerPages,\r\n collectGlobalClientRegistry,\r\n bundleClientComponents,\r\n findPageLayouts,\r\n buildPerPageRegistry,\r\n makePageAdapterSource,\r\n buildCombinedBundle,\r\n copyPublicFiles,\r\n} from './build-common';\r\n\r\n// \u2500\u2500\u2500 Output directories \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst OUTPUT_DIR = path.resolve('.vercel/output');\r\nconst FUNCTIONS_DIR = path.join(OUTPUT_DIR, 'functions');\r\nconst STATIC_DIR = path.join(OUTPUT_DIR, 'static');\r\n\r\nfor (const dir of [FUNCTIONS_DIR, STATIC_DIR])\r\n fs.mkdirSync(dir, { recursive: true });\r\n\r\n// \u2500\u2500\u2500 Config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst config = await loadConfig();\r\nconst SERVER_DIR = path.resolve(config.serverDir);\r\nconst PAGES_DIR = path.resolve('./app/pages');\r\nconst PUBLIC_DIR = path.resolve('./app/public');\r\n\r\n// \u2500\u2500\u2500 Shared esbuild config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * Node built-ins that should never be bundled.\r\n * npm packages are intentionally absent \u2014 they must be bundled because\r\n * Vercel serverless functions have no node_modules at runtime.\r\n */\r\nconst NODE_BUILTINS = [\r\n 'node:*',\r\n 'http', 'https', 'fs', 'path', 'url', 'crypto', 'stream', 'buffer',\r\n 'events', 'util', 'os', 'net', 'tls', 'child_process', 'worker_threads',\r\n 'cluster', 'dgram', 'dns', 'readline', 'zlib', 'assert', 'module',\r\n 'perf_hooks', 'string_decoder', 'timers', 'async_hooks', 'v8', 'vm',\r\n];\r\n\r\n/**\r\n * Banner injected at the top of every Vercel function bundle.\r\n *\r\n * Why it's needed: esbuild bundles CJS packages (mongoose, etc.) into ESM\r\n * output and replaces their require() calls with a __require2 shim. That\r\n * shim cannot resolve Node built-ins on its own inside an ESM module scope.\r\n * Injecting a real require (backed by createRequire) fixes the shim so that\r\n * dynamic require('crypto'), require('stream'), etc. work correctly.\r\n */\r\nconst CJS_COMPAT_BANNER = {\r\n js: `import { createRequire } from 'module';\\nconst require = createRequire(import.meta.url);`,\r\n};\r\n\r\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\ntype VercelRoute = { src: string; dest: string };\r\n\r\n/** Writes a bundled dispatcher into a Vercel .func directory. */\r\nfunction emitVercelFunction(name: string, bundleText: string): void {\r\n const funcDir = path.join(FUNCTIONS_DIR, `${name}.func`);\r\n fs.mkdirSync(funcDir, { recursive: true });\r\n fs.writeFileSync(path.join(funcDir, 'index.mjs'), bundleText);\r\n fs.writeFileSync(\r\n path.join(funcDir, '.vc-config.json'),\r\n JSON.stringify({ runtime: 'nodejs20.x', handler: 'index.mjs', launcherType: 'Nodejs' }, null, 2),\r\n );\r\n}\r\n\r\n// \u2500\u2500\u2500 API dispatcher source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * Generates a single TypeScript dispatcher that imports every API route module,\r\n * matches the incoming URL against each route's regex, injects captured params,\r\n * and calls the right HTTP-method export (GET, POST, \u2026) or default export.\r\n */\r\nfunction makeApiDispatcherSource(\r\n routes: Array<{ absPath: string; srcRegex: string; paramNames: string[] }>,\r\n): string {\r\n const imports = routes\r\n .map((r, i) => `import * as __api_${i}__ from ${JSON.stringify(r.absPath)};`)\r\n .join('\\n');\r\n\r\n const routeEntries = routes\r\n .map((r, i) =>\r\n ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, mod: __api_${i}__ },`,\r\n )\r\n .join('\\n');\r\n\r\n return `\\\r\nimport type { IncomingMessage, ServerResponse } from 'http';\r\n${imports}\r\n\r\nfunction enhance(res: ServerResponse) {\r\n (res as any).json = function(data: any, status = 200) {\r\n this.statusCode = status;\r\n this.setHeader('Content-Type', 'application/json');\r\n this.end(JSON.stringify(data));\r\n };\r\n (res as any).status = function(code: number) { this.statusCode = code; return this; };\r\n return res;\r\n}\r\n\r\nasync function parseBody(req: IncomingMessage): Promise<any> {\r\n return new Promise((resolve, reject) => {\r\n let body = '';\r\n req.on('data', (chunk: any) => { body += chunk.toString(); });\r\n req.on('end', () => {\r\n try {\r\n resolve(\r\n body && req.headers['content-type']?.includes('application/json')\r\n ? JSON.parse(body)\r\n : body,\r\n );\r\n } catch (e) { reject(e); }\r\n });\r\n req.on('error', reject);\r\n });\r\n}\r\n\r\nconst ROUTES = [\r\n${routeEntries}\r\n];\r\n\r\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\r\n const url = new URL(req.url || '/', 'http://localhost');\r\n const pathname = url.pathname;\r\n\r\n for (const route of ROUTES) {\r\n const m = pathname.match(new RegExp(route.regex));\r\n if (!m) continue;\r\n\r\n const method = (req.method || 'GET').toUpperCase();\r\n const apiRes = enhance(res);\r\n const apiReq = req as any;\r\n\r\n apiReq.body = await parseBody(req);\r\n apiReq.query = Object.fromEntries(url.searchParams);\r\n apiReq.params = {};\r\n route.params.forEach((name: string, i: number) => { apiReq.params[name] = m[i + 1]; });\r\n\r\n const fn = (route.mod as any)[method] ?? (route.mod as any)['default'];\r\n if (typeof fn !== 'function') {\r\n (apiRes as any).json({ error: \\`Method \\${method} not allowed\\` }, 405);\r\n return;\r\n }\r\n await fn(apiReq, apiRes);\r\n return;\r\n }\r\n\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: 'Not Found' }));\r\n}\r\n`;\r\n}\r\n\r\n// \u2500\u2500\u2500 Pages dispatcher source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/**\r\n * Generates a TypeScript dispatcher that imports each page's pre-generated\r\n * adapter, matches the incoming URL, encodes captured dynamic params as\r\n * query-string values (catch-all params use repeated keys), then delegates\r\n * to the matching handler.\r\n */\r\nfunction makePagesDispatcherSource(\r\n routes: Array<{\r\n adapterPath: string;\r\n srcRegex: string;\r\n paramNames: string[];\r\n catchAllNames: string[];\r\n }>,\r\n): string {\r\n const imports = routes\r\n .map((r, i) => `import __page_${i}__ from ${JSON.stringify(r.adapterPath)};`)\r\n .join('\\n');\r\n\r\n const routeEntries = routes\r\n .map((r, i) =>\r\n ` { regex: ${JSON.stringify(r.srcRegex)}, params: ${JSON.stringify(r.paramNames)}, catchAll: ${JSON.stringify(r.catchAllNames)}, handler: __page_${i}__ },`,\r\n )\r\n .join('\\n');\r\n\r\n return `\\\r\nimport type { IncomingMessage, ServerResponse } from 'http';\r\n${imports}\r\n\r\nconst ROUTES: Array<{\r\n regex: string;\r\n params: string[];\r\n catchAll: string[];\r\n handler: (req: IncomingMessage, res: ServerResponse) => Promise<void>;\r\n}> = [\r\n${routeEntries}\r\n];\r\n\r\nexport default async function handler(req: IncomingMessage, res: ServerResponse) {\r\n const url = new URL(req.url || '/', 'http://localhost');\r\n const pathname = url.pathname;\r\n\r\n for (const route of ROUTES) {\r\n const m = pathname.match(new RegExp(route.regex));\r\n if (!m) continue;\r\n\r\n const catchAllSet = new Set(route.catchAll);\r\n route.params.forEach((name, i) => {\r\n const raw = m[i + 1] ?? '';\r\n if (catchAllSet.has(name)) {\r\n // Encode catch-all as repeated keys so the handler can getAll() \u2192 string[]\r\n raw.split('/').filter(Boolean).forEach(seg => url.searchParams.append(name, seg));\r\n } else {\r\n url.searchParams.set(name, raw);\r\n }\r\n });\r\n req.url = pathname + (url.search || '');\r\n\r\n return route.handler(req, res);\r\n }\r\n\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\r\n res.end('Not Found');\r\n}\r\n`;\r\n}\r\n\r\n// \u2500\u2500\u2500 Build API function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst vercelRoutes: VercelRoute[] = [];\r\n\r\nconst apiFiles = walkFiles(SERVER_DIR);\r\nif (apiFiles.length === 0) console.warn(`\u26A0 No server files found in ${SERVER_DIR}`);\r\n\r\nconst apiRoutes = apiFiles\r\n .map(relPath => ({ ...analyzeFile(relPath, 'api'), absPath: path.join(SERVER_DIR, relPath) }))\r\n .sort((a, b) => b.specificity - a.specificity);\r\n\r\nif (apiRoutes.length > 0) {\r\n const dispatcherPath = path.join(SERVER_DIR, `_api_dispatcher_${randomBytes(4).toString('hex')}.ts`);\r\n fs.writeFileSync(dispatcherPath, makeApiDispatcherSource(apiRoutes));\r\n\r\n try {\r\n const result = await build({\r\n entryPoints: [dispatcherPath],\r\n bundle: true,\r\n format: 'esm',\r\n platform: 'node',\r\n target: 'node20',\r\n banner: CJS_COMPAT_BANNER,\r\n external: NODE_BUILTINS,\r\n write: false,\r\n });\r\n emitVercelFunction('api', result.outputFiles[0].text);\r\n console.log(` built API dispatcher \u2192 api.func (${apiRoutes.length} route(s))`);\r\n } finally {\r\n fs.unlinkSync(dispatcherPath);\r\n }\r\n\r\n // API routes are listed first \u2014 they win on any URL collision with pages.\r\n for (const { srcRegex } of apiRoutes)\r\n vercelRoutes.push({ src: srcRegex, dest: '/api' });\r\n}\r\n\r\n// \u2500\u2500\u2500 Build Pages function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nconst serverPages = collectServerPages(PAGES_DIR);\r\n\r\nif (serverPages.length > 0) {\r\n // Pass 1 \u2014 bundle all client components to static files.\r\n const globalRegistry = collectGlobalClientRegistry(serverPages, PAGES_DIR);\r\n const prerenderedHtml = await bundleClientComponents(globalRegistry, PAGES_DIR, STATIC_DIR);\r\n const prerenderedRecord = Object.fromEntries(prerenderedHtml);\r\n\r\n // Pass 2 \u2014 write one temp adapter per page next to its source file (so\r\n // relative imports resolve correctly), then bundle everything in\r\n // one esbuild pass via the dispatcher.\r\n const tempAdapterPaths: string[] = [];\r\n\r\n for (const page of serverPages) {\r\n const adapterDir = path.dirname(page.absPath);\r\n const adapterPath = path.join(adapterDir, `_page_adapter_${randomBytes(4).toString('hex')}.ts`);\r\n\r\n const layoutPaths = findPageLayouts(page.absPath, PAGES_DIR);\r\n const { registry, clientComponentNames } = buildPerPageRegistry(page.absPath, layoutPaths, PAGES_DIR);\r\n\r\n const layoutImports = layoutPaths\r\n .map((lp, i) => {\r\n const rel = path.relative(adapterDir, lp).replace(/\\\\/g, '/');\r\n return `import __layout_${i}__ from ${JSON.stringify(rel.startsWith('.') ? rel : './' + rel)};`;\r\n })\r\n .join('\\n');\r\n\r\n fs.writeFileSync(\r\n adapterPath,\r\n makePageAdapterSource({\r\n pageImport: JSON.stringify('./' + path.basename(page.absPath)),\r\n layoutImports,\r\n clientComponentNames,\r\n allClientIds: [...registry.keys()],\r\n layoutArrayItems: layoutPaths.map((_, i) => `__layout_${i}__`).join(', '),\r\n prerenderedHtml: prerenderedRecord,\r\n catchAllNames: page.catchAllNames,\r\n }),\r\n );\r\n\r\n tempAdapterPaths.push(adapterPath);\r\n console.log(` prepared ${path.relative(PAGES_DIR, page.absPath)} \u2192 ${page.funcPath} [page]`);\r\n }\r\n\r\n const dispatcherRoutes = serverPages.map((page, i) => ({\r\n adapterPath: tempAdapterPaths[i],\r\n srcRegex: page.srcRegex,\r\n paramNames: page.paramNames,\r\n catchAllNames: page.catchAllNames,\r\n }));\r\n\r\n const dispatcherPath = path.join(PAGES_DIR, `_pages_dispatcher_${randomBytes(4).toString('hex')}.ts`);\r\n fs.writeFileSync(dispatcherPath, makePagesDispatcherSource(dispatcherRoutes));\r\n\r\n try {\r\n const result = await build({\r\n entryPoints: [dispatcherPath],\r\n bundle: true,\r\n format: 'esm',\r\n platform: 'node',\r\n target: 'node20',\r\n jsx: 'automatic',\r\n banner: CJS_COMPAT_BANNER,\r\n external: NODE_BUILTINS,\r\n define: { 'process.env.NODE_ENV': '\"production\"' },\r\n write: false,\r\n });\r\n emitVercelFunction('pages', result.outputFiles[0].text);\r\n console.log(` built Pages dispatcher \u2192 pages.func (${serverPages.length} page(s))`);\r\n } finally {\r\n fs.unlinkSync(dispatcherPath);\r\n for (const p of tempAdapterPaths) if (fs.existsSync(p)) fs.unlinkSync(p);\r\n }\r\n\r\n for (const { srcRegex } of serverPages)\r\n vercelRoutes.push({ src: srcRegex, dest: '/pages' });\r\n}\r\n\r\n// \u2500\u2500\u2500 Vercel config \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfs.writeFileSync(\r\n path.join(OUTPUT_DIR, 'config.json'),\r\n JSON.stringify({ version: 3, routes: vercelRoutes }, null, 2),\r\n);\r\nfs.writeFileSync(\r\n path.resolve('vercel.json'),\r\n JSON.stringify({ runtime: 'nodejs20.x' }, null, 2),\r\n);\r\n\r\n// \u2500\u2500\u2500 Static assets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nawait buildCombinedBundle(STATIC_DIR);\r\ncopyPublicFiles(PUBLIC_DIR, STATIC_DIR);\r\n\r\nconst fnCount = (apiRoutes.length > 0 ? 1 : 0) + (serverPages.length > 0 ? 1 : 0);\r\nconsole.log(`\\n\u2713 Vercel build complete \u2014 ${fnCount} function(s) \u2192 .vercel/output`);\r\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/builder.d.ts CHANGED
@@ -1 +1,11 @@
1
+ /**
2
+ * builder.ts — NukeJS Package Build Script
3
+ *
4
+ * Compiles the NukeJS source into dist/ via a single esbuild pass targeting
5
+ * Node ESM, followed by processDist() which rewrites bare relative imports
6
+ * (e.g. `from './utils'`) to include .js extensions as required by Node's
7
+ * strict ESM resolver.
8
+ *
9
+ * Finally, `tsc --emitDeclarationOnly` generates .d.ts files for consumers.
10
+ */
1
11
  export {};
package/dist/builder.js CHANGED
@@ -3,38 +3,48 @@ import fs from "fs";
3
3
  import { execSync } from "child_process";
4
4
  import path from "path";
5
5
  import { fileURLToPath } from "url";
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = path.dirname(__filename);
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
7
  const srcDir = path.resolve(__dirname, "");
9
8
  const outDir = path.resolve(__dirname, "../dist");
10
- const excludeFolder = "as-is";
11
9
  function cleanDist(dir) {
12
10
  if (!fs.existsSync(dir)) return;
13
11
  fs.rmSync(dir, { recursive: true, force: true });
14
- console.log(`\u{1F5D1}\uFE0F Cleared dist folder: ${dir}`);
12
+ console.log(`\u{1F5D1}\uFE0F Cleared ${dir}`);
15
13
  }
16
- function collectFiles(dir, exclude) {
17
- const entries = fs.readdirSync(dir, { withFileTypes: true });
14
+ function collectFiles(dir, exclude = []) {
18
15
  const files = [];
19
- for (const entry of entries) {
20
- const fullPath = path.join(dir, entry.name);
16
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
17
+ const full = path.join(dir, entry.name);
21
18
  if (entry.isDirectory()) {
22
- if (!exclude.includes(entry.name)) {
23
- files.push(...collectFiles(fullPath, exclude));
24
- }
25
- } else if (entry.isFile() && fullPath.match(/\.[tj]s$/)) {
26
- files.push(fullPath);
19
+ if (!exclude.includes(entry.name)) files.push(...collectFiles(full, exclude));
20
+ } else if (/\.[tj]sx?$/.test(entry.name)) {
21
+ files.push(full);
27
22
  }
28
23
  }
29
24
  return files;
30
25
  }
31
- const entryPoints = collectFiles(srcDir, [excludeFolder]);
26
+ function processDist(dir) {
27
+ (function walk(currentDir) {
28
+ fs.readdirSync(currentDir, { withFileTypes: true }).forEach((d) => {
29
+ const fullPath = path.join(currentDir, d.name);
30
+ if (d.isDirectory()) {
31
+ walk(fullPath);
32
+ } else if (fullPath.endsWith(".js")) {
33
+ let content = fs.readFileSync(fullPath, "utf-8");
34
+ content = content.replace(/from\s+['"](\.\/.*?)['"]/g, 'from "$1.js"');
35
+ content = content.replace(/import\(['"](\.\/.*?)['"]\)/g, 'import("$1.js")');
36
+ fs.writeFileSync(fullPath, content, "utf-8");
37
+ }
38
+ });
39
+ })(dir);
40
+ console.log("\u{1F527} Post-processing done: relative imports \u2192 .js extensions.");
41
+ }
32
42
  async function runBuild() {
33
43
  try {
34
44
  cleanDist(outDir);
35
- console.log("\u{1F680} Starting esbuild...");
45
+ console.log("\u{1F680} Building sources\u2026");
36
46
  await build({
37
- entryPoints,
47
+ entryPoints: collectFiles(srcDir),
38
48
  outdir: outDir,
39
49
  platform: "node",
40
50
  format: "esm",
@@ -42,56 +52,15 @@ async function runBuild() {
42
52
  packages: "external",
43
53
  sourcemap: true
44
54
  });
45
- console.log("\u2705 Build finished.");
46
- copyFolder(path.join(srcDir, excludeFolder), path.join(outDir, excludeFolder));
55
+ console.log("\u2705 Build done.");
47
56
  processDist(outDir);
48
- console.log("\u{1F4C4} Generating TypeScript types...");
49
- execSync("tsc --emitDeclarationOnly --declaration --outDir dist", {
50
- stdio: "inherit"
51
- });
52
- console.log("\u{1F389} Build complete. dist folder is ready!");
57
+ console.log("\u{1F4C4} Generating TypeScript declarations\u2026");
58
+ execSync("tsc --emitDeclarationOnly --declaration --outDir dist", { stdio: "inherit" });
59
+ console.log("\n\u{1F389} Build complete \u2192 dist/");
53
60
  } catch (err) {
54
- console.error("\u274C Build failed:", err);
61
+ console.error("\u274C Build failed:", err);
55
62
  process.exit(1);
56
63
  }
57
64
  }
58
- function copyFolder(src, dest) {
59
- if (!fs.existsSync(src)) return;
60
- if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
61
- const entries = fs.readdirSync(src, { withFileTypes: true });
62
- for (const entry of entries) {
63
- const srcPath = path.join(src, entry.name);
64
- const destPath = path.join(dest, entry.name);
65
- if (entry.isDirectory()) {
66
- copyFolder(srcPath, destPath);
67
- } else {
68
- fs.copyFileSync(srcPath, destPath);
69
- }
70
- }
71
- console.log(`\u{1F4C1} Copied as-is folder to ${dest}`);
72
- }
73
- function processDist(dir) {
74
- const excludeFolder2 = "as-is";
75
- (function walk(currentDir) {
76
- fs.readdirSync(currentDir, { withFileTypes: true }).forEach((d) => {
77
- const fullPath = path.join(currentDir, d.name);
78
- if (d.isDirectory()) {
79
- if (d.name !== excludeFolder2) walk(fullPath);
80
- } else if (fullPath.endsWith(".js")) {
81
- let content = fs.readFileSync(fullPath, "utf-8");
82
- content = content.replace(
83
- /from\s+['"](\.\/(?!as-is\/).*?)['"]/g,
84
- 'from "$1.js"'
85
- );
86
- content = content.replace(
87
- /import\(['"](\.\/(?!as-is\/).*?)['"]\)/g,
88
- 'import("$1.js")'
89
- );
90
- fs.writeFileSync(fullPath, content, "utf-8");
91
- }
92
- });
93
- })(dir);
94
- console.log("\u{1F527} Post-processing done: .ts imports \u2192 .js (excluding as-is folder).");
95
- }
96
65
  runBuild();
97
66
  //# sourceMappingURL=builder.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/builder.ts"],
4
- "sourcesContent": ["import { build } from \"esbuild\";\r\nimport fs from \"fs\";\r\nimport { execSync } from \"child_process\";\r\nimport path from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\n\r\n// Equivalent of __dirname in ESM\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\n\r\nconst srcDir = path.resolve(__dirname, \"\");\r\nconst outDir = path.resolve(__dirname, \"../dist\");\r\nconst excludeFolder = \"as-is\";\r\n\r\n// --- Step 0: Clean dist folder ---\r\nfunction cleanDist(dir: string) {\r\n if (!fs.existsSync(dir)) return;\r\n fs.rmSync(dir, { recursive: true, force: true });\r\n console.log(`\uD83D\uDDD1\uFE0F Cleared dist folder: ${dir}`);\r\n}\r\n\r\n// --- Step 1: Collect entry points ---\r\nfunction collectFiles(dir: string, exclude: string[]): string[] {\r\n const entries = fs.readdirSync(dir, { withFileTypes: true });\r\n const files: string[] = [];\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n if (!exclude.includes(entry.name)) {\r\n files.push(...collectFiles(fullPath, exclude));\r\n }\r\n } else if (entry.isFile() && fullPath.match(/\\.[tj]s$/)) {\r\n files.push(fullPath);\r\n }\r\n }\r\n\r\n return files;\r\n}\r\n\r\nconst entryPoints = collectFiles(srcDir, [excludeFolder]);\r\n\r\n// --- Step 2: Build with esbuild ---\r\nasync function runBuild() {\r\n try {\r\n cleanDist(outDir); // Clear dist first\r\n\r\n console.log(\"\uD83D\uDE80 Starting esbuild...\");\r\n await build({\r\n entryPoints,\r\n outdir: outDir,\r\n platform: \"node\",\r\n format: \"esm\",\r\n target: [\"node20\"],\r\n packages: \"external\",\r\n sourcemap: true,\r\n });\r\n console.log(\"\u2705 Build finished.\");\r\n\r\n // --- Step 3: Copy as-is folder ---\r\n copyFolder(path.join(srcDir, excludeFolder), path.join(outDir, excludeFolder));\r\n\r\n // --- Step 4: Post-process .js files ---\r\n processDist(outDir);\r\n\r\n // --- Step 5: Compile types ---\r\n console.log(\"\uD83D\uDCC4 Generating TypeScript types...\");\r\n execSync(\"tsc --emitDeclarationOnly --declaration --outDir dist\", {\r\n stdio: \"inherit\",\r\n });\r\n\r\n console.log(\"\uD83C\uDF89 Build complete. dist folder is ready!\");\r\n } catch (err) {\r\n console.error(\"\u274C Build failed:\", err);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n// --- Copy folder recursively ---\r\nfunction copyFolder(src: string, dest: string) {\r\n if (!fs.existsSync(src)) return;\r\n if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });\r\n\r\n const entries = fs.readdirSync(src, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const srcPath = path.join(src, entry.name);\r\n const destPath = path.join(dest, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n copyFolder(srcPath, destPath);\r\n } else {\r\n fs.copyFileSync(srcPath, destPath);\r\n }\r\n }\r\n console.log(`\uD83D\uDCC1 Copied as-is folder to ${dest}`);\r\n}\r\n\r\n// --- Post-process .js files ---\r\nfunction processDist(dir: string) {\r\n const excludeFolder = \"as-is\";\r\n\r\n (function walk(currentDir: string) {\r\n fs.readdirSync(currentDir, { withFileTypes: true }).forEach((d) => {\r\n const fullPath = path.join(currentDir, d.name);\r\n\r\n if (d.isDirectory()) {\r\n if (d.name !== excludeFolder) walk(fullPath);\r\n } else if (fullPath.endsWith(\".js\")) {\r\n let content = fs.readFileSync(fullPath, \"utf-8\");\r\n\r\n // Replace import/export paths ending with .ts \u2192 .js, skip paths containing excludeFolder\r\n content = content.replace(\r\n /from\\s+['\"](\\.\\/(?!as-is\\/).*?)['\"]/g,\r\n 'from \"$1.js\"'\r\n );\r\n content = content.replace(\r\n /import\\(['\"](\\.\\/(?!as-is\\/).*?)['\"]\\)/g,\r\n 'import(\"$1.js\")'\r\n );\r\n\r\n fs.writeFileSync(fullPath, content, \"utf-8\");\r\n }\r\n });\r\n })(dir);\r\n\r\n console.log(\"\uD83D\uDD27 Post-processing done: .ts imports \u2192 .js (excluding as-is folder).\");\r\n}\r\n\r\n// Run the full build\r\nrunBuild();"],
5
- "mappings": "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",
6
- "names": ["excludeFolder"]
4
+ "sourcesContent": ["/**\r\n * builder.ts \u2014 NukeJS Package Build Script\r\n *\r\n * Compiles the NukeJS source into dist/ via a single esbuild pass targeting\r\n * Node ESM, followed by processDist() which rewrites bare relative imports\r\n * (e.g. `from './utils'`) to include .js extensions as required by Node's\r\n * strict ESM resolver.\r\n *\r\n * Finally, `tsc --emitDeclarationOnly` generates .d.ts files for consumers.\r\n */\r\n\r\nimport { build } from 'esbuild';\r\nimport fs from 'fs';\r\nimport { execSync } from 'child_process';\r\nimport path from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\r\nconst srcDir = path.resolve(__dirname, '');\r\nconst outDir = path.resolve(__dirname, '../dist');\r\n\r\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nfunction cleanDist(dir: string): void {\r\n if (!fs.existsSync(dir)) return;\r\n fs.rmSync(dir, { recursive: true, force: true });\r\n console.log(`\uD83D\uDDD1\uFE0F Cleared ${dir}`);\r\n}\r\n\r\n/** Collects all .ts/.tsx/.js/.jsx files under `dir`, skipping `exclude` dirs. */\r\nfunction collectFiles(dir: string, exclude: string[] = []): string[] {\r\n const files: string[] = [];\r\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\r\n const full = path.join(dir, entry.name);\r\n if (entry.isDirectory()) {\r\n if (!exclude.includes(entry.name)) files.push(...collectFiles(full, exclude));\r\n } else if (/\\.[tj]sx?$/.test(entry.name)) {\r\n files.push(full);\r\n }\r\n }\r\n return files;\r\n}\r\n\r\n// \u2500\u2500\u2500 Post-process .js files \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n/** Rewrites bare relative imports to include .js extensions for Node ESM. */\r\nfunction processDist(dir: string) {\r\n (function walk(currentDir: string) {\r\n fs.readdirSync(currentDir, { withFileTypes: true }).forEach((d) => {\r\n const fullPath = path.join(currentDir, d.name);\r\n if (d.isDirectory()) {\r\n walk(fullPath);\r\n } else if (fullPath.endsWith('.js')) {\r\n let content = fs.readFileSync(fullPath, 'utf-8');\r\n content = content.replace(/from\\s+['\"](\\.\\/.*?)['\"]/g, 'from \"$1.js\"');\r\n content = content.replace(/import\\(['\"](\\.\\/.*?)['\"]\\)/g, 'import(\"$1.js\")');\r\n fs.writeFileSync(fullPath, content, 'utf-8');\r\n }\r\n });\r\n })(dir);\r\n\r\n console.log('\uD83D\uDD27 Post-processing done: relative imports \u2192 .js extensions.');\r\n}\r\n\r\n// \u2500\u2500\u2500 Build \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\nasync function runBuild(): Promise<void> {\r\n try {\r\n cleanDist(outDir);\r\n\r\n console.log('\uD83D\uDE80 Building sources\u2026');\r\n await build({\r\n entryPoints: collectFiles(srcDir),\r\n outdir: outDir,\r\n platform: 'node',\r\n format: 'esm',\r\n target: ['node20'],\r\n packages: 'external',\r\n sourcemap: true,\r\n });\r\n console.log('\u2705 Build done.');\r\n\r\n processDist(outDir);\r\n\r\n console.log('\uD83D\uDCC4 Generating TypeScript declarations\u2026');\r\n execSync('tsc --emitDeclarationOnly --declaration --outDir dist', { stdio: 'inherit' });\r\n\r\n console.log('\\n\uD83C\uDF89 Build complete \u2192 dist/');\r\n } catch (err) {\r\n console.error('\u274C Build failed:', err);\r\n process.exit(1);\r\n }\r\n}\r\n\r\nrunBuild();"],
5
+ "mappings": "AAWA,SAAS,aAAa;AACtB,OAAO,QAAQ;AACf,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,MAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,MAAM,SAAS,KAAK,QAAQ,WAAW,EAAE;AACzC,MAAM,SAAS,KAAK,QAAQ,WAAW,SAAS;AAIhD,SAAS,UAAU,KAAmB;AACpC,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG;AACzB,KAAG,OAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC/C,UAAQ,IAAI,4BAAgB,GAAG,EAAE;AACnC;AAGA,SAAS,aAAa,KAAa,UAAoB,CAAC,GAAa;AACnE,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,UAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;AACtC,QAAI,MAAM,YAAY,GAAG;AACvB,UAAI,CAAC,QAAQ,SAAS,MAAM,IAAI,EAAG,OAAM,KAAK,GAAG,aAAa,MAAM,OAAO,CAAC;AAAA,IAC9E,WAAW,aAAa,KAAK,MAAM,IAAI,GAAG;AACxC,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,YAAY,KAAa;AAChC,GAAC,SAAS,KAAK,YAAoB;AACjC,OAAG,YAAY,YAAY,EAAE,eAAe,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM;AACjE,YAAM,WAAW,KAAK,KAAK,YAAY,EAAE,IAAI;AAC7C,UAAI,EAAE,YAAY,GAAG;AACnB,aAAK,QAAQ;AAAA,MACf,WAAW,SAAS,SAAS,KAAK,GAAG;AACnC,YAAI,UAAU,GAAG,aAAa,UAAU,OAAO;AAC/C,kBAAU,QAAQ,QAAQ,6BAA6B,cAAc;AACrE,kBAAU,QAAQ,QAAQ,gCAAgC,iBAAiB;AAC3E,WAAG,cAAc,UAAU,SAAS,OAAO;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH,GAAG,GAAG;AAEN,UAAQ,IAAI,yEAA6D;AAC3E;AAIA,eAAe,WAA0B;AACvC,MAAI;AACF,cAAU,MAAM;AAEhB,YAAQ,IAAI,mCAAuB;AACnC,UAAM,MAAM;AAAA,MACV,aAAa,aAAa,MAAM;AAAA,MAChC,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,QAAQ,CAAC,QAAQ;AAAA,MACjB,UAAU;AAAA,MACV,WAAW;AAAA,IACb,CAAC;AACD,YAAQ,IAAI,qBAAgB;AAE5B,gBAAY,MAAM;AAElB,YAAQ,IAAI,qDAAyC;AACrD,aAAS,yDAAyD,EAAE,OAAO,UAAU,CAAC;AAEtF,YAAQ,IAAI,0CAA8B;AAAA,EAC5C,SAAS,KAAK;AACZ,YAAQ,MAAM,yBAAoB,GAAG;AACrC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS;",
6
+ "names": []
7
7
  }