@moonsjs/vite 0.1.17 → 0.1.18

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.
@@ -1,15 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/server/shell.ts", "../src/server/node.ts", "../src/virtual-modules.ts", "../src/server/dev.ts", "../src/devtools.ts", "../src/manifest.ts"],
4
- "sourcesContent": [
5
- "import { MoonsError } from \"@moonsjs/core\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { ViteDevServer } from \"vite\";\n\nexport type Shell = (\n markup: string,\n payload: string,\n url: string,\n meta?: Record<string, unknown>,\n) => string | Promise<string>;\n\nexport const ROOT_PLACEHOLDER = '<div id=\"root\"></div>';\n\nexport const DEFAULT_TEMPLATE = [\n \"<!doctype html>\",\n '<html lang=\"id\">',\n \"<head>\",\n ' <meta charset=\"utf-8\" />',\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n \" <title>Moons</title>\",\n \"</head>\",\n \"<body>\",\n ` ${ROOT_PLACEHOLDER}`,\n ' <script type=\"module\" src=\"/src/client/main.tsx\"></script>',\n \"</body>\",\n \"</html>\",\n \"\",\n].join(\"\\n\");\n\n/** Inject markup SSR + payload devalue ke shell HTML (PRD §8.2, §17, Addendum B.1). */\nexport function injectShell(\n template: string,\n markup: string,\n payload: string,\n meta?: Record<string, unknown>,\n): string {\n if (!template.includes(ROOT_PLACEHOLDER)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n message: `shell HTML tidak memuat \\`${ROOT_PLACEHOLDER}\\``,\n details: \"index.html aplikasi wajib memuat elemen root tersebut agar SSR bisa meng-inject markup.\",\n suggestions: [\n `Tambahkan ${ROOT_PLACEHOLDER} ke index.html`,\n \"Atau hapus index.html untuk memakai shell bawaan\",\n ],\n });\n }\n const dataScript = `<script id=\"__moons_data\" type=\"application/x-moons\">${payload}</script>`;\n const withRoot = template.replace(ROOT_PLACEHOLDER, `<div id=\"root\">${markup}</div>${dataScript}`);\n return applyMeta(withRoot, meta);\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\");\n}\n\n/**\n * Terapkan meta route ke `<head>` (Addendum B.1): `<title>` + description/og.\n * Tag yang sudah ada (mis. di index.html) ditimpa; yang belum ada disisipkan\n * sebelum `</head>`.\n */\nfunction applyMeta(html: string, meta: Record<string, unknown> | undefined): string {\n if (meta === undefined) {\n return html;\n }\n let out = html;\n if (typeof meta.title === \"string\") {\n const title = `<title>${escapeHtml(meta.title)}</title>`;\n out = /<title>[\\s\\S]*?<\\/title>/.test(out)\n ? out.replace(/<title>[\\s\\S]*?<\\/title>/, title)\n : out.replace(\"</head>\", ` ${title}\\n</head>`);\n }\n\n const tags: Array<{ attr: \"name\" | \"property\"; key: string; value: unknown }> = [\n { attr: \"name\", key: \"description\", value: meta.description },\n { attr: \"property\", key: \"og:title\", value: meta.title },\n { attr: \"property\", key: \"og:description\", value: meta.description },\n ];\n for (const tag of tags) {\n if (typeof tag.value !== \"string\") {\n continue;\n }\n const rendered = `<meta ${tag.attr}=\"${tag.key}\" content=\"${escapeHtml(tag.value)}\" />`;\n const pattern = new RegExp(`<meta[^>]*${tag.attr}=\"${tag.key}\"[^>]*>`);\n out = pattern.test(out)\n ? out.replace(pattern, rendered)\n : out.replace(\"</head>\", ` ${rendered}\\n</head>`);\n }\n return out;\n}\n\n/**\n * Shell untuk dev: baca `index.html` dari disk setiap request (selalu segar)\n * lalu lewatkan ke Vite `transformIndexHtml` (inject `/@vite/client`, dsb).\n */\nexport function createDevShell(server: ViteDevServer, options: { templatePath: string }): Shell {\n return async (markup, payload, url, meta) => {\n const template = existsSync(options.templatePath)\n ? readFileSync(options.templatePath, \"utf8\")\n : DEFAULT_TEMPLATE;\n const html = injectShell(template, markup, payload, meta);\n return await server.transformIndexHtml(url, html);\n };\n}\n\n/** Shell untuk produksi: baca `dist/client/index.html` sekali dari cwd. */\nexport function createFileShell(options: { clientDir?: string } = {}): Shell {\n let cached: string | null = null;\n return async (markup, payload, _url, meta) => {\n if (cached === null) {\n const clientDir = resolve(options.clientDir ?? process.cwd(), \"dist/client\");\n const file = join(clientDir, \"index.html\");\n if (!existsSync(file)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"`dist/client/index.html` tidak ditemukan\",\n details: \"Build client harus dijalankan sebelum server produksi dinyalakan.\",\n suggestions: [\"Jalankan `bun run build` lebih dulu\"],\n });\n }\n cached = readFileSync(file, \"utf8\");\n }\n return injectShell(cached, markup, payload, meta);\n };\n}\n",
6
- "import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { CLIENT_IP_HEADER } from \"@moonsjs/core\";\n\n/** Batas transport default (Addendum J.2); RPC punya batas lebih kecil dari config. */\nexport const MAX_TRANSPORT_BODY_BYTES = 32 * 1024 * 1024;\n\n/** Request tidak valid (Host/URL malformed) → dipetakan ke 400 oleh server. */\nexport class InvalidRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidRequestError\";\n }\n}\n\n/** Body melebihi batas → dipetakan ke 413; pembacaan dihentikan saat melewati. */\nexport class BodyLimitError extends Error {\n readonly limit: number;\n constructor(limit: number) {\n super(`request body melebihi batas ${limit} byte`);\n this.name = \"BodyLimitError\";\n this.limit = limit;\n }\n}\n\nexport interface ToWebRequestOptions {\n /** Addendum J.1: percayai `x-forwarded-proto`/`x-forwarded-host` (default false). */\n trustProxy?: boolean;\n /** Batas pembacaan body (byte). Default: `MAX_TRANSPORT_BODY_BYTES`. */\n maxBodyBytes?: number;\n}\n\n/**\n * Rekonstruksi URL request (Addendum J.1). Tanpa `trustProxy`, origin/host\n * murni dari header `Host` (perilaku lama, kebal spoofing `x-forwarded-*`).\n * Malformed → `InvalidRequestError` (server memetakan ke 400).\n */\nexport function resolveRequestUrl(\n req: IncomingMessage,\n options: ToWebRequestOptions = {},\n): URL {\n const hostHeader = req.headers.host ?? \"localhost\";\n const trustProxy = options.trustProxy === true;\n const proto = trustProxy ? forwardedProtocol(req.headers[\"x-forwarded-proto\"]) : null;\n const forwardedHostValue = trustProxy ? forwardedHost(req.headers[\"x-forwarded-host\"]) : null;\n const host = forwardedHostValue ?? hostHeader;\n try {\n return new URL(`${proto ?? \"http\"}://${host}${req.url ?? \"/\"}`);\n } catch {\n throw new InvalidRequestError(`header Host tidak valid: ${JSON.stringify(hostHeader)}`);\n }\n}\n\n/** IP klien tepercaya (Addendum J.1): XFF (hanya bila trustProxy) → socket. */\nexport function resolveClientIp(req: IncomingMessage, trustProxy: boolean): string | null {\n if (trustProxy) {\n const forwarded = firstHeaderValue(req.headers[\"x-forwarded-for\"]);\n if (forwarded !== null && isPlausibleIp(forwarded)) {\n return normalizeIp(forwarded);\n }\n }\n const remote = req.socket?.remoteAddress ?? null;\n return remote === null ? null : normalizeIp(remote);\n}\n\n/** `::ffff:127.0.0.1` → `127.0.0.1`; buang zone id (`%eth0`). */\nfunction normalizeIp(value: string): string {\n const withoutZone = stripZoneId(value);\n return withoutZone.startsWith(\"::ffff:\") ? withoutZone.slice(7) : withoutZone;\n}\n\n/** Konversi request Node → Web `Request` (body diteruskan untuk non-GET/HEAD, §7.3 + J.1/J.2). */\nexport async function toWebRequest(\n req: IncomingMessage,\n options: ToWebRequestOptions = {},\n): Promise<Request> {\n const url = resolveRequestUrl(req, options);\n const method = req.method ?? \"GET\";\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined || key === \"content-length\" || key === CLIENT_IP_HEADER) {\n // content-length tidak disalin; fetch menghitung ulang dari body.\n // x-moons-client-ip selalu ditimpa nilai tepercaya di bawah.\n continue;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(key, item);\n }\n } else {\n headers.set(key, value);\n }\n }\n\n const clientIp = resolveClientIp(req, options.trustProxy === true);\n if (clientIp !== null) {\n headers.set(CLIENT_IP_HEADER, clientIp);\n }\n\n if (method === \"GET\" || method === \"HEAD\") {\n return new Request(url, { method, headers });\n }\n\n const body = await readBody(req, options.maxBodyBytes ?? MAX_TRANSPORT_BODY_BYTES);\n // View zero-copy (bukan salinan) — Buffer selalu di atas ArrayBuffer biasa.\n const view = new Uint8Array(body.buffer as ArrayBuffer, body.byteOffset, body.byteLength);\n return new Request(url, { method, headers, body: view });\n}\n\n/**\n * Baca body dengan batas tegas (Addendum J.2): begitu melewati `maxBytes`,\n * pembacaan dihentikan (pause) dan `BodyLimitError` dilempar — tidak pernah\n * seluruh body besar masuk memori, dan hanya satu salinan buffer dibuat.\n */\nexport function readBody(req: IncomingMessage, maxBytes: number): Promise<Buffer> {\n return new Promise((resolvePromise, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n let settled = false;\n\n const fail = (error: Error): void => {\n if (settled) {\n return;\n }\n settled = true;\n req.pause();\n reject(error);\n };\n\n req.on(\"data\", (chunk: Buffer) => {\n if (settled) {\n return;\n }\n size += chunk.length;\n if (size > maxBytes) {\n fail(new BodyLimitError(maxBytes));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => {\n if (!settled) {\n settled = true;\n resolvePromise(Buffer.concat(chunks));\n }\n });\n req.on(\"error\", (error) => fail(error));\n });\n}\n\n/** Addendum J.7: default aman runtime; `config.headers` tetap menang (cek hasHeader). */\nexport const DEFAULT_SECURITY_HEADERS: Record<string, string> = {\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"strict-origin-when-cross-origin\",\n};\n\n/** Tulis Web `Response` ke `ServerResponse` Node (streaming bila ada body). */\nexport async function sendNodeResponse(res: ServerResponse, response: Response): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n // `set-cookie` ditangani terpisah: forEach menggabungkan nilai ganda\n // menjadi satu string (cookie kedua hilang — D.2).\n if (key === \"set-cookie\") {\n return;\n }\n res.setHeader(key, value);\n });\n const getSetCookie = (response.headers as { getSetCookie?: () => string[] }).getSetCookie;\n if (typeof getSetCookie === \"function\") {\n const cookies = getSetCookie.call(response.headers);\n if (cookies.length > 0) {\n res.setHeader(\"set-cookie\", cookies);\n }\n } else {\n const single = response.headers.get(\"set-cookie\");\n if (single !== null) {\n res.setHeader(\"set-cookie\", single);\n }\n }\n\n for (const [name, value] of Object.entries(DEFAULT_SECURITY_HEADERS)) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n\n if (response.body === null || res.req?.method === \"HEAD\") {\n res.end();\n return;\n }\n\n // Addendum J.2: stream langsung — tidak ada `arrayBuffer()` penuh di memori.\n await pipeline(\n Readable.fromWeb(response.body as unknown as import(\"node:stream/web\").ReadableStream),\n res,\n );\n}\n\nfunction firstHeaderValue(value: string | string[] | undefined): string | null {\n if (value === undefined) {\n return null;\n }\n const raw = Array.isArray(value) ? value[0] : value;\n if (raw === undefined) {\n return null;\n }\n const first = raw.split(\",\")[0]?.trim() ?? \"\";\n return first.length === 0 ? null : first;\n}\n\nfunction forwardedProtocol(value: string | string[] | undefined): \"http\" | \"https\" | null {\n const first = firstHeaderValue(value)?.toLowerCase() ?? null;\n if (first === \"https\") {\n return \"https\";\n }\n if (first === \"http\") {\n return \"http\";\n }\n return null;\n}\n\nfunction forwardedHost(value: string | string[] | undefined): string | null {\n const first = firstHeaderValue(value);\n if (first === null || first.length === 0 || first.length > 255) {\n return null;\n }\n // hostname[:port] — tolak karakter di luar himpunan aman (spasi, CRLF, /, @, ?).\n if (!/^[A-Za-z0-9.\\-[\\]:]+$/.test(first)) {\n return null;\n }\n return first;\n}\n\nfunction isPlausibleIp(value: string): boolean {\n return value.length <= 64 && /^[0-9a-fA-F:.]+$/.test(value);\n}\n\nfunction stripZoneId(value: string): string {\n const index = value.indexOf(\"%\");\n return index === -1 ? value : value.slice(0, index);\n}\n",
7
- "/** Nama virtual module PRD §9.4. Semua di-resolve ke id `\\0`-prefix. */\nexport const VIRTUAL_MODULES = {\n routes: \"virtual:moons/routes\",\n api: \"virtual:moons/api\",\n config: \"virtual:moons/config\",\n clientEntry: \"virtual:moons/client-entry\",\n serverEntry: \"virtual:moons/server-entry\",\n} as const;\n\nexport type VirtualModuleName = (typeof VIRTUAL_MODULES)[keyof typeof VIRTUAL_MODULES];\n\nexport function isVirtualModuleId(id: string): id is VirtualModuleName {\n const clean = id.startsWith(\"\\0\") ? id.slice(1) : id;\n return (Object.values(VIRTUAL_MODULES) as string[]).includes(clean);\n}\n\nexport function toNullPrefixed(id: VirtualModuleName): `\\0${string}` {\n return `\\0${id}`;\n}\n\nexport function fromNullPrefixed(id: string): VirtualModuleName | null {\n const clean = id.startsWith(\"\\0\") ? id.slice(1) : id;\n return isVirtualModuleId(clean) ? (clean as VirtualModuleName) : null;\n}\n",
8
- "import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { ViteDevServer } from \"vite\";\nimport { VIRTUAL_MODULES } from \"../virtual-modules\";\nimport type { PayloadScanOptions } from \"../payload-scan\";\nimport type { PluginRuntime } from \"./plugins\";\nimport type { Shell } from \"./shell\";\nimport { createDevShell } from \"./shell\";\nimport {\n BodyLimitError,\n InvalidRequestError,\n resolveRequestUrl,\n sendNodeResponse,\n toWebRequest,\n} from \"./node\";\nimport { DEFAULT_BODY_LIMIT_BYTES } from \"@moonsjs/core\";\nimport { emptyDevtoolsData, renderDevtoolsHtml, type DevtoolsData } from \"../devtools\";\n\ninterface DevApp {\n handler: (request: Request) => Promise<Response>;\n plugins: PluginRuntime;\n}\n\ntype DevServerEntry = {\n createDevApp: (\n shell: Shell,\n payloadScan?: import(\"../payload-scan\").PayloadScanOptions,\n ) => DevApp;\n};\n\n/**\n * Middleware SSR dev: dipasang sebelum middleware internal Vite, menangani\n * request HTML dan RPC serverFn (`/_moons/fn/*`) — modul/aset tetap Vite.\n * Handler + lifecycle plugin (Addendum B.4) diinisialisasi sekali.\n */\nexport function installDevMiddleware(\n server: ViteDevServer,\n options: {\n templatePath: string;\n payloadScan?: PayloadScanOptions;\n apiPrefix?: string;\n /** Addendum J.1: paritas dev dengan produksi (trustProxy/bodyLimitBytes). */\n trustProxy?: boolean;\n bodyLimitBytes?: number;\n /** Addendum I.4: datasource devtools overlay (dipanggil per request). */\n devtools?: () => DevtoolsData;\n },\n): void {\n let appPromise: Promise<DevApp> | null = null;\n\n const getApp = (): Promise<DevApp> => {\n if (appPromise === null) {\n appPromise = (async () => {\n const entry = (await server.ssrLoadModule(VIRTUAL_MODULES.serverEntry)) as DevServerEntry;\n const app = entry.createDevApp(createDevShell(server, options), options.payloadScan);\n await app.plugins.start();\n await app.plugins.ready();\n return app;\n })();\n }\n return appPromise;\n };\n\n server.httpServer?.once(\"close\", () => {\n void appPromise?.then((app) => app.plugins.shutdown());\n });\n\n server.middlewares.use((req, res, next) => {\n // Addendum I.4 (W4): overlay dev-only — selalu data segar per request.\n if (\n (req.method === \"GET\" || req.method === \"HEAD\") &&\n new URL(req.url ?? \"/\", \"http://localhost\").pathname === \"/__moons/devtools\"\n ) {\n try {\n const data = options.devtools?.() ?? emptyDevtoolsData();\n res.statusCode = 200;\n res.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n res.end(req.method === \"HEAD\" ? undefined : renderDevtoolsHtml(data));\n } catch (error) {\n res.statusCode = 500;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(`[moons] devtools gagal dirender: ${String(error)}`);\n }\n return;\n }\n\n if (!shouldHandle(req, options.apiPrefix)) {\n next();\n return;\n }\n void handleRequest(getApp, req, res, options).catch((error: unknown) => {\n if (error instanceof InvalidRequestError) {\n res.statusCode = 400;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Bad Request\");\n return;\n }\n if (error instanceof BodyLimitError) {\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Payload Too Large\");\n res.once(\"finish\", () => req.destroy());\n return;\n }\n next(error as Error);\n });\n });\n}\n\nasync function handleRequest(\n getApp: () => Promise<DevApp>,\n req: IncomingMessage,\n res: ServerResponse,\n options: { trustProxy?: boolean; bodyLimitBytes?: number },\n): Promise<void> {\n const app = await getApp();\n const url = resolveRequestUrl(req, { trustProxy: options.trustProxy === true });\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n const request = await toWebRequest(req, {\n trustProxy: options.trustProxy === true,\n ...(isRpc ? { maxBodyBytes: options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES } : {}),\n });\n const response = await app.handler(request);\n await sendNodeResponse(res, response);\n}\n\nfunction shouldHandle(req: IncomingMessage, apiPrefix: string | undefined): boolean {\n const path = new URL(req.url ?? \"/\", \"http://localhost\").pathname;\n\n // RPC serverFn (semua method): dulu hanya GET/HEAD HTML yang dirutekan,\n // sehingga `POST /_moons/fn/<hash>` jatuh ke Vite (\"Cannot POST\", 404) dan\n // serverFn tidak bisa dipakai di dev (temuan eval T2 ronde 2; decisions/0016).\n if (path.startsWith(\"/_moons/fn/\")) {\n return true;\n }\n\n // Addendum D.1: endpoint `src/api` (semua method) dirutekan ke runtime.\n if (apiPrefix !== undefined && (path === apiPrefix || path.startsWith(`${apiPrefix}/`))) {\n return true;\n }\n\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n return false;\n }\n if (path.startsWith(\"/@\") || path.startsWith(\"/node_modules/\") || path.startsWith(\"/__\")) {\n return false;\n }\n const lastSegment = path.split(\"/\").pop() ?? \"\";\n if (lastSegment.includes(\".\")) {\n return false;\n }\n const accept = req.headers.accept ?? \"\";\n return accept.includes(\"text/html\") || accept.includes(\"*/*\");\n}\n",
9
- "/**\n * Addendum I.4 (W4): devtools overlay dev-only — tabel route, registry\n * serverFn (hash §12), endpoint `src/api`, dan status payload-scan.\n * Renderer murni (tanpa I/O) supaya bisa diuji unit; middleware dev yang\n * menyajikannya di `/__moons/devtools`.\n */\n\nexport interface DevtoolsRoute {\n /** Path URL (bentuk PRD §6.1), mis. \"/users/:id\". */\n path: string;\n /** \"page\" | \"layout\" | \"error\" | \"404\" | \"middleware\" | \"api\". */\n kind: string;\n /** Path relatif terhadap root app (posix). */\n file: string;\n}\n\nexport interface DevtoolsFn {\n file: string;\n name: string;\n hash: string;\n}\n\nexport interface DevtoolsData {\n routes: DevtoolsRoute[];\n apiRoutes: DevtoolsRoute[];\n serverFns: DevtoolsFn[];\n /** Canary `leakTest` terpasang → payload-scan aktif (A1). */\n canary: boolean;\n version: string;\n}\n\nexport function emptyDevtoolsData(): DevtoolsData {\n return { routes: [], apiRoutes: [], serverFns: [], canary: false, version: \"\" };\n}\n\nexport function renderDevtoolsHtml(data: DevtoolsData): string {\n const rows = (items: DevtoolsRoute[]): string =>\n items.length === 0\n ? '<tr><td colspan=\"3\" class=\"muted\">(kosong)</td></tr>'\n : items\n .map(\n (item) =>\n `<tr><td><code>${esc(item.path)}</code></td><td><span class=\"kind k-${esc(item.kind)}\">${esc(item.kind)}</span></td><td class=\"muted\">${esc(item.file)}</td></tr>`,\n )\n .join(\"\\n\");\n\n const fnRows =\n data.serverFns.length === 0\n ? '<tr><td colspan=\"3\" class=\"muted\">(tidak ada serverFn)</td></tr>'\n : data.serverFns\n .map(\n (fn) =>\n `<tr><td><code>${esc(fn.hash)}</code></td><td><code>${esc(fn.name)}</code></td><td class=\"muted\">${esc(fn.file)}</td></tr>`,\n )\n .join(\"\\n\");\n\n const canary = data.canary\n ? '<span class=\"ok\">aktif</span> (canary terpasang)'\n : '<span class=\"muted\">nonaktif</span> (tanpa canary)';\n\n return `<!doctype html>\n<html lang=\"id\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>moons devtools</title>\n<style>\n :root { color-scheme: dark; }\n body { margin: 0; padding: 2rem; background: #101418; color: #e6edf3;\n font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }\n h1 { font-size: 1.1rem; margin: 0 0 .25rem; }\n h2 { font-size: .95rem; margin: 2rem 0 .5rem; color: #9fb0c0; }\n .muted { color: #8b98a5; }\n .ok { color: #3fb950; font-weight: 600; }\n .meta { margin-bottom: 1.5rem; }\n table { border-collapse: collapse; width: 100%; max-width: 1100px; }\n th, td { text-align: left; padding: .35rem .75rem .35rem 0; border-bottom: 1px solid #1f2630; }\n th { color: #8b98a5; font-weight: 600; font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; }\n code { color: #79c0ff; }\n .kind { border: 1px solid #30363d; border-radius: 4px; padding: 0 .35rem; font-size: .8rem; }\n .k-page { color: #d2a8ff; } .k-layout { color: #7ee787; }\n .k-error { color: #ff7b72; } .k-404 { color: #ff7b72; }\n .k-middleware { color: #e3b341; } .k-api { color: #79c0ff; }\n</style>\n</head>\n<body>\n<h1>moons devtools</h1>\n<div class=\"meta muted\">@moonsjs/vite ${esc(data.version)} · dev-only · payload-scan: ${canary}</div>\n\n<h2>Routes (${data.routes.length})</h2>\n<table><thead><tr><th>path</th><th>kind</th><th>file</th></tr></thead>\n<tbody>\n${rows(data.routes)}\n</tbody></table>\n\n<h2>API (${data.apiRoutes.length})</h2>\n<table><thead><tr><th>path</th><th>kind</th><th>file</th></tr></thead>\n<tbody>\n${rows(data.apiRoutes)}\n</tbody></table>\n\n<h2>serverFn registry (${data.serverFns.length})</h2>\n<table><thead><tr><th>hash</th><th>export</th><th>file</th></tr></thead>\n<tbody>\n${fnRows}\n</tbody></table>\n</body>\n</html>\n`;\n}\n\nfunction esc(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => {\n switch (char) {\n case \"&\":\n return \"&amp;\";\n case \"<\":\n return \"&lt;\";\n case \">\":\n return \"&gt;\";\n case '\"':\n return \"&quot;\";\n default:\n return \"&#39;\";\n }\n });\n}\n",
10
- "import { findLayouts, routeKeyFromFile, type ApiRouteDefinition, type RouteDefinition } from \"@moonsjs/core\";\nimport { relative, sep } from \"node:path\";\n\nexport interface ClientManifestEntry {\n page: string;\n layouts: string[];\n}\n\n/** Key manifest untuk halaman kustom `_404` dan `_error` (§11.2). */\nexport const NOT_FOUND_ROUTE_KEY = \"__moons/404\";\nexport const ERROR_ROUTE_KEY = \"__moons/error\";\n\n/**\n * Manifest route untuk client (PRD §8.2): key = key route file\n * (routeKeyFromFile), nilai = page + layout chain dari root ke leaf.\n */\nexport function buildClientManifest(\n routes: RouteDefinition[],\n routesDir: string,\n): Record<string, ClientManifestEntry> {\n const manifest: Record<string, ClientManifestEntry> = {};\n for (const route of routes) {\n if (route.kind !== \"page\") {\n continue;\n }\n const key = routeKeyFromFile(routesDir, route.file);\n manifest[key] = {\n page: key,\n layouts: findLayouts(route, routes).map((layout) => routeKeyFromFile(routesDir, layout.file)),\n };\n }\n\n const notFound = routes.find((route) => route.kind === \"404\");\n if (notFound !== undefined) {\n manifest[NOT_FOUND_ROUTE_KEY] = { page: routeKeyFromFile(routesDir, notFound.file), layouts: [] };\n }\n const errorRoute = routes.find((route) => route.kind === \"error\");\n if (errorRoute !== undefined) {\n manifest[ERROR_ROUTE_KEY] = { page: routeKeyFromFile(routesDir, errorRoute.file), layouts: [] };\n }\n // D.3: semua boundary `_error` (termasuk bersarang) ikut manifest — payload\n // memakai key file boundary yang dipilih runtime.\n for (const route of routes) {\n if (route.kind !== \"error\") {\n continue;\n }\n const key = routeKeyFromFile(routesDir, route.file);\n manifest[key] = { page: key, layouts: [] };\n }\n\n return manifest;\n}\n\n/** `virtual:moons/api` (Addendum D.1 + D.3): tabel API + middleware + peta import(). */\nexport function renderApiModule(\n apiRoutes: ApiRouteDefinition[],\n apiMiddlewares: ReadonlyArray<{ file: string; dir: string }>,\n projectRoot: string,\n): string {\n const loadEntries = apiRoutes\n .map(\n (route) =>\n ` ${JSON.stringify(route.path)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, route.file))}),`,\n )\n .join(\"\\n\");\n const middlewareEntries = apiMiddlewares\n .map(\n (middleware) =>\n ` ${JSON.stringify(middleware.file)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, middleware.file))}),`,\n )\n .join(\"\\n\");\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n `export const apiRoutes = ${JSON.stringify(apiRoutes, null, 2)};`,\n `export const apiMiddlewares = ${JSON.stringify(apiMiddlewares, null, 2)};`,\n \"export const loadApi = {\",\n loadEntries,\n \"};\",\n \"export const loadApiMiddleware = {\",\n middlewareEntries,\n \"};\",\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Isi `virtual:moons/routes`: daftar RouteDefinition, manifest client, dan\n * peta import() dinamis per file route (specifier root-relative).\n */\nexport function renderRoutesModule(\n routes: RouteDefinition[],\n routesDir: string,\n projectRoot: string,\n): string {\n const manifest = buildClientManifest(routes, routesDir);\n\n const loadEntries = routes.map((route) => {\n const key = routeKeyFromFile(routesDir, route.file);\n return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, route.file))}),`;\n });\n\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n `export const routes = ${JSON.stringify(routes, null, 2)};`,\n \"\",\n `export const clientManifest = ${JSON.stringify(manifest, null, 2)};`,\n \"\",\n \"export const loadRoute = {\",\n ...loadEntries,\n \"};\",\n \"\",\n ].join(\"\\n\");\n}\n\n/** Path file absolut project → specifier root-relative yang bisa di-resolve Vite. */\nexport function rootSpecifier(projectRoot: string, file: string): string {\n let rel = relative(projectRoot, file);\n rel = sep === \"/\" ? rel : rel.split(sep).join(\"/\");\n return rel.startsWith(\"/\") ? rel : `/${rel}`;\n}\n"
11
- ],
12
- "mappings": "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",
13
- "debugId": "9EF4B5AD3ED4C6D264756E2164756E21",
14
- "names": []
15
- }