@moonsjs/vite 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -2
- package/dist/index-8xq8fcgq.js +222 -0
- package/dist/index-8xq8fcgq.js.map +14 -0
- package/dist/index-fg6nqart.js +776 -0
- package/dist/index-fg6nqart.js.map +10 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +423 -0
- package/dist/index.js.map +11 -0
- package/dist/leak-check.d.ts +14 -0
- package/dist/leak-check.d.ts.map +1 -0
- package/dist/manifest.d.ts +21 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/server/dev.d.ts +9 -0
- package/dist/server/dev.d.ts.map +1 -0
- package/dist/server/handler.d.ts +18 -0
- package/dist/server/handler.d.ts.map +1 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +311 -0
- package/dist/server/index.js.map +13 -0
- package/dist/server/node-server.d.ts +17 -0
- package/dist/server/node-server.d.ts.map +1 -0
- package/dist/server/node.d.ts +6 -0
- package/dist/server/node.d.ts.map +1 -0
- package/dist/server/shell.d.ts +18 -0
- package/dist/server/shell.d.ts.map +1 -0
- package/dist/server/shutdown.d.ts +17 -0
- package/dist/server/shutdown.d.ts.map +1 -0
- package/dist/server/test-server.d.ts +21 -0
- package/dist/server/test-server.d.ts.map +1 -0
- package/dist/transform.d.ts +101 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +34 -0
- package/dist/transform.js.map +9 -0
- package/dist/virtual-modules.d.ts +12 -0
- package/dist/virtual-modules.d.ts.map +1 -0
- package/package.json +51 -4
- package/src/ctx-fallback.d.ts +9 -0
- package/src/index.ts +2 -0
- package/src/leak-check.ts +36 -0
- package/src/manifest.ts +79 -0
- package/src/plugin.ts +471 -0
- package/src/server/dev.ts +54 -0
- package/src/server/handler.ts +249 -0
- package/src/server/index.ts +12 -0
- package/src/server/node-server.ts +115 -0
- package/src/server/node.ts +61 -0
- package/src/server/shell.ts +77 -0
- package/src/server/shutdown.ts +64 -0
- package/src/server/test-server.ts +44 -0
- package/src/transform.ts +1073 -0
- package/src/virtual-modules.ts +23 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/transform.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { MoonsError, computeFnHash, fnRegistryKey } from \"@moonsjs/core\";\nimport { parse } from \"@babel/parser\";\nimport { existsSync, readdirSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\n\n/**\n * Spec §12: analisis `.server.ts` + stub client + injeksi meta server +\n * penolakan import (E_SERVER_IMPORT_IN_CLIENT / E_FORBIDDEN_SERVER_IMPORT).\n */\n\nexport interface ServerFnInfo {\n name: string;\n hash: string;\n line: number;\n input: { start: number; end: number };\n output: { start: number; end: number };\n objectStart: number;\n}\n\nexport interface ServerFileAnalysis {\n /** Absolute path. */\n file: string;\n serverFns: ServerFnInfo[];\n /** Semua nama export top-level (langsung). */\n exportNames: string[];\n /** Pernyataan `export { X as Y } from \"./z.server\"` (untuk resolusi re-export). */\n reExports: Array<{ source: string; names: Array<{ local: string; exported: string }> }>;\n /** `export * from \"./z.server\"`. */\n exportAllFrom: string[];\n}\n\ninterface AstNode {\n type: string;\n start: number | null;\n end: number | null;\n loc?: { start: { line: number } } | null;\n [key: string]: unknown;\n}\n\nconst SERVER_SPECIFIER = /\\.server(\\.(ts|tsx|js|jsx|mts|cts|mjs|cjs))?$/i;\nconst CONTRACT_SERVER_FILE = /\\.server\\.(ts|tsx)$/i;\nconst NON_CONTRACT_SERVER_FILE = /\\.server\\.(js|jsx|mts|cts|mjs|cjs)$/i;\n\nexport function isServerFilePath(path: string): boolean {\n return CONTRACT_SERVER_FILE.test(stripQuery(path));\n}\n\n/** File server dengan ekstensi di luar kontrak §12 (tidak bisa di-stub). */\nexport function isNonContractServerFile(path: string): boolean {\n return NON_CONTRACT_SERVER_FILE.test(stripQuery(path));\n}\n\nexport function isServerSpecifier(specifier: string): boolean {\n return SERVER_SPECIFIER.test(specifier);\n}\n\n/**\n * Resolusi sinkron untuk specifier `*.server` (relatif/absolut).\n * Import alias/virtual untuk file server tidak didukung — tidak dibutuhkan app.\n */\nexport function resolveServerSpecifierSync(importerFile: string, specifier: string): string | null {\n if (!isServerSpecifier(specifier)) {\n return null;\n }\n const base = specifier.startsWith(\".\")\n ? resolve(dirname(importerFile), specifier)\n : isAbsolute(specifier)\n ? specifier\n : null;\n if (base === null) {\n return null;\n }\n for (const candidate of [base, `${base}.ts`, `${base}.tsx`]) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n return null;\n}\n\nexport function stripQuery(id: string): string {\n const queryIndex = id.indexOf(\"?\");\n return queryIndex === -1 ? id : id.slice(0, queryIndex);\n}\n\nfunction parseModule(code: string, filename: string): AstNode {\n return parse(code, {\n sourceType: \"module\",\n plugins: filename.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n errorRecovery: false,\n }) as unknown as AstNode;\n}\n\nfunction walk(\n node: unknown,\n visit: (node: AstNode, ancestors: AstNode[]) => void,\n ancestors: AstNode[] = [],\n): void {\n if (node === null || typeof node !== \"object\") {\n return;\n }\n if (Array.isArray(node)) {\n for (const item of node) {\n walk(item, visit, ancestors);\n }\n return;\n }\n const candidate = node as AstNode;\n if (typeof candidate.type !== \"string\" || typeof candidate.start !== \"number\") {\n return;\n }\n visit(candidate, ancestors);\n const nextAncestors = [...ancestors, candidate];\n for (const key of Object.keys(candidate)) {\n if (key === \"loc\" || key === \"start\" || key === \"end\" || key === \"extra\") {\n continue;\n }\n walk(candidate[key], visit, nextAncestors);\n }\n}\n\nfunction topLevelStatements(ast: AstNode): AstNode[] {\n const program = ast[\"program\"] as { body?: AstNode[] } | undefined;\n return program?.body ?? [];\n}\n\nfunction keyName(node: unknown): string | null {\n const key = node as AstNode | undefined;\n if (key?.type === \"Identifier\") {\n return key[\"name\"] as string;\n }\n if (key?.type === \"StringLiteral\") {\n return key[\"value\"] as string;\n }\n return null;\n}\n\nfunction extractServerFnInit(init: unknown): {\n input: { start: number; end: number };\n output: { start: number; end: number };\n line: number;\n objectStart: number;\n} | null {\n const call = init as AstNode | undefined;\n if (call?.type !== \"CallExpression\") {\n return null;\n }\n const callee = call[\"callee\"] as AstNode | undefined;\n if (callee?.type !== \"Identifier\" || callee[\"name\"] !== \"serverFn\") {\n return null;\n }\n const args = (call[\"arguments\"] ?? []) as AstNode[];\n const first = args[0];\n if (first?.type !== \"ObjectExpression\") {\n return null;\n }\n\n const properties = new Map<string, AstNode>();\n for (const property of (first[\"properties\"] ?? []) as AstNode[]) {\n if (property.type !== \"ObjectProperty\") {\n continue;\n }\n const name = keyName(property[\"key\"]);\n if (name !== null) {\n properties.set(name, property);\n }\n }\n\n const input = properties.get(\"input\")?.[\"value\"] as AstNode | undefined;\n const output = properties.get(\"output\")?.[\"value\"] as AstNode | undefined;\n if (\n input?.start == null ||\n input.end == null ||\n output?.start == null ||\n output.end == null\n ) {\n return null;\n }\n\n return {\n input: { start: input.start, end: input.end },\n output: { start: output.start, end: output.end },\n line: call.loc?.start.line ?? 1,\n objectStart: first.start ?? 0,\n };\n}\n\nexport function analyzeServerFile(\n source: string,\n filename: string,\n projectRoot: string,\n): ServerFileAnalysis {\n const ast = parseModule(source, filename);\n const serverFns: ServerFnInfo[] = [];\n const exportNames: string[] = [];\n const reExports: ServerFileAnalysis[\"reExports\"] = [];\n const exportAllFrom: string[] = [];\n\n for (const statement of topLevelStatements(ast)) {\n if (statement.type === \"ExportNamedDeclaration\") {\n const declaration = statement[\"declaration\"] as AstNode | null | undefined;\n\n if (declaration?.type === \"VariableDeclaration\") {\n for (const declarator of (declaration[\"declarations\"] ?? []) as AstNode[]) {\n const id = declarator[\"id\"] as AstNode | undefined;\n if (id?.type !== \"Identifier\") {\n continue;\n }\n const name = id[\"name\"] as string;\n exportNames.push(name);\n const info = extractServerFnInit(declarator[\"init\"]);\n if (info !== null) {\n serverFns.push({\n name,\n hash: computeFnHash(projectRoot, filename, name),\n line: info.line,\n input: info.input,\n output: info.output,\n objectStart: info.objectStart,\n });\n }\n }\n } else if (declaration?.type === \"FunctionDeclaration\") {\n const id = declaration[\"id\"] as AstNode | undefined;\n if (id?.type === \"Identifier\") {\n exportNames.push(id[\"name\"] as string);\n }\n }\n\n for (const specifier of (statement[\"specifiers\"] ?? []) as AstNode[]) {\n const exported = specifier[\"exported\"] as AstNode | undefined;\n if (exported?.type === \"Identifier\") {\n exportNames.push(exported[\"name\"] as string);\n }\n }\n\n const sourceNode = statement[\"source\"] as AstNode | undefined;\n if (sourceNode?.type === \"StringLiteral\" && isServerSpecifier(sourceNode[\"value\"] as string)) {\n reExports.push({\n source: sourceNode[\"value\"] as string,\n names: ((statement[\"specifiers\"] ?? []) as AstNode[]).map((specifier) => ({\n local: ((specifier[\"local\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\",\n exported: (((specifier[\"exported\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\"),\n })),\n });\n }\n } else if (statement.type === \"ExportDefaultDeclaration\") {\n exportNames.push(\"default\");\n } else if (statement.type === \"ExportAllDeclaration\") {\n const sourceNode = statement[\"source\"] as AstNode | undefined;\n if (sourceNode?.type === \"StringLiteral\" && isServerSpecifier(sourceNode[\"value\"] as string)) {\n exportAllFrom.push(sourceNode[\"value\"] as string);\n }\n }\n }\n\n return { file: filename, serverFns, exportNames, reExports, exportAllFrom };\n}\n\n/** Nama-nama yang diekspor sebagai serverFn stub dari file (langsung atau via re-export). */\nexport function serverFnExportNames(\n analysis: ServerFileAnalysis,\n analyzeTarget: (specifier: string) => ServerFileAnalysis | null,\n seen = new Set<string>(),\n): Set<string> {\n const names = new Set(analysis.serverFns.map((fn) => fn.name));\n\n for (const reExport of analysis.reExports) {\n const target = analyzeTarget(reExport.source);\n if (target === null || seen.has(reExport.source)) {\n continue;\n }\n seen.add(reExport.source);\n const targetNames = serverFnExportNames(target, analyzeTarget, seen);\n for (const { local, exported } of reExport.names) {\n if (local === \"*\" || targetNames.has(local)) {\n names.add(exported);\n }\n }\n }\n\n for (const specifier of analysis.exportAllFrom) {\n const target = analyzeTarget(specifier);\n if (target === null || seen.has(specifier)) {\n continue;\n }\n seen.add(specifier);\n for (const name of serverFnExportNames(target, analyzeTarget, seen)) {\n names.add(name);\n }\n }\n\n return names;\n}\n\nfunction collectRetainedText(source: string, analysis: ServerFileAnalysis): string {\n return analysis.serverFns\n .map((fn) => `${source.slice(fn.input.start, fn.input.end)}\\n${source.slice(fn.output.start, fn.output.end)}`)\n .join(\"\\n\");\n}\n\nfunction isUsed(name: string, retainedText: string): boolean {\n return new RegExp(`(^|[^\\\\w$])${escapeRegExp(name)}([^\\\\w$]|$)`).test(retainedText);\n}\n\nfunction escapeRegExp(text: string): string {\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport interface StubDependencies {\n /** Resolve specifier relatif file sumber → analysis (null bila tidak bisa). */\n analyzeSpecifier: (sourceFile: string, specifier: string) => ServerFileAnalysis | null;\n}\n\nexport interface RenderStubResult {\n code: string;\n /** Specifier server file yang di-referensikan (untuk keperluan cache/diagnostik). */\n referenced: string[];\n}\n\n/**\n * Bangun stub client §12.2/§12.3 dari sumber `.server.ts`:\n * hanya import yang dipakai schema + `__moons_createStub` per serverFn.\n */\nexport function renderServerFnStub(\n source: string,\n filename: string,\n analysis: ServerFileAnalysis,\n dependencies: StubDependencies,\n): RenderStubResult {\n const ast = parseModule(source, filename);\n const retainedText = collectRetainedText(source, analysis);\n const importLines: string[] = [];\n const referenced: string[] = [];\n let needsCreateStub = analysis.serverFns.length > 0;\n\n for (const statement of topLevelStatements(ast)) {\n if (statement.type !== \"ImportDeclaration\") {\n continue;\n }\n const sourceNode = statement[\"source\"] as AstNode;\n const specifier = sourceNode[\"value\"] as string;\n\n if (/^@moons\\/server(\\/|$)/.test(specifier)) {\n continue; // serverFn/env tidak dibawa ke client (§12.2)\n }\n if (specifier.startsWith(\"node:\") || specifier.startsWith(\"bun:\")) {\n continue; // import server-only dibuang\n }\n\n const specifiers = (statement[\"specifiers\"] ?? []) as AstNode[];\n const kept: AstNode[] = [];\n\n if (isServerSpecifier(specifier)) {\n referenced.push(specifier);\n for (const item of specifiers) {\n if (item.type === \"ImportDefaultSpecifier\" || item.type === \"ImportNamespaceSpecifier\") {\n continue; // default / * as dari *.server → dibuang (§12.2)\n }\n const local = ((item[\"local\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\";\n if (local.length > 0 && isUsed(local, retainedText)) {\n kept.push(item);\n }\n }\n } else {\n for (const item of specifiers) {\n const local = ((item[\"local\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\";\n if (local.length > 0 && isUsed(local, retainedText)) {\n kept.push(item);\n }\n }\n }\n\n if (kept.length === 0) {\n continue; // import tak terpakai → dipangkas (§12.3)\n }\n\n const keptText = kept\n .map((item) => source.slice(item.start ?? 0, item.end ?? 0))\n .join(\", \");\n importLines.push(`import { ${keptText} } from ${JSON.stringify(specifier)};`);\n }\n\n if (needsCreateStub) {\n importLines.push('import { __moons_createStub } from \"@moonsjs/server/client\";');\n }\n\n const exportLines: string[] = [];\n for (const fn of analysis.serverFns) {\n const input = source.slice(fn.input.start, fn.input.end);\n const output = source.slice(fn.output.start, fn.output.end);\n exportLines.push(\n `export const ${fn.name} = __moons_createStub({ hash: ${JSON.stringify(fn.hash)}, input: ${input}, output: ${output} });`,\n );\n }\n\n for (const reExport of analysis.reExports) {\n const target = dependencies.analyzeSpecifier(filename, reExport.source);\n if (target === null) {\n throw new MoonsError({\n code: \"E_SERVER_IMPORT_IN_CLIENT\",\n file: filename,\n message: `tidak bisa me-resolve \\`${reExport.source}\\` untuk re-export`,\n details: \"Re-export dari `*.server.ts` harus bisa di-resolve statis (PRD §12.6).\",\n suggestions: [\"Perbaiki path re-export\", \"Hindari re-export dinamis dari file server\"],\n });\n }\n const targetNames = serverFnExportNames(target, (specifier) =>\n dependencies.analyzeSpecifier(filename, specifier),\n );\n const keptNames = reExport.names.filter(({ local }) => local !== \"\" && targetNames.has(local));\n if (keptNames.length > 0) {\n const specifiers = keptNames\n .map(({ local, exported }) => (local === exported ? local : `${local} as ${exported}`))\n .join(\", \");\n exportLines.push(`export { ${specifiers} } from ${JSON.stringify(reExport.source)};`);\n }\n }\n\n for (const specifier of analysis.exportAllFrom) {\n const target = dependencies.analyzeSpecifier(filename, specifier);\n if (target === null) {\n throw new MoonsError({\n code: \"E_SERVER_IMPORT_IN_CLIENT\",\n file: filename,\n message: `\\`export *\\` dari \\`${specifier}\\` tidak bisa di-resolve`,\n details: \"`export *` dari `*.server.ts` wajib bisa di-expand statis (PRD §12.6).\",\n suggestions: [\"Perbaiki path re-export\", \"Ganti menjadi named re-export\"],\n });\n }\n const targetNames = serverFnExportNames(target, (nested) =>\n dependencies.analyzeSpecifier(filename, nested),\n );\n if (targetNames.size > 0) {\n exportLines.push(\n `export { ${[...targetNames].join(\", \")} } from ${JSON.stringify(specifier)};`,\n );\n }\n }\n\n if (importLines.length === 0 && exportLines.length === 0) {\n return { code: \"// @moons: tidak ada serverFn yang di-export\\nexport {};\\n\", referenced };\n }\n\n return { code: `${[...importLines, \"\", ...exportLines].join(\"\\n\")}\\n`, referenced };\n}\n\n/** Inject meta §7.2 ke deklarasi serverFn (env ssr; handler tetap utuh). */\nexport function injectServerFnMeta(\n source: string,\n analysis: ServerFileAnalysis,\n projectRoot: string,\n): string {\n let output = source;\n const inserts = [...analysis.serverFns].sort((a, b) => b.objectStart - a.objectStart);\n\n for (const fn of inserts) {\n const meta =\n ` __hash: ${JSON.stringify(fn.hash)},` +\n ` __file: ${JSON.stringify(fnRegistryKey(projectRoot, analysis.file, fn.name).split(\"#\")[0] as string)},` +\n ` __line: ${fn.line},` +\n ` __exportName: ${JSON.stringify(fn.name)},`;\n const at = fn.objectStart + 1;\n output = output.slice(0, at) + meta + output.slice(at);\n }\n\n return output;\n}\n\nexport interface ClientImportCheckContext {\n /** Absolute path file yang sedang diperiksa. */\n file: string;\n code: string;\n projectRoot: string;\n /**\n * Resolve specifier dengan importer tertentu → absolute path (null bila tidak\n * ada). Boleh sinkron maupun async (plugin memakai `this.resolve`, sehingga\n * alias Vite & `tsconfig paths` ikut terperiksa — audit ronde 2).\n */\n resolve: (specifier: string, importer: string) => string | null | Promise<string | null>;\n /** Analysis untuk file server (hasil cache plugin). */\n analyze: (absoluteFile: string) => ServerFileAnalysis | null;\n}\n\n/** Nama serverFn (langsung atau via re-export) — versi async untuk pemeriksaan resolve. */\nasync function serverFnExportNamesAsync(\n analysis: ServerFileAnalysis,\n analyzeSpecifier: (specifier: string, importer: string) => Promise<ServerFileAnalysis | null>,\n seen = new Set<string>(),\n): Promise<Set<string>> {\n const names = new Set(analysis.serverFns.map((fn) => fn.name));\n\n for (const reExport of analysis.reExports) {\n const key = `${analysis.file}\\0${reExport.source}`;\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n const target = await analyzeSpecifier(reExport.source, analysis.file);\n if (target === null) {\n continue;\n }\n const targetNames = await serverFnExportNamesAsync(target, analyzeSpecifier, seen);\n for (const { local, exported } of reExport.names) {\n if (local === \"*\" || targetNames.has(local)) {\n names.add(exported);\n }\n }\n }\n\n for (const specifier of analysis.exportAllFrom) {\n const key = `${analysis.file}\\0${specifier}`;\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n const target = await analyzeSpecifier(specifier, analysis.file);\n if (target === null) {\n continue;\n }\n for (const name of await serverFnExportNamesAsync(target, analyzeSpecifier, seen)) {\n names.add(name);\n }\n }\n\n return names;\n}\n\nexport function nonContractServerFileError(file: string, projectRoot: string): MoonsError {\n return new MoonsError({\n code: \"E_SERVER_IMPORT_IN_CLIENT\",\n file: toRelative(projectRoot, file),\n message: \"file server memakai ekstensi di luar kontrak §12\",\n details:\n \"Transform zero-trust hanya menangani `*.server.ts`/`*.server.tsx`; file server dengan ekstensi lain tidak bisa di-stub dan tidak boleh masuk graph client.\",\n suggestions: [\n \"Ganti nama file menjadi `*.server.ts`/`*.server.tsx` dan taruh `serverFn` di dalamnya\",\n \"Atau pindahkan nilai yang dibutuhkan ke file non-server\",\n ],\n });\n}\n\n/** Periksa import modul client terhadap §12.4/§12.7/§12.8 — berbasis hasil resolve. */\nexport async function checkClientModuleImports(\n context: ClientImportCheckContext,\n): Promise<void> {\n const { file, code, projectRoot, resolve, analyze } = context;\n const ast = parseModule(code, file);\n const relativeFile = toRelative(projectRoot, file);\n\n const resolveSafe = async (specifier: string, importer: string): Promise<string | null> => {\n try {\n const result = await resolve(specifier, importer);\n if (result === null) {\n return null;\n }\n const clean = stripQuery(result);\n // Audit ronde 2: normalisasi realpath — symlink ke `*.server.ts` harus\n // tertangkap walau resolver mengembalikan path link.\n try {\n return realpathSync(clean);\n } catch {\n return clean;\n }\n } catch {\n return null;\n }\n };\n\n const analyzeResolved = async (\n specifier: string,\n importer: string,\n ): Promise<ServerFileAnalysis | null> => {\n const absolute = await resolveSafe(specifier, importer);\n return absolute === null ? null : analyze(absolute);\n };\n\n const isAllowedServerFnImport = async (\n resolvedTarget: string | null,\n specifier: string,\n name: string,\n ): Promise<boolean> => {\n const target =\n resolvedTarget === null ? await analyzeResolved(specifier, file) : analyze(resolvedTarget);\n if (target === null) {\n return false;\n }\n const names = await serverFnExportNamesAsync(target, (nested, importer) =>\n analyzeResolved(nested, importer),\n );\n return names.has(name);\n };\n\n const reject = (line: number, message: string, details: string): never => {\n throw new MoonsError({\n code: \"E_SERVER_IMPORT_IN_CLIENT\",\n file: relativeFile,\n line,\n message,\n details,\n suggestions: [\n \"Buat server function yang mengembalikan data yang dibutuhkan, atau\",\n \"Pindahkan nilai itu ke file yang tidak berakhiran .server.ts\",\n ],\n });\n };\n\n const rejectForbidden = (line: number, specifier: string): never => {\n throw new MoonsError({\n code: \"E_FORBIDDEN_SERVER_IMPORT\",\n file: relativeFile,\n line,\n message: `mengimpor \\`${specifier}\\` di modul client`,\n details: \"Modul server-only hanya boleh di-import dari *.server.ts.\",\n suggestions: [\n \"Pindahkan operasi tersebut ke serverFn, atau\",\n \"Hapus import tersebut\",\n ],\n });\n };\n\n for (const statement of topLevelStatements(ast)) {\n if (statement.type === \"ImportDeclaration\" || statement.type === \"ExportNamedDeclaration\" || statement.type === \"ExportAllDeclaration\") {\n const sourceNode = statement[\"source\"] as AstNode | null | undefined;\n if (sourceNode?.type !== \"StringLiteral\") {\n continue;\n }\n const rawSpecifier = sourceNode[\"value\"] as string;\n // Query Vite (`?raw`, `?url`, `?inline`, dst.) dinormalisasi untuk\n // pencocokan & resolusi (audit adversarial M6).\n const specifier = stripQuery(rawSpecifier);\n const line = statement.loc?.start.line ?? 1;\n\n if (specifier.startsWith(\"node:\") || specifier.startsWith(\"bun:\")) {\n rejectForbidden(line, specifier);\n }\n\n const resolvedTarget = await resolveSafe(specifier, file);\n\n // Audit ronde 2: file server di luar kontrak §12 ditolak (tidak bisa di-stub).\n if (resolvedTarget !== null && isNonContractServerFile(resolvedTarget)) {\n throw nonContractServerFileError(resolvedTarget, projectRoot);\n }\n\n // Audit ronde 2: keputusan berbasis hasil resolve — menangkap alias Vite,\n // `tsconfig paths`, dan symlink (realpath) yang menunjuk `*.server.ts`.\n const serverBySpecifier = isServerSpecifier(specifier);\n const serverByResolve = resolvedTarget !== null && isServerFilePath(resolvedTarget);\n if (!serverBySpecifier && !serverByResolve) {\n continue;\n }\n\n const targetRelative =\n resolvedTarget === null ? rawSpecifier : toRelative(projectRoot, resolvedTarget);\n\n if (statement.type === \"ExportAllDeclaration\") {\n if (resolvedTarget === null) {\n reject(line, `\\`export *\\` dari \\`${targetRelative}\\` tidak bisa di-resolve`, \"Re-export dari `*.server.ts` wajib bisa di-resolve statis (PRD §12.6).\");\n }\n continue; // aman: target menjadi stub\n }\n\n const specifiers = (statement[\"specifiers\"] ?? []) as AstNode[];\n for (const item of specifiers) {\n if (item.type === \"ImportDefaultSpecifier\") {\n reject(line, `mengimpor default dari ${targetRelative}`, \"Default export dari file server tidak boleh menyeberang ke client.\");\n }\n if (item.type === \"ImportNamespaceSpecifier\") {\n reject(line, `mengimpor namespace (\\`* as\\`) dari ${targetRelative}`, \"Import namespace dari file server tidak boleh menyeberang ke client.\");\n }\n const name = ((item[\"local\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\";\n const kind = (item[\"importKind\"] as string | undefined) ?? (statement[\"importKind\"] as string | undefined);\n if (kind === \"type\") {\n reject(line, `mengimpor type \\`${name}\\` dari ${targetRelative}`, \"Import dari file server tidak diizinkan di modul client (PRD §12.4).\");\n }\n if (name.length > 0 && !(await isAllowedServerFnImport(resolvedTarget, specifier, name))) {\n reject(\n line,\n `mengimpor \\`${name}\\` dari ${targetRelative}`,\n \"Kode server tidak boleh muncul di client.\\nHanya `serverFn` yang diizinkan menyeberang.\",\n );\n }\n }\n }\n }\n\n // §12.4: pemanggilan env() di modul client (juga @moonsjs/server import env).\n const envBindings = new Set<string>();\n for (const statement of topLevelStatements(ast)) {\n if (statement.type !== \"ImportDeclaration\") {\n continue;\n }\n const sourceNode = statement[\"source\"] as AstNode | undefined;\n const specifier = sourceNode?.type === \"StringLiteral\" ? (sourceNode[\"value\"] as string) : \"\";\n if (specifier !== \"@moonsjs/server\" && !specifier.startsWith(\"@moonsjs/server/\")) {\n continue;\n }\n for (const item of (statement[\"specifiers\"] ?? []) as AstNode[]) {\n if (item.type !== \"ImportSpecifier\") {\n continue;\n }\n const imported = item[\"imported\"] as AstNode | undefined;\n const local = item[\"local\"] as AstNode | undefined;\n if (imported?.type === \"Identifier\" && imported[\"name\"] === \"env\" && local?.type === \"Identifier\") {\n envBindings.add(local[\"name\"] as string);\n }\n }\n }\n\n if (envBindings.size > 0) {\n walk(ast, (node) => {\n if (node.type !== \"CallExpression\") {\n return;\n }\n const callee = node[\"callee\"] as AstNode | undefined;\n if (callee?.type !== \"Identifier\" || !envBindings.has(callee[\"name\"] as string)) {\n return;\n }\n const callText = code\n .slice(node.start ?? 0, node.end ?? 0)\n .replace(/\\s+/g, \" \")\n .slice(0, 80);\n throw new MoonsError({\n code: \"E_ENV_IN_CLIENT\",\n file: relativeFile,\n line: node.loc?.start.line ?? 1,\n message: `memanggil \\`${callText}\\` di modul yang masuk client`,\n details: \"`env()` hanya legal di server.\",\n suggestions: [\n \"Pindahkan pemanggilan ke dalam serverFn, atau\",\n \"Gunakan import.meta.env untuk nilai publik\",\n ],\n });\n });\n }\n\n // Dynamic import (§12.7/§12.8) — literal maupun template dengan teks `.server`,\n // plus resolusi (alias/tsconfig paths/symlink) — audit ronde 2.\n const dynamicRequests: Array<{ request: DynamicImportRequest; guarded: boolean }> = [];\n walk(ast, (node, ancestors) => {\n const request = dynamicImportRequest(node);\n if (request !== null) {\n dynamicRequests.push({\n request,\n guarded: ancestors.some((ancestor) => isDevGuard(ancestor)),\n });\n }\n });\n\n for (const { request, guarded } of dynamicRequests) {\n if (guarded) {\n continue; // §12.8: branch DEV/PROD mati saat build → tidak perlu diperiksa\n }\n\n const specifier = stripQuery(request.text);\n const resolvedTarget = await resolveSafe(specifier, file);\n\n if (resolvedTarget !== null && isNonContractServerFile(resolvedTarget)) {\n throw nonContractServerFileError(resolvedTarget, projectRoot);\n }\n\n const serverBySpecifier = isServerSpecifier(specifier);\n const serverByResolve = resolvedTarget !== null && isServerFilePath(resolvedTarget);\n if (!serverBySpecifier && !serverByResolve) {\n continue;\n }\n\n const targetRelative =\n resolvedTarget === null ? request.text : toRelative(projectRoot, resolvedTarget);\n reject(request.node.loc?.start.line ?? 1, `mengimpor (dynamic) \\`${request.text}\\` dari ${targetRelative}`, \"Client tidak boleh melakukan dynamic import ke `*.server.ts` (PRD §12.7).\");\n }\n\n // `import.meta.glob` yang mencakup `*.server.ts` (§12.7) — audit adversarial M6.\n walk(ast, (node) => {\n if (node.type !== \"CallExpression\") {\n return;\n }\n const callee = node[\"callee\"] as AstNode | undefined;\n if (callee?.type !== \"MemberExpression\") {\n return;\n }\n const object = callee[\"object\"] as AstNode | undefined;\n const property = callee[\"property\"] as AstNode | undefined;\n if (\n object?.type !== \"MetaProperty\" ||\n property?.type !== \"Identifier\" ||\n property[\"name\"] !== \"glob\"\n ) {\n return;\n }\n\n for (const pattern of globPatterns(((node[\"arguments\"] ?? []) as AstNode[])[0])) {\n if (!isServerSpecifier(pattern)) {\n continue;\n }\n throw new MoonsError({\n code: \"E_SERVER_IMPORT_IN_CLIENT\",\n file: relativeFile,\n line: node.loc?.start.line ?? 1,\n message: `mengimpor (glob) \\`${pattern}\\` di modul client`,\n details: \"`import.meta.glob` yang mencakup `*.server.ts` dilarang di client (PRD §12.7).\",\n suggestions: [\n \"Import statis `serverFn` dari `*.server.ts` (hanya itu yang boleh menyeberang), atau\",\n \"Pindahkan kebutuhan data ke dalam server function\",\n ],\n });\n }\n });\n}\n\ninterface DynamicImportRequest {\n /** Teks specifier literal, atau gabungan quasi template (`*` untuk ekspresi). */\n text: string;\n node: AstNode;\n}\n\n/** Dukung Babel 8 (`ImportExpression`) dan bentuk lama (`CallExpression` + callee `Import`). */\nfunction dynamicImportRequest(node: AstNode): DynamicImportRequest | null {\n let sourceNode: AstNode | null = null;\n\n if (node.type === \"ImportExpression\") {\n sourceNode = (node[\"source\"] as AstNode | undefined) ?? null;\n } else if (node.type === \"CallExpression\") {\n const callee = node[\"callee\"] as AstNode | undefined;\n if (callee?.type !== \"Import\") {\n return null;\n }\n sourceNode = ((node[\"arguments\"] ?? []) as AstNode[])[0] ?? null;\n }\n\n if (sourceNode === null) {\n return null;\n }\n if (sourceNode.type === \"StringLiteral\") {\n return { text: sourceNode[\"value\"] as string, node: sourceNode };\n }\n if (sourceNode.type === \"TemplateLiteral\") {\n const text = ((sourceNode[\"quasis\"] ?? []) as AstNode[])\n .map((quasi) => ((quasi[\"value\"] as { cooked?: string | null } | undefined)?.cooked ?? \"\"))\n .join(\"*\");\n return { text, node: sourceNode };\n }\n return null;\n}\n\nfunction globPatterns(node: AstNode | undefined): string[] {\n if (node?.type === \"StringLiteral\") {\n return [node[\"value\"] as string];\n }\n if (node?.type === \"ArrayExpression\") {\n return ((node[\"elements\"] ?? []) as Array<AstNode | null>)\n .filter((element): element is AstNode => element?.type === \"StringLiteral\")\n .map((element) => element[\"value\"] as string);\n }\n return [];\n}\n\nfunction isDevGuard(node: AstNode): boolean {\n if (node.type !== \"IfStatement\") {\n return false;\n }\n const test = node[\"test\"] as AstNode | undefined;\n return isImportMetaFlag(test, \"DEV\") || isNegatedImportMetaFlag(test, \"PROD\");\n}\n\nfunction isImportMetaFlag(node: AstNode | undefined, flag: string): boolean {\n const member = node;\n if (member?.type !== \"MemberExpression\") {\n return false;\n }\n const property = member[\"property\"] as AstNode | undefined;\n if (property?.type !== \"Identifier\" || property[\"name\"] !== flag) {\n return false;\n }\n const object = member[\"object\"] as AstNode | undefined;\n return isImportMetaEnv(object);\n}\n\nfunction isNegatedImportMetaFlag(node: AstNode | undefined, flag: string): boolean {\n if (node?.type !== \"UnaryExpression\" || node[\"operator\"] !== \"!\") {\n return false;\n }\n return isImportMetaFlag(node[\"argument\"] as AstNode | undefined, flag);\n}\n\nfunction isImportMetaEnv(node: AstNode | undefined): boolean {\n if (node?.type !== \"MemberExpression\") {\n return false;\n }\n const property = node[\"property\"] as AstNode | undefined;\n if (property?.type !== \"Identifier\" || property[\"name\"] !== \"env\") {\n return false;\n }\n const object = node[\"object\"] as AstNode | undefined;\n return object?.type === \"MetaProperty\";\n}\n\nfunction toRelative(projectRoot: string, file: string): string {\n const relative = file.startsWith(projectRoot)\n ? file.slice(projectRoot.length).replace(/^[/\\\\]/, \"\")\n : file;\n return relative.split(\"\\\\\").join(\"/\");\n}\n\nexport interface RouteExportCheckContext {\n file: string;\n code: string;\n routesDir: string;\n projectRoot: string;\n}\n\n/**\n * §11.2 + §12.4: export legal per jenis modul route.\n * page: `default|loader|meta`; layout: `default|loader`; `_error`/`_404`: `default`.\n */\nexport function checkRouteModuleExports(context: RouteExportCheckContext): void {\n const { file, code, routesDir, projectRoot } = context;\n if (!file.startsWith(routesDir) || !file.endsWith(\".tsx\")) {\n return;\n }\n\n const base = file.slice(file.lastIndexOf(\"/\") + 1);\n if (base.startsWith(\"_\") && base !== \"_layout.tsx\" && base !== \"_error.tsx\" && base !== \"_404.tsx\") {\n return; // bukan route (diabaikan scanner)\n }\n\n const allowed =\n base === \"_layout.tsx\"\n ? [\"default\", \"loader\"]\n : base === \"_error.tsx\" || base === \"_404.tsx\"\n ? [\"default\"]\n : [\"default\", \"loader\", \"meta\"];\n const allowedText = `Hanya ${allowed.map((name) => `\\`${name}\\``).join(\", \")} yang boleh di-export.`;\n const relativeFile = toRelative(projectRoot, file);\n const ast = parseModule(code, file);\n\n const declarations: Array<{ name: string; line: number }> = [];\n let hasDefault = false;\n\n for (const statement of topLevelStatements(ast)) {\n if (statement.type === \"ExportDefaultDeclaration\") {\n hasDefault = true;\n continue;\n }\n\n if (statement.type === \"ExportAllDeclaration\") {\n throw new MoonsError({\n code: \"E_ROUTE_EXPORT_INVALID\",\n file: relativeFile,\n line: statement.loc?.start.line ?? 1,\n message: \"`export *` tidak diizinkan di modul route\",\n details: allowedText,\n suggestions: [\n `Pindahkan isi file ke luar ${toRelative(projectRoot, routesDir)}/, atau`,\n \"Hapus `export *` tersebut\",\n ],\n });\n }\n\n if (statement.type !== \"ExportNamedDeclaration\") {\n continue;\n }\n\n const declaration = statement[\"declaration\"] as AstNode | null | undefined;\n if (declaration !== null && declaration !== undefined) {\n for (const name of declarationNames(declaration)) {\n declarations.push({ name, line: declaration.loc?.start.line ?? 1 });\n }\n }\n\n for (const item of (statement[\"specifiers\"] ?? []) as AstNode[]) {\n const exported = item[\"exported\"] as AstNode | undefined;\n const name =\n exported?.type === \"Identifier\"\n ? (exported[\"name\"] as string)\n : exported?.type === \"StringLiteral\"\n ? (exported[\"value\"] as string)\n : null;\n if (name !== null) {\n declarations.push({ name, line: item.loc?.start.line ?? statement.loc?.start.line ?? 1 });\n }\n }\n }\n\n for (const entry of declarations) {\n if (!allowed.includes(entry.name)) {\n throw new MoonsError({\n code: \"E_ROUTE_EXPORT_INVALID\",\n file: relativeFile,\n line: entry.line,\n message: `export \\`${entry.name}\\` tidak diizinkan di modul route`,\n details: allowedText,\n suggestions: [\n `Pindahkan \\`${entry.name}\\` ke file di luar ${toRelative(projectRoot, routesDir)}/, atau`,\n \"Hapus export tersebut\",\n ],\n });\n }\n }\n\n if (!hasDefault) {\n throw new MoonsError({\n code: \"E_ROUTE_EXPORT_INVALID\",\n file: relativeFile,\n message: \"modul route wajib mengekspor `default`\",\n details: \"Setiap file route harus punya `export default` berupa komponen React (PRD §11.2).\",\n suggestions: [\"Tambahkan `export default function Page() { ... }`\"],\n });\n }\n}\n\nfunction declarationNames(declaration: AstNode): string[] {\n switch (declaration.type) {\n case \"VariableDeclaration\":\n return ((declaration[\"declarations\"] ?? []) as AstNode[])\n .map((declarator) => ((declarator[\"id\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\")\n .filter((name) => name.length > 0);\n case \"FunctionDeclaration\":\n case \"ClassDeclaration\":\n case \"TSInterfaceDeclaration\":\n case \"TSTypeAliasDeclaration\":\n case \"TSEnumDeclaration\":\n return [((declaration[\"id\"] as AstNode | undefined)?.[\"name\"] as string) ?? \"\"].filter(\n (name) => name.length > 0,\n );\n default:\n return [];\n }\n}\n\n/** Scan semua `*.server.{ts,tsx}` di bawah root (exclude direktori build/dependency). */\nexport function scanServerFiles(projectRoot: string): string[] {\n const excluded = new Set([\"node_modules\", \"dist\", \".moons\", \".git\"]);\n const result: string[] = [];\n\n const walkDir = (dir: string): void => {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (excluded.has(entry.name)) {\n continue;\n }\n walkDir(join(dir, entry.name));\n } else if (entry.isFile() && isServerFilePath(entry.name)) {\n result.push(join(dir, entry.name));\n }\n }\n };\n\n walkDir(projectRoot);\n return result.sort();\n}\n\nexport interface FnRegistryJson {\n [key: string]: string;\n}\n\n/** Bangun isi `fn-registry.json` (bentuk yang dibaca §21.3). */\nexport function buildFnRegistry(projectRoot: string, files: string[]): FnRegistryJson {\n const registry: FnRegistryJson = {};\n for (const file of files) {\n let source: string;\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n continue;\n }\n const analysis = analyzeServerFile(source, file, projectRoot);\n for (const fn of analysis.serverFns) {\n registry[fnRegistryKey(projectRoot, file, fn.name)] = fn.hash;\n }\n }\n return registry;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "A2B4D23CAFD2B11164756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderRoutesModule,
|
|
3
|
+
rootSpecifier,
|
|
4
|
+
VIRTUAL_MODULES,
|
|
5
|
+
fromNullPrefixed,
|
|
6
|
+
installDevMiddleware2
|
|
7
|
+
} from "./index-8xq8fcgq.js";
|
|
8
|
+
import {
|
|
9
|
+
isServerFilePath2,
|
|
10
|
+
isNonContractServerFile2,
|
|
11
|
+
resolveServerSpecifierSync2,
|
|
12
|
+
stripQuery2,
|
|
13
|
+
analyzeServerFile2,
|
|
14
|
+
renderServerFnStub2,
|
|
15
|
+
injectServerFnMeta2,
|
|
16
|
+
nonContractServerFileError2,
|
|
17
|
+
checkClientModuleImports2,
|
|
18
|
+
checkRouteModuleExports2,
|
|
19
|
+
scanServerFiles2
|
|
20
|
+
} from "./index-fg6nqart.js";
|
|
21
|
+
|
|
22
|
+
// src/plugin.ts
|
|
23
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
import { resolve as resolvePath } from "node:path";
|
|
26
|
+
import {
|
|
27
|
+
MoonsError,
|
|
28
|
+
fnRegistryKey,
|
|
29
|
+
generateTypes,
|
|
30
|
+
scanRoutes,
|
|
31
|
+
validateConfig
|
|
32
|
+
} from "@moonsjs/core";
|
|
33
|
+
import { loadConfigFromFile } from "vite";
|
|
34
|
+
|
|
35
|
+
// src/leak-check.ts
|
|
36
|
+
function findLeak(outputs, canary, decode = defaultDecode) {
|
|
37
|
+
for (const output of outputs) {
|
|
38
|
+
const fileName = output.fileName ?? "(unknown)";
|
|
39
|
+
let text = "";
|
|
40
|
+
if (typeof output.code === "string") {
|
|
41
|
+
text = output.code;
|
|
42
|
+
} else if (typeof output.source === "string") {
|
|
43
|
+
text = output.source;
|
|
44
|
+
} else if (output.source instanceof Uint8Array) {
|
|
45
|
+
text = decode(output.source);
|
|
46
|
+
}
|
|
47
|
+
if (text.includes(canary)) {
|
|
48
|
+
return { fileName };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function defaultDecode(bytes) {
|
|
54
|
+
return new TextDecoder().decode(bytes);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/plugin.ts
|
|
58
|
+
var CODE_FILE_PATTERN = /\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
|
|
59
|
+
function moons(options = {}) {
|
|
60
|
+
let root = options.projectRoot ?? process.cwd();
|
|
61
|
+
let isSsrBuild = false;
|
|
62
|
+
let configFilePath = "";
|
|
63
|
+
let routesDir = "";
|
|
64
|
+
let routes = [];
|
|
65
|
+
let analysisCache = new Map;
|
|
66
|
+
const stubTransformed = new Set;
|
|
67
|
+
function analyzeFile(absoluteFile) {
|
|
68
|
+
const cached = analysisCache.get(absoluteFile);
|
|
69
|
+
if (cached !== undefined) {
|
|
70
|
+
return cached;
|
|
71
|
+
}
|
|
72
|
+
let source;
|
|
73
|
+
try {
|
|
74
|
+
source = readFileSync(absoluteFile, "utf8");
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const analysis = analyzeServerFile2(source, absoluteFile, root);
|
|
79
|
+
analysisCache.set(absoluteFile, analysis);
|
|
80
|
+
return analysis;
|
|
81
|
+
}
|
|
82
|
+
function refreshServerFns() {
|
|
83
|
+
const next = new Map;
|
|
84
|
+
const registry = {};
|
|
85
|
+
for (const file of scanServerFiles2(root)) {
|
|
86
|
+
let source;
|
|
87
|
+
try {
|
|
88
|
+
source = readFileSync(file, "utf8");
|
|
89
|
+
} catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const analysis = analyzeServerFile2(source, file, root);
|
|
93
|
+
next.set(file, analysis);
|
|
94
|
+
for (const fn of analysis.serverFns) {
|
|
95
|
+
registry[fnRegistryKey(root, file, fn.name)] = fn.hash;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
analysisCache = next;
|
|
99
|
+
const outDir = resolvePath(root, ".moons");
|
|
100
|
+
mkdirSync(outDir, { recursive: true });
|
|
101
|
+
writeFileSync(resolvePath(outDir, "fn-registry.json"), `${JSON.stringify(registry, null, 2)}
|
|
102
|
+
`, "utf8");
|
|
103
|
+
}
|
|
104
|
+
function serverFnFileSpecifiers() {
|
|
105
|
+
const specifiers = [];
|
|
106
|
+
for (const [file, analysis] of analysisCache) {
|
|
107
|
+
if (analysis.serverFns.length > 0) {
|
|
108
|
+
specifiers.push(rootSpecifier(root, file));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return specifiers.sort();
|
|
112
|
+
}
|
|
113
|
+
function transformServerFileClient(code, id) {
|
|
114
|
+
const relativePath = id.startsWith(root) ? id.slice(root.length).split("\\").join("/") : id;
|
|
115
|
+
const cacheKey = createHash("sha256").update(`${relativePath}\x00${code}`).digest("hex");
|
|
116
|
+
const cacheFile = resolvePath(root, ".moons/cache", `${cacheKey}.js`);
|
|
117
|
+
if (existsSync(cacheFile)) {
|
|
118
|
+
stubTransformed.add(id);
|
|
119
|
+
return readFileSync(cacheFile, "utf8");
|
|
120
|
+
}
|
|
121
|
+
const analysis = analyzeFile(id);
|
|
122
|
+
if (analysis === null) {
|
|
123
|
+
throw new MoonsError({
|
|
124
|
+
code: "E_INTERNAL",
|
|
125
|
+
file: id,
|
|
126
|
+
message: "gagal membaca file server untuk transform",
|
|
127
|
+
details: "File `.server.ts` harus bisa dibaca saat transform (PRD §12.2).",
|
|
128
|
+
suggestions: ["Periksa path dan izin file"]
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const stub = renderServerFnStub2(code, id, analysis, {
|
|
132
|
+
analyzeSpecifier: (sourceFile, specifier) => {
|
|
133
|
+
const resolved = resolveServerSpecifierSync2(sourceFile, specifier);
|
|
134
|
+
return resolved === null ? null : analyzeFile(resolved);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
mkdirSync(resolvePath(root, ".moons/cache"), { recursive: true });
|
|
138
|
+
writeFileSync(cacheFile, stub.code, "utf8");
|
|
139
|
+
stubTransformed.add(id);
|
|
140
|
+
return stub.code;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
name: "moons",
|
|
144
|
+
enforce: "pre",
|
|
145
|
+
config(_config, env) {
|
|
146
|
+
isSsrBuild = env.isSsrBuild === true;
|
|
147
|
+
const common = {
|
|
148
|
+
appType: "custom"
|
|
149
|
+
};
|
|
150
|
+
if (isSsrBuild) {
|
|
151
|
+
return {
|
|
152
|
+
...common,
|
|
153
|
+
build: {
|
|
154
|
+
outDir: "dist/server",
|
|
155
|
+
emptyOutDir: true,
|
|
156
|
+
ssr: ".moons/server-entry.ts",
|
|
157
|
+
rollupOptions: { output: { entryFileNames: "index.js", codeSplitting: false } }
|
|
158
|
+
},
|
|
159
|
+
ssr: { noExternal: true, target: "node" }
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
...common,
|
|
164
|
+
build: { outDir: "dist/client", emptyOutDir: true }
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
async configResolved(resolved) {
|
|
168
|
+
root = options.projectRoot ?? resolved.root;
|
|
169
|
+
configFilePath = resolvePath(root, options.configPath ?? "moons.config.ts");
|
|
170
|
+
if (!existsSync(configFilePath)) {
|
|
171
|
+
throw new MoonsError({
|
|
172
|
+
code: "E_CONFIG_INVALID",
|
|
173
|
+
file: configFilePath,
|
|
174
|
+
message: "`moons.config.ts` tidak ditemukan",
|
|
175
|
+
details: "Framework membutuhkan file config di root project (PRD §14.3).",
|
|
176
|
+
suggestions: [
|
|
177
|
+
"Buat `moons.config.ts` dengan `export default defineConfig({ context: async (req) => ({}) })`"
|
|
178
|
+
]
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
let raw;
|
|
182
|
+
try {
|
|
183
|
+
const loaded = await loadConfigFromFile({ command: resolved.command, mode: resolved.mode }, configFilePath, root);
|
|
184
|
+
raw = loaded?.config;
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (error instanceof MoonsError) {
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
throw new MoonsError({
|
|
190
|
+
code: "E_CONFIG_INVALID",
|
|
191
|
+
file: configFilePath,
|
|
192
|
+
message: "gagal memuat `moons.config.ts`",
|
|
193
|
+
details: error instanceof Error ? error.message : String(error),
|
|
194
|
+
suggestions: ["Periksa sintaks dan import di `moons.config.ts`"]
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const config = validateConfig(raw, { file: configFilePath, projectRoot: root });
|
|
198
|
+
routesDir = resolvePath(root, config.routesDir);
|
|
199
|
+
},
|
|
200
|
+
async buildStart() {
|
|
201
|
+
routes = scanRoutes(routesDir);
|
|
202
|
+
await generateTypes({
|
|
203
|
+
routesDir,
|
|
204
|
+
configPath: configFilePath,
|
|
205
|
+
outDir: resolvePath(root, ".moons")
|
|
206
|
+
});
|
|
207
|
+
refreshServerFns();
|
|
208
|
+
if (isSsrBuild) {
|
|
209
|
+
writeFileSync(resolvePath(root, ".moons/server-entry.ts"), renderServerEntryBuild(routesDir, serverFnFileSpecifiers()), "utf8");
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
resolveId(id) {
|
|
213
|
+
const clean = id.startsWith("\x00") ? id.slice(1) : id;
|
|
214
|
+
if (Object.values(VIRTUAL_MODULES).includes(clean)) {
|
|
215
|
+
return `\x00${clean}`;
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
},
|
|
219
|
+
load(id) {
|
|
220
|
+
const name = fromNullPrefixed(id);
|
|
221
|
+
if (name === null) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
switch (name) {
|
|
225
|
+
case VIRTUAL_MODULES.routes:
|
|
226
|
+
return renderRoutesModule(routes, routesDir, root);
|
|
227
|
+
case VIRTUAL_MODULES.clientEntry:
|
|
228
|
+
return `// Generated by @moons. Jangan diubah manual.
|
|
229
|
+
export { clientManifest, loadRoute } from "virtual:moons/routes";
|
|
230
|
+
`;
|
|
231
|
+
case VIRTUAL_MODULES.config:
|
|
232
|
+
return renderConfigModule(root, configFilePath);
|
|
233
|
+
case VIRTUAL_MODULES.serverEntry:
|
|
234
|
+
return renderServerEntryDev(routesDir, serverFnFileSpecifiers());
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
async transform(code, id) {
|
|
238
|
+
const cleanId = stripQuery2(id);
|
|
239
|
+
if (cleanId.startsWith("\x00") || cleanId.includes("/node_modules/")) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const environment = environmentName(this);
|
|
243
|
+
if (isServerFilePath2(cleanId)) {
|
|
244
|
+
if (environment === "ssr") {
|
|
245
|
+
const analysis = analysisCache.get(cleanId) ?? analyzeFile(cleanId);
|
|
246
|
+
if (analysis === null || analysis.serverFns.length === 0) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
return injectServerFnMeta2(code, analysis, root);
|
|
250
|
+
}
|
|
251
|
+
return transformServerFileClient(code, cleanId);
|
|
252
|
+
}
|
|
253
|
+
if (environment !== "ssr" && isNonContractServerFile2(cleanId)) {
|
|
254
|
+
throw nonContractServerFileError2(cleanId, root);
|
|
255
|
+
}
|
|
256
|
+
if (environment !== "ssr" && CODE_FILE_PATTERN.test(cleanId)) {
|
|
257
|
+
if (cleanId.startsWith(routesDir) && cleanId.endsWith(".tsx")) {
|
|
258
|
+
checkRouteModuleExports2({
|
|
259
|
+
file: cleanId,
|
|
260
|
+
code,
|
|
261
|
+
routesDir,
|
|
262
|
+
projectRoot: root
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
await checkClientModuleImports2({
|
|
266
|
+
file: cleanId,
|
|
267
|
+
code,
|
|
268
|
+
projectRoot: root,
|
|
269
|
+
resolve: async (specifier, importer) => {
|
|
270
|
+
try {
|
|
271
|
+
const resolved = await this.resolve(specifier, importer);
|
|
272
|
+
return resolved === null ? null : stripQuery2(resolved.id);
|
|
273
|
+
} catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
analyze: (absoluteFile) => analysisCache.get(absoluteFile) ?? analyzeFile(absoluteFile)
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
},
|
|
282
|
+
generateBundle(_options, bundle) {
|
|
283
|
+
if (environmentName(this) === "ssr") {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const canary = options.leakTest?.canary;
|
|
287
|
+
if (canary !== undefined && canary.length > 0) {
|
|
288
|
+
const leak = findLeak(Object.values(bundle), canary);
|
|
289
|
+
if (leak !== null) {
|
|
290
|
+
throw new MoonsError({
|
|
291
|
+
code: "E_INTERNAL",
|
|
292
|
+
message: `canary \`${canary}\` ditemukan di bundle client (${leak.fileName})`,
|
|
293
|
+
details: "Verifikasi kebocoran §2/§9.2.8 gagal: kode server bocor ke output client. Build dihentikan.",
|
|
294
|
+
suggestions: [
|
|
295
|
+
"Periksa transform `*.server.ts` (§12)",
|
|
296
|
+
"Jalankan `./scripts/m2/test-leak.sh` untuk audit"
|
|
297
|
+
]
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
for (const output of Object.values(bundle)) {
|
|
302
|
+
if (output.type !== "chunk") {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
for (const moduleId of Object.keys(output.modules)) {
|
|
306
|
+
const cleanId = stripQuery2(moduleId);
|
|
307
|
+
if (!isServerFilePath2(cleanId) || stubTransformed.has(cleanId)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
throw new MoonsError({
|
|
311
|
+
code: "E_FORBIDDEN_SERVER_IMPORT",
|
|
312
|
+
file: cleanId,
|
|
313
|
+
message: "modul server ikut ter-bundle di client tanpa melewati transform",
|
|
314
|
+
details: "Verifikasi build §9.2: setiap `*.server.ts` di bundle client wajib berupa stub RPC hasil transform.",
|
|
315
|
+
suggestions: [
|
|
316
|
+
"Pastikan transform zero-trust (§12) berjalan untuk modul ini",
|
|
317
|
+
"Laporkan ini sebagai bug framework jika berulang"
|
|
318
|
+
]
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
configureServer(server) {
|
|
324
|
+
installDevMiddleware2(server, { templatePath: resolvePath(root, "index.html") });
|
|
325
|
+
},
|
|
326
|
+
async handleHotUpdate(context) {
|
|
327
|
+
if (isServerFilePath2(context.file)) {
|
|
328
|
+
refreshServerFns();
|
|
329
|
+
context.server.ws.send({ type: "full-reload" });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (!context.file.startsWith(routesDir)) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
routes = scanRoutes(routesDir);
|
|
337
|
+
await generateTypes({
|
|
338
|
+
routesDir,
|
|
339
|
+
configPath: configFilePath,
|
|
340
|
+
outDir: resolvePath(root, ".moons")
|
|
341
|
+
});
|
|
342
|
+
} catch (error) {
|
|
343
|
+
context.server.config.logger.error(String(error));
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
invalidateVirtualModules(context.server);
|
|
347
|
+
context.server.ws.send({ type: "full-reload" });
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function renderConfigModule(root, configFilePath) {
|
|
352
|
+
return [
|
|
353
|
+
"// Generated by @moons. Jangan diubah manual.",
|
|
354
|
+
`import raw from ${JSON.stringify(rootSpecifier(root, configFilePath))};`,
|
|
355
|
+
'import { validateConfig } from "@moonsjs/core";',
|
|
356
|
+
`export default validateConfig(raw, { file: ${JSON.stringify(configFilePath)} });`,
|
|
357
|
+
""
|
|
358
|
+
].join(`
|
|
359
|
+
`);
|
|
360
|
+
}
|
|
361
|
+
function renderServerEntryDev(routesDir, eagerImports) {
|
|
362
|
+
return [
|
|
363
|
+
"// Generated by @moons. Jangan diubah manual.",
|
|
364
|
+
'import { createRequestHandler } from "@moonsjs/vite/server";',
|
|
365
|
+
'import config from "virtual:moons/config";',
|
|
366
|
+
'import { routes, loadRoute } from "virtual:moons/routes";',
|
|
367
|
+
...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),
|
|
368
|
+
"",
|
|
369
|
+
"export function createDevHandler(shell) {",
|
|
370
|
+
` return createRequestHandler({ routes, config, routesDir: ${JSON.stringify(routesDir)}, loadRoute, shell });`,
|
|
371
|
+
"}",
|
|
372
|
+
""
|
|
373
|
+
].join(`
|
|
374
|
+
`);
|
|
375
|
+
}
|
|
376
|
+
function renderServerEntryBuild(routesDir, eagerImports) {
|
|
377
|
+
return [
|
|
378
|
+
"// Generated by @moons. Jangan diubah manual.",
|
|
379
|
+
'import { createFileShell, createRequestHandler, startNodeServer } from "@moonsjs/vite/server";',
|
|
380
|
+
'import config from "virtual:moons/config";',
|
|
381
|
+
'import { routes, loadRoute } from "virtual:moons/routes";',
|
|
382
|
+
...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),
|
|
383
|
+
"",
|
|
384
|
+
"const handler = createRequestHandler({",
|
|
385
|
+
" routes,",
|
|
386
|
+
" config,",
|
|
387
|
+
` routesDir: ${JSON.stringify(routesDir)},`,
|
|
388
|
+
" loadRoute,",
|
|
389
|
+
" shell: createFileShell(),",
|
|
390
|
+
"});",
|
|
391
|
+
"",
|
|
392
|
+
"startNodeServer(handler);",
|
|
393
|
+
""
|
|
394
|
+
].join(`
|
|
395
|
+
`);
|
|
396
|
+
}
|
|
397
|
+
function environmentName(context) {
|
|
398
|
+
const environment = context?.environment;
|
|
399
|
+
return environment?.name ?? "client";
|
|
400
|
+
}
|
|
401
|
+
function invalidateVirtualModules(server) {
|
|
402
|
+
const graphs = [server.moduleGraph];
|
|
403
|
+
const environments = server.environments;
|
|
404
|
+
if (environments !== undefined) {
|
|
405
|
+
for (const environment of Object.values(environments)) {
|
|
406
|
+
if (environment.moduleGraph !== undefined) {
|
|
407
|
+
graphs.push(environment.moduleGraph);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
for (const graph of graphs) {
|
|
412
|
+
for (const name of Object.values(VIRTUAL_MODULES)) {
|
|
413
|
+
for (const module of graph.getModulesByFile(`\x00${name}`) ?? []) {
|
|
414
|
+
graph.invalidateModule(module);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
export {
|
|
420
|
+
moons as default
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
//# debugId=B0BD6103F707A0BE64756E2164756E21
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/plugin.ts", "../src/leak-check.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n MoonsError,\n fnRegistryKey,\n generateTypes,\n scanRoutes,\n validateConfig,\n type RouteDefinition,\n} from \"@moonsjs/core\";\nimport { loadConfigFromFile, type Plugin, type ViteDevServer } from \"vite\";\nimport { findLeak } from \"./leak-check\";\nimport { renderRoutesModule, rootSpecifier } from \"./manifest\";\nimport { installDevMiddleware } from \"./server/dev\";\nimport {\n analyzeServerFile,\n checkClientModuleImports,\n checkRouteModuleExports,\n injectServerFnMeta,\n isNonContractServerFile,\n isServerFilePath,\n nonContractServerFileError,\n renderServerFnStub,\n resolveServerSpecifierSync,\n scanServerFiles,\n stripQuery,\n type ServerFileAnalysis,\n} from \"./transform\";\nimport { fromNullPrefixed, VIRTUAL_MODULES } from \"./virtual-modules\";\n\nexport interface MoonsVitePluginOptions {\n /** Default: \"moons.config.ts\". */\n configPath?: string;\n /** Hanya dipakai di CI (M2 §21). */\n leakTest?: { canary?: string };\n /** Default: root Vite. */\n projectRoot?: string;\n}\n\n/**\n * Plugin `@moonsjs/vite` (PRD §9): scan route, typegen, virtual module,\n * dev SSR middleware, build client + server.\n */\nconst CODE_FILE_PATTERN = /\\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;\n\nexport default function moons(options: MoonsVitePluginOptions = {}): Plugin {\n let root = options.projectRoot ?? process.cwd();\n let isSsrBuild = false;\n let configFilePath = \"\";\n let routesDir = \"\";\n let routes: RouteDefinition[] = [];\n let analysisCache = new Map<string, ServerFileAnalysis>();\n const stubTransformed = new Set<string>();\n\n function analyzeFile(absoluteFile: string): ServerFileAnalysis | null {\n const cached = analysisCache.get(absoluteFile);\n if (cached !== undefined) {\n return cached;\n }\n let source: string;\n try {\n source = readFileSync(absoluteFile, \"utf8\");\n } catch {\n return null;\n }\n const analysis = analyzeServerFile(source, absoluteFile, root);\n analysisCache.set(absoluteFile, analysis);\n return analysis;\n }\n\n function refreshServerFns(): void {\n const next = new Map<string, ServerFileAnalysis>();\n const registry: Record<string, string> = {};\n\n for (const file of scanServerFiles(root)) {\n let source: string;\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n continue;\n }\n const analysis = analyzeServerFile(source, file, root);\n next.set(file, analysis);\n for (const fn of analysis.serverFns) {\n registry[fnRegistryKey(root, file, fn.name)] = fn.hash;\n }\n }\n\n analysisCache = next;\n const outDir = resolvePath(root, \".moons\");\n mkdirSync(outDir, { recursive: true });\n writeFileSync(\n resolvePath(outDir, \"fn-registry.json\"),\n `${JSON.stringify(registry, null, 2)}\\n`,\n \"utf8\",\n );\n }\n\n /** Semua specifier file `.server.ts` yang punya serverFn (untuk eager import di entry server). */\n function serverFnFileSpecifiers(): string[] {\n const specifiers: string[] = [];\n for (const [file, analysis] of analysisCache) {\n if (analysis.serverFns.length > 0) {\n specifiers.push(rootSpecifier(root, file));\n }\n }\n return specifiers.sort();\n }\n\n /** Stub client §12.2 + cache §12.2.5. */\n function transformServerFileClient(code: string, id: string): string {\n const relativePath = id.startsWith(root)\n ? id.slice(root.length).split(\"\\\\\").join(\"/\")\n : id;\n const cacheKey = createHash(\"sha256\").update(`${relativePath}\\0${code}`).digest(\"hex\");\n const cacheFile = resolvePath(root, \".moons/cache\", `${cacheKey}.js`);\n\n if (existsSync(cacheFile)) {\n stubTransformed.add(id);\n return readFileSync(cacheFile, \"utf8\");\n }\n\n const analysis = analyzeFile(id);\n if (analysis === null) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file: id,\n message: \"gagal membaca file server untuk transform\",\n details: \"File `.server.ts` harus bisa dibaca saat transform (PRD §12.2).\",\n suggestions: [\"Periksa path dan izin file\"],\n });\n }\n\n const stub = renderServerFnStub(code, id, analysis, {\n analyzeSpecifier: (sourceFile, specifier) => {\n const resolved = resolveServerSpecifierSync(sourceFile, specifier);\n return resolved === null ? null : analyzeFile(resolved);\n },\n });\n\n mkdirSync(resolvePath(root, \".moons/cache\"), { recursive: true });\n writeFileSync(cacheFile, stub.code, \"utf8\");\n stubTransformed.add(id);\n return stub.code;\n }\n\n return {\n name: \"moons\",\n enforce: \"pre\",\n\n config(_config, env) {\n isSsrBuild = env.isSsrBuild === true;\n const common = {\n appType: \"custom\" as const,\n };\n\n if (isSsrBuild) {\n return {\n ...common,\n build: {\n outDir: \"dist/server\",\n emptyOutDir: true,\n // Entry nyata yang di-generate saat buildStart (Rolldown butuh file,\n // entry virtual tidak di-resolve lewat plugin container).\n ssr: \".moons/server-entry.ts\",\n rollupOptions: { output: { entryFileNames: \"index.js\", codeSplitting: false } },\n },\n ssr: { noExternal: true, target: \"node\" as const },\n };\n }\n\n return {\n ...common,\n build: { outDir: \"dist/client\", emptyOutDir: true },\n };\n },\n\n async configResolved(resolved) {\n root = options.projectRoot ?? resolved.root;\n configFilePath = resolvePath(root, options.configPath ?? \"moons.config.ts\");\n\n if (!existsSync(configFilePath)) {\n throw new MoonsError({\n code: \"E_CONFIG_INVALID\",\n file: configFilePath,\n message: \"`moons.config.ts` tidak ditemukan\",\n details: \"Framework membutuhkan file config di root project (PRD §14.3).\",\n suggestions: [\n \"Buat `moons.config.ts` dengan `export default defineConfig({ context: async (req) => ({}) })`\",\n ],\n });\n }\n\n let raw: unknown;\n try {\n const loaded = await loadConfigFromFile(\n { command: resolved.command, mode: resolved.mode },\n configFilePath,\n root,\n );\n raw = loaded?.config;\n } catch (error) {\n if (error instanceof MoonsError) {\n throw error;\n }\n throw new MoonsError({\n code: \"E_CONFIG_INVALID\",\n file: configFilePath,\n message: \"gagal memuat `moons.config.ts`\",\n details: error instanceof Error ? error.message : String(error),\n suggestions: [\"Periksa sintaks dan import di `moons.config.ts`\"],\n });\n }\n\n const config = validateConfig(raw, { file: configFilePath, projectRoot: root });\n routesDir = resolvePath(root, config.routesDir);\n },\n\n async buildStart() {\n routes = scanRoutes(routesDir);\n await generateTypes({\n routesDir,\n configPath: configFilePath,\n outDir: resolvePath(root, \".moons\"),\n });\n refreshServerFns();\n if (isSsrBuild) {\n writeFileSync(\n resolvePath(root, \".moons/server-entry.ts\"),\n renderServerEntryBuild(routesDir, serverFnFileSpecifiers()),\n \"utf8\",\n );\n }\n },\n\n resolveId(id) {\n const clean = id.startsWith(\"\\0\") ? id.slice(1) : id;\n if ((Object.values(VIRTUAL_MODULES) as string[]).includes(clean)) {\n return `\\0${clean}`;\n }\n return undefined;\n },\n\n load(id) {\n const name = fromNullPrefixed(id);\n if (name === null) {\n return undefined;\n }\n switch (name) {\n case VIRTUAL_MODULES.routes:\n return renderRoutesModule(routes, routesDir, root);\n case VIRTUAL_MODULES.clientEntry:\n return '// Generated by @moons. Jangan diubah manual.\\nexport { clientManifest, loadRoute } from \"virtual:moons/routes\";\\n';\n case VIRTUAL_MODULES.config:\n return renderConfigModule(root, configFilePath);\n case VIRTUAL_MODULES.serverEntry:\n // Hanya dipakai dev (ssrLoadModule); build memakai .moons/server-entry.ts.\n return renderServerEntryDev(routesDir, serverFnFileSpecifiers());\n }\n },\n\n async transform(code, id) {\n const cleanId = stripQuery(id);\n if (cleanId.startsWith(\"\\0\") || cleanId.includes(\"/node_modules/\")) {\n return undefined;\n }\n\n const environment = environmentName(this);\n\n if (isServerFilePath(cleanId)) {\n if (environment === \"ssr\") {\n const analysis = analysisCache.get(cleanId) ?? analyzeFile(cleanId);\n if (analysis === null || analysis.serverFns.length === 0) {\n return undefined;\n }\n return injectServerFnMeta(code, analysis, root);\n }\n return transformServerFileClient(code, cleanId);\n }\n\n // Audit ronde 2: file server di luar kontrak §12 tidak bisa di-stub —\n // jangan pernah biarkan masuk graph client.\n if (environment !== \"ssr\" && isNonContractServerFile(cleanId)) {\n throw nonContractServerFileError(cleanId, root);\n }\n\n if (environment !== \"ssr\" && CODE_FILE_PATTERN.test(cleanId)) {\n if (cleanId.startsWith(routesDir) && cleanId.endsWith(\".tsx\")) {\n checkRouteModuleExports({\n file: cleanId,\n code,\n routesDir,\n projectRoot: root,\n });\n }\n await checkClientModuleImports({\n file: cleanId,\n code,\n projectRoot: root,\n // Resolusi penuh (alias Vite, tsconfig paths, symlink) — audit ronde 2.\n resolve: async (specifier, importer) => {\n try {\n const resolved = await this.resolve(specifier, importer);\n return resolved === null ? null : stripQuery(resolved.id);\n } catch {\n return null;\n }\n },\n analyze: (absoluteFile) => analysisCache.get(absoluteFile) ?? analyzeFile(absoluteFile),\n });\n }\n\n return undefined;\n },\n\n generateBundle(_options, bundle) {\n if (environmentName(this) === \"ssr\") {\n return;\n }\n\n const canary = options.leakTest?.canary;\n if (canary !== undefined && canary.length > 0) {\n const leak = findLeak(Object.values(bundle), canary);\n if (leak !== null) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n message: `canary \\`${canary}\\` ditemukan di bundle client (${leak.fileName})`,\n details:\n \"Verifikasi kebocoran §2/§9.2.8 gagal: kode server bocor ke output client. Build dihentikan.\",\n suggestions: [\n \"Periksa transform `*.server.ts` (§12)\",\n \"Jalankan `./scripts/m2/test-leak.sh` untuk audit\",\n ],\n });\n }\n }\n\n for (const output of Object.values(bundle)) {\n if (output.type !== \"chunk\") {\n continue;\n }\n for (const moduleId of Object.keys(output.modules)) {\n const cleanId = stripQuery(moduleId);\n if (!isServerFilePath(cleanId) || stubTransformed.has(cleanId)) {\n continue;\n }\n throw new MoonsError({\n code: \"E_FORBIDDEN_SERVER_IMPORT\",\n file: cleanId,\n message: \"modul server ikut ter-bundle di client tanpa melewati transform\",\n details:\n \"Verifikasi build §9.2: setiap `*.server.ts` di bundle client wajib berupa stub RPC hasil transform.\",\n suggestions: [\n \"Pastikan transform zero-trust (§12) berjalan untuk modul ini\",\n \"Laporkan ini sebagai bug framework jika berulang\",\n ],\n });\n }\n }\n },\n\n configureServer(server) {\n installDevMiddleware(server, { templatePath: resolvePath(root, \"index.html\") });\n },\n\n async handleHotUpdate(context) {\n if (isServerFilePath(context.file)) {\n refreshServerFns();\n context.server.ws.send({ type: \"full-reload\" });\n return;\n }\n\n if (!context.file.startsWith(routesDir)) {\n return;\n }\n\n try {\n routes = scanRoutes(routesDir);\n await generateTypes({\n routesDir,\n configPath: configFilePath,\n outDir: resolvePath(root, \".moons\"),\n });\n } catch (error) {\n context.server.config.logger.error(String(error));\n return;\n }\n\n invalidateVirtualModules(context.server);\n context.server.ws.send({ type: \"full-reload\" });\n },\n };\n}\n\nfunction renderConfigModule(root: string, configFilePath: string): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n `import raw from ${JSON.stringify(rootSpecifier(root, configFilePath))};`,\n 'import { validateConfig } from \"@moonsjs/core\";',\n `export default validateConfig(raw, { file: ${JSON.stringify(configFilePath)} });`,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderServerEntryDev(routesDir: string, eagerImports: string[]): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n 'import { createRequestHandler } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"export function createDevHandler(shell) {\",\n ` return createRequestHandler({ routes, config, routesDir: ${JSON.stringify(routesDir)}, loadRoute, shell });`,\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderServerEntryBuild(routesDir: string, eagerImports: string[]): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n 'import { createFileShell, createRequestHandler, startNodeServer } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"const handler = createRequestHandler({\",\n \" routes,\",\n \" config,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" shell: createFileShell(),\",\n \"});\",\n \"\",\n \"startNodeServer(handler);\",\n \"\",\n ].join(\"\\n\");\n}\n\ninterface ModuleGraphLike {\n getModulesByFile(file: string): Iterable<{ id?: string | null }> | undefined;\n invalidateModule(module: unknown): void;\n}\n\nfunction environmentName(context: unknown): string {\n const environment = (context as { environment?: { name?: string } } | undefined)?.environment;\n return environment?.name ?? \"client\";\n}\n\nfunction invalidateVirtualModules(server: ViteDevServer): void {\n const graphs: ModuleGraphLike[] = [server.moduleGraph as unknown as ModuleGraphLike];\n const environments = (server as unknown as { environments?: Record<string, { moduleGraph?: unknown }> })\n .environments;\n if (environments !== undefined) {\n for (const environment of Object.values(environments)) {\n if (environment.moduleGraph !== undefined) {\n graphs.push(environment.moduleGraph as ModuleGraphLike);\n }\n }\n }\n\n for (const graph of graphs) {\n for (const name of Object.values(VIRTUAL_MODULES)) {\n for (const module of graph.getModulesByFile(`\\0${name}`) ?? []) {\n graph.invalidateModule(module);\n }\n }\n }\n}\n",
|
|
6
|
+
"export interface BundleOutputLike {\n type: string;\n fileName?: string;\n code?: string;\n source?: string | Uint8Array;\n}\n\n/**\n * §9.1 (`leakTest.canary`) / §10.4: cari canary pada output bundle client.\n * Dipakai `generateBundle` plugin — build gagal bila canary ditemukan.\n */\nexport function findLeak(\n outputs: Iterable<BundleOutputLike>,\n canary: string,\n decode: (source: Uint8Array) => string = defaultDecode,\n): { fileName: string } | null {\n for (const output of outputs) {\n const fileName = output.fileName ?? \"(unknown)\";\n let text = \"\";\n if (typeof output.code === \"string\") {\n text = output.code;\n } else if (typeof output.source === \"string\") {\n text = output.source;\n } else if (output.source instanceof Uint8Array) {\n text = decode(output.source);\n }\n if (text.includes(canary)) {\n return { fileName };\n }\n }\n return null;\n}\n\nfunction defaultDecode(bytes: Uint8Array): string {\n return new TextDecoder().decode(bytes);\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "B0BD6103F707A0BE64756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|