@moonsjs/vite 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-1fnt137k.js → index-qz9sc74p.js} +2 -2
- package/dist/{index-1fnt137k.js.map → index-qz9sc74p.js.map} +2 -2
- package/dist/{index-e7qz0epf.js → index-tysyk2qf.js} +13 -13
- package/dist/{index-e7qz0epf.js.map → index-tysyk2qf.js.map} +4 -4
- package/dist/index.js +16 -16
- package/dist/index.js.map +4 -4
- package/dist/server/index.js +131 -23
- package/dist/server/index.js.map +7 -6
- package/dist/server/isr.d.ts +25 -0
- package/dist/server/isr.d.ts.map +1 -0
- package/dist/server/node-server.d.ts +6 -0
- package/dist/server/node-server.d.ts.map +1 -1
- package/dist/server/prerender.d.ts.map +1 -1
- package/dist/transform.js +1 -1
- package/package.json +10 -3
- package/src/api.ts +4 -4
- package/src/plugin.ts +13 -9
- package/src/server/handler.ts +7 -7
- package/src/server/isr.ts +81 -0
- package/src/server/node-server.ts +85 -12
- package/src/server/prerender.ts +33 -7
- package/src/server/shell.ts +1 -1
- package/src/server-only.ts +1 -1
- package/src/transform.ts +11 -11
package/dist/index.js.map
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/plugin.ts", "../src/api.ts", "../src/leak-check.ts"],
|
|
4
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 scanApiMiddlewares,\n scanApiRoutes,\n scanRoutes,\n validateConfig,\n type ApiMiddlewareDefinition,\n type ApiRouteDefinition,\n type RouteDefinition,\n} from \"@moonsjs/core\";\nimport { loadConfigFromFile, type Plugin, type ViteDevServer } from \"vite\";\nimport { assertApiModuleExports, assertMiddlewareExports } from \"./api\";\nimport { findLeak } from \"./leak-check\";\nimport type { PackageJsonInfo } from \"./server-only\";\nimport { renderApiModule, 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 serverOnlyPackages: ReadonlyArray<string> = [];\n let apiDir = \"\";\n let apiRoutes: ApiRouteDefinition[] = [];\n let apiMiddlewares: ApiMiddlewareDefinition[] = [];\n /** Cache package.json untuk gate Addendum C (dibagi lintas modul). */\n const packageCache = new Map<string, PackageJsonInfo | null>(); 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 // D.5: dua entry — server (index) + prerender runner.\n ssr: true,\n rollupOptions: {\n input: {\n index: \".moons/server-entry.ts\",\n prerender: \".moons/prerender-entry.ts\",\n },\n output: {\n entryFileNames: \"[name].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n },\n },\n },\n ssr: { noExternal: true, target: \"node\" as const },\n };\n }\n\n return {\n ...common,\n build: { outDir: \"dist/client\", emptyOutDir: true },\n // Dev SSR: paket framework WAJIB di-inline ke pipeline Vite. Sejak\n // dipublikasikan, `@moonsjs/*` adalah package node_modules biasa (bukan\n // workspace-link) sehingga default Vite mengeksternalnya; import runtime\n // (bun) menyelesaikannya lewat kondisi `bun` → `src`, sedangkan modul\n // route diselesaikan Vite → `dist` — dua instans React context →\n // \"useLoaderData dipanggil di luar render route\" (temuan eval T4;\n // docs/decisions/0015). Inline → semua konsisten lewat Vite.\n ssr: { noExternal: [/^@moonsjs\\//] },\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 serverOnlyPackages = config.security?.serverOnlyPackages ?? [];\n\n // Addendum D.1: scan + validasi statis modul `src/api`.\n apiDir = resolvePath(root, config.apiDir ?? \"src/api\");\n if (existsSync(apiDir)) {\n apiRoutes = scanApiRoutes(apiDir);\n for (const route of apiRoutes) {\n assertApiModuleExports(readFileSync(route.file, \"utf8\"), route.file);\n }\n apiMiddlewares = scanApiMiddlewares(apiDir);\n for (const middleware of apiMiddlewares) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\n } else {\n apiRoutes = [];\n apiMiddlewares = [];\n }\n },\n\n async buildStart() {\n routes = scanRoutes(routesDir);\n // D.3: validasi statis `_middleware.ts` pohon routes.\n for (const middleware of routes.filter((route) => route.kind === \"middleware\")) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\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 writeFileSync(\n resolvePath(root, \".moons/prerender-entry.ts\"),\n renderPrerenderEntry(routesDir, root, options.leakTest?.canary),\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.api:\n return renderApiModule(apiRoutes, apiMiddlewares, 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 apiDir,\n serverOnlyPackages,\n packageCache,\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, {\n templatePath: resolvePath(root, \"index.html\"),\n // A1: pemindaian payload SSR hanya di dev (warning), tanpa biaya di production.\n payloadScan: {\n ...(options.leakTest?.canary === undefined ? {} : { canary: options.leakTest.canary }),\n env: process.env,\n },\n // D.1: request ke prefix API (semua method) dirutekan ke runtime.\n ...(apiRoutes.length === 0\n ? {}\n : { apiPrefix: `/${apiDir.split(/[\\\\/]/).filter((part) => part.length > 0).pop() ?? \"api\"}` }),\n });\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(apiDir) && existsSync(apiDir)) {\n try {\n apiRoutes = scanApiRoutes(apiDir);\n for (const route of apiRoutes) {\n assertApiModuleExports(readFileSync(route.file, \"utf8\"), route.file);\n }\n apiMiddlewares = scanApiMiddlewares(apiDir);\n for (const middleware of apiMiddlewares) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\n } catch (error) {\n context.server.config.logger.error(String(error));\n return;\n }\n invalidateVirtualModules(context.server);\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 for (const middleware of routes.filter((route) => route.kind === \"middleware\")) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\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 { createPluginRuntime, createRequestHandler } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n 'import { apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware } from \"virtual:moons/api\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"export function createDevApp(shell, payloadScan) {\",\n \" const plugins = createPluginRuntime({ config, routes, middlewares: config.middleware ?? [] });\",\n ` const handler = createRequestHandler({ routes, apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware, config, routesDir: ${JSON.stringify(routesDir)}, loadRoute, shell, onContext: (ctx) => plugins.applyExtensions(ctx), ...(payloadScan === undefined ? {} : { payloadScan }) });`,\n \" return { handler, plugins };\",\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, createPluginRuntime, createRequestHandler, startNodeServer } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n 'import { apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware } from \"virtual:moons/api\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"const plugins = createPluginRuntime({ config, routes, middlewares: config.middleware ?? [] });\",\n \"const handler = createRequestHandler({\",\n \" routes,\",\n \" apiRoutes,\",\n \" apiMiddlewares,\",\n \" loadApi,\",\n \" loadApiMiddleware,\",\n \" config,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" shell: createFileShell(),\",\n \" onContext: (ctx) => plugins.applyExtensions(ctx),\",\n \"});\",\n \"\",\n \"startNodeServer(handler, { plugins });\",\n \"\",\n ].join(\"\\n\");\n}\n\ninterface ModuleGraphLike {\n getModulesByFile(file: string): Iterable<{ id?: string | null }> | undefined;\n invalidateModule(module: unknown): void;\n}\n\n/** Entry D.5: runner prerender (dijalankan CLI setelah build server). */\nfunction renderPrerenderEntry(\n routesDir: string,\n projectRoot: string,\n canary: string | undefined,\n): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n 'import { createFileShell, createRequestHandler, runPrerender } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n \"\",\n \"const handler = createRequestHandler({\",\n \" routes,\",\n \" config,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" shell: createFileShell(),\",\n \"});\",\n \"\",\n \"await runPrerender({\",\n \" routes,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" handler,\",\n ` clientDir: ${JSON.stringify(resolvePath(projectRoot, \"dist/client\"))},`,\n ...(canary === undefined ? [] : [` canary: ${JSON.stringify(canary)},`]),\n \"});\",\n \"\",\n ].join(\"\\n\");\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
|
-
"import { parse } from \"@babel/parser\";\nimport { API_METHODS, MoonsError } from \"@moonsjs/core\";\n\n/**\n * Validasi statis export modul `src/api` (PRD Addendum D.1):\n * hanya handler method `GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS` sebagai fungsi;\n * `default`/export lain ditolak → `E_API_HANDLER_INVALID`.\n */\nexport function assertApiModuleExports(code: string, file: string): string[] {\n let ast: unknown;\n try {\n ast = parse(code, {\n sourceType: \"module\",\n plugins: file.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n });\n } catch {\n return []; // biarkan bundler melaporkan syntax error\n }\n\n const program = (ast as { program?: { body?: Array<Record<string, unknown>> } }).program;\n const body = program?.body ?? [];\n const methods: string[] = [];\n\n for (const statement of body) {\n if (statement[\"type\"] === \"ExportDefaultDeclaration\") {\n throw apiError(\n file,\n \"export `default` tidak didukung di modul API\",\n \"Modul `src/api` hanya mengekspor handler method bernama
|
|
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 scanApiMiddlewares,\n scanApiRoutes,\n scanRoutes,\n validateConfig,\n type ApiMiddlewareDefinition,\n type ApiRouteDefinition,\n type RouteDefinition,\n} from \"@moonsjs/core\";\nimport { loadConfigFromFile, type Plugin, type ViteDevServer } from \"vite\";\nimport { assertApiModuleExports, assertMiddlewareExports } from \"./api\";\nimport { findLeak } from \"./leak-check\";\nimport type { PackageJsonInfo } from \"./server-only\";\nimport { renderApiModule, 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 serverOnlyPackages: ReadonlyArray<string> = [];\n let apiDir = \"\";\n let apiRoutes: ApiRouteDefinition[] = [];\n let apiMiddlewares: ApiMiddlewareDefinition[] = [];\n /** Cache package.json untuk gate Addendum C (dibagi lintas modul). */\n const packageCache = new Map<string, PackageJsonInfo | null>(); 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.\",\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 // D.5: dua entry — server (index) + prerender runner.\n ssr: true,\n rollupOptions: {\n input: {\n index: \".moons/server-entry.ts\",\n prerender: \".moons/prerender-entry.ts\",\n },\n output: {\n entryFileNames: \"[name].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n },\n },\n },\n ssr: { noExternal: true, target: \"node\" as const },\n };\n }\n\n return {\n ...common,\n build: { outDir: \"dist/client\", emptyOutDir: true },\n // Dev SSR: paket framework WAJIB di-inline ke pipeline Vite. Sejak\n // dipublikasikan, `@moonsjs/*` adalah package node_modules biasa (bukan\n // workspace-link) sehingga default Vite mengeksternalnya; import runtime\n // (bun) menyelesaikannya lewat kondisi `bun` → `src`, sedangkan modul\n // route diselesaikan Vite → `dist` — dua instans React context →\n // \"useLoaderData dipanggil di luar render route\" (temuan eval T4;\n // docs/decisions/0015). Inline → semua konsisten lewat Vite.\n ssr: { noExternal: [/^@moonsjs\\//] },\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.\",\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 serverOnlyPackages = config.security?.serverOnlyPackages ?? [];\n\n // Addendum D.1: scan + validasi statis modul `src/api`.\n apiDir = resolvePath(root, config.apiDir ?? \"src/api\");\n if (existsSync(apiDir)) {\n apiRoutes = scanApiRoutes(apiDir);\n for (const route of apiRoutes) {\n assertApiModuleExports(readFileSync(route.file, \"utf8\"), route.file);\n }\n apiMiddlewares = scanApiMiddlewares(apiDir);\n for (const middleware of apiMiddlewares) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\n } else {\n apiRoutes = [];\n apiMiddlewares = [];\n }\n },\n\n async buildStart() {\n routes = scanRoutes(routesDir);\n // D.3: validasi statis `_middleware.ts` pohon routes.\n for (const middleware of routes.filter((route) => route.kind === \"middleware\")) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\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(), options.leakTest?.canary),\n \"utf8\",\n );\n writeFileSync(\n resolvePath(root, \".moons/prerender-entry.ts\"),\n renderPrerenderEntry(routesDir, root, options.leakTest?.canary),\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.api:\n return renderApiModule(apiRoutes, apiMiddlewares, 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 apiDir,\n serverOnlyPackages,\n packageCache,\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 gagal: kode server bocor ke output client. Build dihentikan.\",\n suggestions: [\n \"Periksa transform `*.server.ts`\",\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: setiap `*.server.ts` di bundle client wajib berupa stub RPC hasil transform.\",\n suggestions: [\n \"Pastikan transform zero-trust berjalan untuk modul ini\",\n \"Laporkan ini sebagai bug framework jika berulang\",\n ],\n });\n }\n }\n },\n\n configureServer(server) {\n installDevMiddleware(server, {\n templatePath: resolvePath(root, \"index.html\"),\n // A1: pemindaian payload SSR hanya di dev (warning), tanpa biaya di production.\n payloadScan: {\n ...(options.leakTest?.canary === undefined ? {} : { canary: options.leakTest.canary }),\n env: process.env,\n },\n // D.1: request ke prefix API (semua method) dirutekan ke runtime.\n ...(apiRoutes.length === 0\n ? {}\n : { apiPrefix: `/${apiDir.split(/[\\\\/]/).filter((part) => part.length > 0).pop() ?? \"api\"}` }),\n });\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(apiDir) && existsSync(apiDir)) {\n try {\n apiRoutes = scanApiRoutes(apiDir);\n for (const route of apiRoutes) {\n assertApiModuleExports(readFileSync(route.file, \"utf8\"), route.file);\n }\n apiMiddlewares = scanApiMiddlewares(apiDir);\n for (const middleware of apiMiddlewares) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\n } catch (error) {\n context.server.config.logger.error(String(error));\n return;\n }\n invalidateVirtualModules(context.server);\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 for (const middleware of routes.filter((route) => route.kind === \"middleware\")) {\n assertMiddlewareExports(readFileSync(middleware.file, \"utf8\"), middleware.file);\n }\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 { createPluginRuntime, createRequestHandler } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n 'import { apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware } from \"virtual:moons/api\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"export function createDevApp(shell, payloadScan) {\",\n \" const plugins = createPluginRuntime({ config, routes, middlewares: config.middleware ?? [] });\",\n ` const handler = createRequestHandler({ routes, apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware, config, routesDir: ${JSON.stringify(routesDir)}, loadRoute, shell, onContext: (ctx) => plugins.applyExtensions(ctx), ...(payloadScan === undefined ? {} : { payloadScan }) });`,\n \" return { handler, plugins };\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction renderServerEntryBuild(\n routesDir: string,\n eagerImports: string[],\n canary: string | undefined,\n): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n 'import { createFileShell, createPluginRuntime, createRequestHandler, startNodeServer } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n 'import { apiRoutes, apiMiddlewares, loadApi, loadApiMiddleware } from \"virtual:moons/api\";',\n ...eagerImports.map((specifier) => `import ${JSON.stringify(specifier)};`),\n \"\",\n \"const plugins = createPluginRuntime({ config, routes, middlewares: config.middleware ?? [] });\",\n \"const handler = createRequestHandler({\",\n \" routes,\",\n \" apiRoutes,\",\n \" apiMiddlewares,\",\n \" loadApi,\",\n \" loadApiMiddleware,\",\n \" config,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" shell: createFileShell(),\",\n \" onContext: (ctx) => plugins.applyExtensions(ctx),\",\n \"});\",\n \"\",\n `startNodeServer(handler, { plugins${canary === undefined ? \"\" : `, canary: ${JSON.stringify(canary)}`} });`,\n \"\",\n ].join(\"\\n\");\n}\n\ninterface ModuleGraphLike {\n getModulesByFile(file: string): Iterable<{ id?: string | null }> | undefined;\n invalidateModule(module: unknown): void;\n}\n\n/** Entry D.5: runner prerender (dijalankan CLI setelah build server). */\nfunction renderPrerenderEntry(\n routesDir: string,\n projectRoot: string,\n canary: string | undefined,\n): string {\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n 'import { createFileShell, createRequestHandler, runPrerender } from \"@moonsjs/vite/server\";',\n 'import config from \"virtual:moons/config\";',\n 'import { routes, loadRoute } from \"virtual:moons/routes\";',\n \"\",\n \"const handler = createRequestHandler({\",\n \" routes,\",\n \" config,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" shell: createFileShell(),\",\n \"});\",\n \"\",\n \"await runPrerender({\",\n \" routes,\",\n ` routesDir: ${JSON.stringify(routesDir)},`,\n \" loadRoute,\",\n \" handler,\",\n ` clientDir: ${JSON.stringify(resolvePath(projectRoot, \"dist/client\"))},`,\n ...(canary === undefined ? [] : [` canary: ${JSON.stringify(canary)},`]),\n \"});\",\n \"\",\n ].join(\"\\n\");\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
|
+
"import { parse } from \"@babel/parser\";\nimport { API_METHODS, MoonsError } from \"@moonsjs/core\";\n\n/**\n * Validasi statis export modul `src/api` (PRD Addendum D.1):\n * hanya handler method `GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS` sebagai fungsi;\n * `default`/export lain ditolak → `E_API_HANDLER_INVALID`.\n */\nexport function assertApiModuleExports(code: string, file: string): string[] {\n let ast: unknown;\n try {\n ast = parse(code, {\n sourceType: \"module\",\n plugins: file.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n });\n } catch {\n return []; // biarkan bundler melaporkan syntax error\n }\n\n const program = (ast as { program?: { body?: Array<Record<string, unknown>> } }).program;\n const body = program?.body ?? [];\n const methods: string[] = [];\n\n for (const statement of body) {\n if (statement[\"type\"] === \"ExportDefaultDeclaration\") {\n throw apiError(\n file,\n \"export `default` tidak didukung di modul API\",\n \"Modul `src/api` hanya mengekspor handler method bernama.\",\n [\"Ganti menjadi `export const GET = (args) => …`\", \"Hapus export default\"],\n );\n }\n if (statement[\"type\"] !== \"ExportNamedDeclaration\") {\n continue;\n }\n if (statement[\"source\"] !== undefined) {\n // re-export `export { X } from \"...\"` — nama tetap dicek di bawah.\n }\n const declaration = statement[\"declaration\"] as Record<string, unknown> | undefined;\n if (declaration !== undefined) {\n if (declaration[\"type\"] === \"VariableDeclaration\") {\n for (const declarator of (declaration[\"declarations\"] ?? []) as Array<Record<string, unknown>>) {\n const id = declarator[\"id\"] as Record<string, unknown> | undefined;\n if (id?.[\"type\"] === \"Identifier\") {\n methods.push(id[\"name\"] as string);\n }\n }\n } else if (declaration[\"type\"] === \"FunctionDeclaration\") {\n const id = declaration[\"id\"] as Record<string, unknown> | undefined;\n if (id?.[\"type\"] === \"Identifier\") {\n methods.push(id[\"name\"] as string);\n }\n }\n continue;\n }\n for (const specifier of (statement[\"specifiers\"] ?? []) as Array<Record<string, unknown>>) {\n const exported = specifier[\"exported\"] as Record<string, unknown> | undefined;\n if (exported?.[\"type\"] === \"Identifier\") {\n methods.push(exported[\"name\"] as string);\n }\n }\n }\n\n const illegal = methods.filter((name) => !API_METHODS.includes(name as never));\n if (illegal.length > 0) {\n throw apiError(\n file,\n `export \\`${illegal[0]}\\` bukan handler method yang dikenal`,\n `Handler yang legal: ${API_METHODS.join(\", \")}.`,\n [\n \"Ganti nama export menjadi salah satu method HTTP\",\n \"Pindahkan helper ke modul lain (mis. `src/server/…`)\",\n ],\n );\n }\n if (methods.length === 0) {\n throw apiError(\n file,\n \"modul API tanpa handler method\",\n `Wajib ada minimal satu dari ${API_METHODS.join(\", \")}.`,\n [`Tambahkan \\`export const GET = (args) => new Response(…)\\``],\n );\n }\n\n return methods;\n}\n\nexport function assertMiddlewareExports(code: string, file: string): void {\n let ast: unknown;\n try {\n ast = parse(code, {\n sourceType: \"module\",\n plugins: file.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n });\n } catch {\n return;\n }\n const program = (ast as { program?: { body?: Array<Record<string, unknown>> } }).program;\n const hasDefault = (program?.body ?? []).some(\n (statement) => statement[\"type\"] === \"ExportDefaultDeclaration\",\n );\n if (!hasDefault) {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file,\n message: \"`_middleware.ts` tanpa `export default`\",\n details: \"Middleware direktori mengikuti bentuk `Middleware`: `(args) => Promise<Response>`.\",\n suggestions: [\n \"Tambahkan `export default async ({ req, ctx, next }) => await next()`\",\n \"Hapus file bila tidak dipakai\",\n ],\n });\n }\n}\n\nfunction apiError(file: string, message: string, details: string, suggestions: string[]): MoonsError {\n return new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file,\n message,\n details,\n suggestions,\n });\n}\n",
|
|
7
7
|
"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"
|
|
8
8
|
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "
|
|
9
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA,oBAAS;AACT;AAAA,gBACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWF;;;ACfA;AACA;AAOO,SAAS,sBAAsB,CAAC,MAAc,MAAwB;AAAA,EAC3E,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,MAAM,MAAM,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,SAAS,KAAK,SAAS,MAAM,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC,YAAY;AAAA,IACxE,CAAC;AAAA,IACD,MAAM;AAAA,IACN,OAAO,CAAC;AAAA;AAAA,EAGV,MAAM,UAAW,IAAgE;AAAA,EACjF,MAAM,OAAO,SAAS,QAAQ,CAAC;AAAA,EAC/B,MAAM,UAAoB,CAAC;AAAA,EAE3B,WAAW,aAAa,MAAM;AAAA,IAC5B,IAAI,UAAU,YAAY,4BAA4B;AAAA,MACpD,MAAM,SACJ,MACA,gDACA,4DACA,CAAC,kDAAkD,sBAAsB,CAC3E;AAAA,IACF;AAAA,IACA,IAAI,UAAU,YAAY,0BAA0B;AAAA,MAClD;AAAA,IACF;AAAA,IACA,IAAI,UAAU,cAAc,WAAW,CAEvC;AAAA,IACA,MAAM,cAAc,UAAU;AAAA,IAC9B,IAAI,gBAAgB,WAAW;AAAA,MAC7B,IAAI,YAAY,YAAY,uBAAuB;AAAA,QACjD,WAAW,cAAe,YAAY,mBAAmB,CAAC,GAAsC;AAAA,UAC9F,MAAM,KAAK,WAAW;AAAA,UACtB,IAAI,KAAK,YAAY,cAAc;AAAA,YACjC,QAAQ,KAAK,GAAG,OAAiB;AAAA,UACnC;AAAA,QACF;AAAA,MACF,EAAO,SAAI,YAAY,YAAY,uBAAuB;AAAA,QACxD,MAAM,KAAK,YAAY;AAAA,QACvB,IAAI,KAAK,YAAY,cAAc;AAAA,UACjC,QAAQ,KAAK,GAAG,OAAiB;AAAA,QACnC;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAW,aAAc,UAAU,iBAAiB,CAAC,GAAsC;AAAA,MACzF,MAAM,WAAW,UAAU;AAAA,MAC3B,IAAI,WAAW,YAAY,cAAc;AAAA,QACvC,QAAQ,KAAK,SAAS,OAAiB;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,QAAQ,OAAO,CAAC,SAAS,CAAC,YAAY,SAAS,IAAa,CAAC;AAAA,EAC7E,IAAI,QAAQ,SAAS,GAAG;AAAA,IACtB,MAAM,SACJ,MACA,YAAY,QAAQ,0CACpB,uBAAuB,YAAY,KAAK,IAAI,MAC5C;AAAA,MACE;AAAA,MACA;AAAA,IACF,CACF;AAAA,EACF;AAAA,EACA,IAAI,QAAQ,WAAW,GAAG;AAAA,IACxB,MAAM,SACJ,MACA,kCACA,+BAA+B,YAAY,KAAK,IAAI,MACpD,CAAC,4DAA4D,CAC/D;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAGF,SAAS,uBAAuB,CAAC,MAAc,MAAoB;AAAA,EACxE,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,MAAM,MAAM,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,SAAS,KAAK,SAAS,MAAM,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC,YAAY;AAAA,IACxE,CAAC;AAAA,IACD,MAAM;AAAA,IACN;AAAA;AAAA,EAEF,MAAM,UAAW,IAAgE;AAAA,EACjF,MAAM,cAAc,SAAS,QAAQ,CAAC,GAAG,KACvC,CAAC,cAAc,UAAU,YAAY,0BACvC;AAAA,EACA,IAAI,CAAC,YAAY;AAAA,IACf,MAAM,IAAI,WAAW;AAAA,MACnB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT,aAAa;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAGF,SAAS,QAAQ,CAAC,MAAc,SAAiB,SAAiB,aAAmC;AAAA,EACnG,OAAO,IAAI,WAAW;AAAA,IACpB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA;;;AC/GI,SAAS,QAAQ,CACtB,SACA,QACA,SAAyC,eACZ;AAAA,EAC7B,WAAW,UAAU,SAAS;AAAA,IAC5B,MAAM,WAAW,OAAO,YAAY;AAAA,IACpC,IAAI,OAAO;AAAA,IACX,IAAI,OAAO,OAAO,SAAS,UAAU;AAAA,MACnC,OAAO,OAAO;AAAA,IAChB,EAAO,SAAI,OAAO,OAAO,WAAW,UAAU;AAAA,MAC5C,OAAO,OAAO;AAAA,IAChB,EAAO,SAAI,OAAO,kBAAkB,YAAY;AAAA,MAC9C,OAAO,OAAO,OAAO,MAAM;AAAA,IAC7B;AAAA,IACA,IAAI,KAAK,SAAS,MAAM,GAAG;AAAA,MACzB,OAAO,EAAE,SAAS;AAAA,IACpB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,aAAa,CAAC,OAA2B;AAAA,EAChD,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA;;;AFgBvC,IAAM,oBAAoB;AAE1B,SAAwB,KAAK,CAAC,UAAkC,CAAC,GAAW;AAAA,EAC1E,IAAI,OAAO,QAAQ,eAAe,QAAQ,IAAI;AAAA,EAC9C,IAAI,aAAa;AAAA,EACjB,IAAI,iBAAiB;AAAA,EACrB,IAAI,YAAY;AAAA,EAChB,IAAI,qBAA4C,CAAC;AAAA,EACjD,IAAI,SAAS;AAAA,EACb,IAAI,YAAkC,CAAC;AAAA,EACvC,IAAI,iBAA4C,CAAC;AAAA,EAEjD,MAAM,eAAe,IAAI;AAAA,EAAwC,IAAI,SAA4B,CAAC;AAAA,EAClG,IAAI,gBAAgB,IAAI;AAAA,EACxB,MAAM,kBAAkB,IAAI;AAAA,EAE5B,SAAS,WAAW,CAAC,cAAiD;AAAA,IACpE,MAAM,SAAS,cAAc,IAAI,YAAY;AAAA,IAC7C,IAAI,WAAW,WAAW;AAAA,MACxB,OAAO;AAAA,IACT;AAAA,IACA,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,SAAS,aAAa,cAAc,MAAM;AAAA,MAC1C,MAAM;AAAA,MACN,OAAO;AAAA;AAAA,IAET,MAAM,WAAW,mBAAkB,QAAQ,cAAc,IAAI;AAAA,IAC7D,cAAc,IAAI,cAAc,QAAQ;AAAA,IACxC,OAAO;AAAA;AAAA,EAGT,SAAS,gBAAgB,GAAS;AAAA,IAChC,MAAM,OAAO,IAAI;AAAA,IACjB,MAAM,WAAmC,CAAC;AAAA,IAE1C,WAAW,QAAQ,iBAAgB,IAAI,GAAG;AAAA,MACxC,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,SAAS,aAAa,MAAM,MAAM;AAAA,QAClC,MAAM;AAAA,QACN;AAAA;AAAA,MAEF,MAAM,WAAW,mBAAkB,QAAQ,MAAM,IAAI;AAAA,MACrD,KAAK,IAAI,MAAM,QAAQ;AAAA,MACvB,WAAW,MAAM,SAAS,WAAW;AAAA,QACnC,SAAS,cAAc,MAAM,MAAM,GAAG,IAAI,KAAK,GAAG;AAAA,MACpD;AAAA,IACF;AAAA,IAEA,gBAAgB;AAAA,IAChB,MAAM,SAAS,YAAY,MAAM,QAAQ;AAAA,IACzC,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,IACrC,cACE,YAAY,QAAQ,kBAAkB,GACtC,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,GACnC,MACF;AAAA;AAAA,EAIF,SAAS,sBAAsB,GAAa;AAAA,IAC1C,MAAM,aAAuB,CAAC;AAAA,IAC9B,YAAY,MAAM,aAAa,eAAe;AAAA,MAC5C,IAAI,SAAS,UAAU,SAAS,GAAG;AAAA,QACjC,WAAW,KAAK,cAAc,MAAM,IAAI,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,IACA,OAAO,WAAW,KAAK;AAAA;AAAA,EAIzB,SAAS,yBAAyB,CAAC,MAAc,IAAoB;AAAA,IACnE,MAAM,eAAe,GAAG,WAAW,IAAI,IACnC,GAAG,MAAM,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE,KAAK,GAAG,IAC1C;AAAA,IACJ,MAAM,WAAW,WAAW,QAAQ,EAAE,OAAO,GAAG,mBAAiB,MAAM,EAAE,OAAO,KAAK;AAAA,IACrF,MAAM,YAAY,YAAY,MAAM,gBAAgB,GAAG,aAAa;AAAA,IAEpE,IAAI,WAAW,SAAS,GAAG;AAAA,MACzB,gBAAgB,IAAI,EAAE;AAAA,MACtB,OAAO,aAAa,WAAW,MAAM;AAAA,IACvC;AAAA,IAEA,MAAM,WAAW,YAAY,EAAE;AAAA,IAC/B,IAAI,aAAa,MAAM;AAAA,MACrB,MAAM,IAAI,YAAW;AAAA,QACnB,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa,CAAC,4BAA4B;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,OAAO,oBAAmB,MAAM,IAAI,UAAU;AAAA,MAClD,kBAAkB,CAAC,YAAY,cAAc;AAAA,QAC3C,MAAM,WAAW,4BAA2B,YAAY,SAAS;AAAA,QACjE,OAAO,aAAa,OAAO,OAAO,YAAY,QAAQ;AAAA;AAAA,IAE1D,CAAC;AAAA,IAED,UAAU,YAAY,MAAM,cAAc,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,IAChE,cAAc,WAAW,KAAK,MAAM,MAAM;AAAA,IAC1C,gBAAgB,IAAI,EAAE;AAAA,IACtB,OAAO,KAAK;AAAA;AAAA,EAGd,OAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,MAAM,CAAC,SAAS,KAAK;AAAA,MACnB,aAAa,IAAI,eAAe;AAAA,MAChC,MAAM,SAAS;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MAEA,IAAI,YAAY;AAAA,QACd,OAAO;AAAA,aACF;AAAA,UACH,OAAO;AAAA,YACL,QAAQ;AAAA,YACR,aAAa;AAAA,YAIb,KAAK;AAAA,YACL,eAAe;AAAA,cACb,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,WAAW;AAAA,cACb;AAAA,cACA,QAAQ;AAAA,gBACN,gBAAgB;AAAA,gBAChB,gBAAgB;AAAA,cAClB;AAAA,YACF;AAAA,UACF;AAAA,UACA,KAAK,EAAE,YAAY,MAAM,QAAQ,OAAgB;AAAA,QACnD;AAAA,MACF;AAAA,MAEA,OAAO;AAAA,WACF;AAAA,QACH,OAAO,EAAE,QAAQ,eAAe,aAAa,KAAK;AAAA,QAQlD,KAAK,EAAE,YAAY,CAAC,aAAa,EAAE;AAAA,MACrC;AAAA;AAAA,SAGI,eAAc,CAAC,UAAU;AAAA,MAC7B,OAAO,QAAQ,eAAe,SAAS;AAAA,MACvC,iBAAiB,YAAY,MAAM,QAAQ,cAAc,iBAAiB;AAAA,MAE1E,IAAI,CAAC,WAAW,cAAc,GAAG;AAAA,QAC/B,MAAM,IAAI,YAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa;AAAA,YACX;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,MAAM,SAAS,MAAM,mBACnB,EAAE,SAAS,SAAS,SAAS,MAAM,SAAS,KAAK,GACjD,gBACA,IACF;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,OAAO,OAAO;AAAA,QACd,IAAI,iBAAiB,aAAY;AAAA,UAC/B,MAAM;AAAA,QACR;AAAA,QACA,MAAM,IAAI,YAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC9D,aAAa,CAAC,iDAAiD;AAAA,QACjE,CAAC;AAAA;AAAA,MAGH,MAAM,SAAS,eAAe,KAAK,EAAE,MAAM,gBAAgB,aAAa,KAAK,CAAC;AAAA,MAC9E,YAAY,YAAY,MAAM,OAAO,SAAS;AAAA,MAC9C,qBAAqB,OAAO,UAAU,sBAAsB,CAAC;AAAA,MAG7D,SAAS,YAAY,MAAM,OAAO,UAAU,SAAS;AAAA,MACrD,IAAI,WAAW,MAAM,GAAG;AAAA,QACtB,YAAY,cAAc,MAAM;AAAA,QAChC,WAAW,SAAS,WAAW;AAAA,UAC7B,uBAAuB,aAAa,MAAM,MAAM,MAAM,GAAG,MAAM,IAAI;AAAA,QACrE;AAAA,QACA,iBAAiB,mBAAmB,MAAM;AAAA,QAC1C,WAAW,cAAc,gBAAgB;AAAA,UACvC,wBAAwB,aAAa,WAAW,MAAM,MAAM,GAAG,WAAW,IAAI;AAAA,QAChF;AAAA,MACF,EAAO;AAAA,QACL,YAAY,CAAC;AAAA,QACb,iBAAiB,CAAC;AAAA;AAAA;AAAA,SAIhB,WAAU,GAAG;AAAA,MACjB,SAAS,WAAW,SAAS;AAAA,MAE7B,WAAW,cAAc,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,YAAY,GAAG;AAAA,QAC9E,wBAAwB,aAAa,WAAW,MAAM,MAAM,GAAG,WAAW,IAAI;AAAA,MAChF;AAAA,MACA,MAAM,cAAc;AAAA,QAClB;AAAA,QACA,YAAY;AAAA,QACZ,QAAQ,YAAY,MAAM,QAAQ;AAAA,MACpC,CAAC;AAAA,MACD,iBAAiB;AAAA,MACjB,IAAI,YAAY;AAAA,QACd,cACE,YAAY,MAAM,wBAAwB,GAC1C,uBAAuB,WAAW,uBAAuB,GAAG,QAAQ,UAAU,MAAM,GACpF,MACF;AAAA,QACA,cACE,YAAY,MAAM,2BAA2B,GAC7C,qBAAqB,WAAW,MAAM,QAAQ,UAAU,MAAM,GAC9D,MACF;AAAA,MACF;AAAA;AAAA,IAGF,SAAS,CAAC,IAAI;AAAA,MACZ,MAAM,QAAQ,GAAG,WAAW,MAAI,IAAI,GAAG,MAAM,CAAC,IAAI;AAAA,MAClD,IAAK,OAAO,OAAO,eAAe,EAAe,SAAS,KAAK,GAAG;AAAA,QAChE,OAAO,OAAK;AAAA,MACd;AAAA,MACA;AAAA;AAAA,IAGF,IAAI,CAAC,IAAI;AAAA,MACP,MAAM,OAAO,iBAAiB,EAAE;AAAA,MAChC,IAAI,SAAS,MAAM;AAAA,QACjB;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,aACD,gBAAgB;AAAA,UACnB,OAAO,mBAAmB,QAAQ,WAAW,IAAI;AAAA,aAC9C,gBAAgB;AAAA,UACnB,OAAO,gBAAgB,WAAW,gBAAgB,IAAI;AAAA,aACnD,gBAAgB;AAAA,UACnB,OAAO;AAAA;AAAA;AAAA,aACJ,gBAAgB;AAAA,UACnB,OAAO,mBAAmB,MAAM,cAAc;AAAA,aAC3C,gBAAgB;AAAA,UAEnB,OAAO,qBAAqB,WAAW,uBAAuB,CAAC;AAAA;AAAA;AAAA,SAI/D,UAAS,CAAC,MAAM,IAAI;AAAA,MACxB,MAAM,UAAU,YAAW,EAAE;AAAA,MAC7B,IAAI,QAAQ,WAAW,MAAI,KAAK,QAAQ,SAAS,gBAAgB,GAAG;AAAA,QAClE;AAAA,MACF;AAAA,MAEA,MAAM,cAAc,gBAAgB,IAAI;AAAA,MAExC,IAAI,kBAAiB,OAAO,GAAG;AAAA,QAC7B,IAAI,gBAAgB,OAAO;AAAA,UACzB,MAAM,WAAW,cAAc,IAAI,OAAO,KAAK,YAAY,OAAO;AAAA,UAClE,IAAI,aAAa,QAAQ,SAAS,UAAU,WAAW,GAAG;AAAA,YACxD;AAAA,UACF;AAAA,UACA,OAAO,oBAAmB,MAAM,UAAU,IAAI;AAAA,QAChD;AAAA,QACA,OAAO,0BAA0B,MAAM,OAAO;AAAA,MAChD;AAAA,MAIA,IAAI,gBAAgB,SAAS,yBAAwB,OAAO,GAAG;AAAA,QAC7D,MAAM,4BAA2B,SAAS,IAAI;AAAA,MAChD;AAAA,MAEA,IAAI,gBAAgB,SAAS,kBAAkB,KAAK,OAAO,GAAG;AAAA,QAC5D,IAAI,QAAQ,WAAW,SAAS,KAAK,QAAQ,SAAS,MAAM,GAAG;AAAA,UAC7D,yBAAwB;AAAA,YACtB,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA,aAAa;AAAA,UACf,CAAC;AAAA,QACH;AAAA,QACA,MAAM,0BAAyB;AAAA,UAC7B,MAAM;AAAA,UACN;AAAA,UACA,aAAa;AAAA,UAEb,SAAS,OAAO,WAAW,aAAa;AAAA,YACtC,IAAI;AAAA,cACF,MAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,QAAQ;AAAA,cACvD,OAAO,aAAa,OAAO,OAAO,YAAW,SAAS,EAAE;AAAA,cACxD,MAAM;AAAA,cACN,OAAO;AAAA;AAAA;AAAA,UAGX,SAAS,CAAC,iBAAiB,cAAc,IAAI,YAAY,KAAK,YAAY,YAAY;AAAA,UACtF;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA;AAAA;AAAA,IAGF,cAAc,CAAC,UAAU,QAAQ;AAAA,MAC/B,IAAI,gBAAgB,IAAI,MAAM,OAAO;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,MAAM,SAAS,QAAQ,UAAU;AAAA,MACjC,IAAI,WAAW,aAAa,OAAO,SAAS,GAAG;AAAA,QAC7C,MAAM,OAAO,SAAS,OAAO,OAAO,MAAM,GAAG,MAAM;AAAA,QACnD,IAAI,SAAS,MAAM;AAAA,UACjB,MAAM,IAAI,YAAW;AAAA,YACnB,MAAM;AAAA,YACN,SAAS,YAAY,wCAAwC,KAAK;AAAA,YAClE,SACE;AAAA,YACF,aAAa;AAAA,cACX;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MAEA,WAAW,UAAU,OAAO,OAAO,MAAM,GAAG;AAAA,QAC1C,IAAI,OAAO,SAAS,SAAS;AAAA,UAC3B;AAAA,QACF;AAAA,QACA,WAAW,YAAY,OAAO,KAAK,OAAO,OAAO,GAAG;AAAA,UAClD,MAAM,UAAU,YAAW,QAAQ;AAAA,UACnC,IAAI,CAAC,kBAAiB,OAAO,KAAK,gBAAgB,IAAI,OAAO,GAAG;AAAA,YAC9D;AAAA,UACF;AAAA,UACA,MAAM,IAAI,YAAW;AAAA,YACnB,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS;AAAA,YACT,SACE;AAAA,YACF,aAAa;AAAA,cACX;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA,IAGF,eAAe,CAAC,QAAQ;AAAA,MACtB,sBAAqB,QAAQ;AAAA,QAC3B,cAAc,YAAY,MAAM,YAAY;AAAA,QAE5C,aAAa;AAAA,aACP,QAAQ,UAAU,WAAW,YAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,SAAS,OAAO;AAAA,UACpF,KAAK,QAAQ;AAAA,QACf;AAAA,WAEI,UAAU,WAAW,IACrB,CAAC,IACD,EAAE,WAAW,IAAI,OAAO,MAAM,OAAO,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,IAAI,KAAK,QAAQ;AAAA,MAChG,CAAC;AAAA;AAAA,SAGG,gBAAe,CAAC,SAAS;AAAA,MAC7B,IAAI,kBAAiB,QAAQ,IAAI,GAAG;AAAA,QAClC,iBAAiB;AAAA,QACjB,QAAQ,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,MAEA,IAAI,QAAQ,KAAK,WAAW,MAAM,KAAK,WAAW,MAAM,GAAG;AAAA,QACzD,IAAI;AAAA,UACF,YAAY,cAAc,MAAM;AAAA,UAChC,WAAW,SAAS,WAAW;AAAA,YAC7B,uBAAuB,aAAa,MAAM,MAAM,MAAM,GAAG,MAAM,IAAI;AAAA,UACrE;AAAA,UACA,iBAAiB,mBAAmB,MAAM;AAAA,UAC1C,WAAW,cAAc,gBAAgB;AAAA,YACvC,wBAAwB,aAAa,WAAW,MAAM,MAAM,GAAG,WAAW,IAAI;AAAA,UAChF;AAAA,UACA,OAAO,OAAO;AAAA,UACd,QAAQ,OAAO,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC;AAAA,UAChD;AAAA;AAAA,QAEF,yBAAyB,QAAQ,MAAM;AAAA,QACvC,QAAQ,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA,QAC9C;AAAA,MACF;AAAA,MAEA,IAAI,CAAC,QAAQ,KAAK,WAAW,SAAS,GAAG;AAAA,QACvC;AAAA,MACF;AAAA,MAEA,IAAI;AAAA,QACF,SAAS,WAAW,SAAS;AAAA,QAC7B,WAAW,cAAc,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,YAAY,GAAG;AAAA,UAC9E,wBAAwB,aAAa,WAAW,MAAM,MAAM,GAAG,WAAW,IAAI;AAAA,QAChF;AAAA,QACA,MAAM,cAAc;AAAA,UAClB;AAAA,UACA,YAAY;AAAA,UACZ,QAAQ,YAAY,MAAM,QAAQ;AAAA,QACpC,CAAC;AAAA,QACD,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO,OAAO,OAAO,MAAM,OAAO,KAAK,CAAC;AAAA,QAChD;AAAA;AAAA,MAGF,yBAAyB,QAAQ,MAAM;AAAA,MACvC,QAAQ,OAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AAAA;AAAA,EAElD;AAAA;AAGF,SAAS,kBAAkB,CAAC,MAAc,gBAAgC;AAAA,EACxE,OAAO;AAAA,IACL;AAAA,IACA,mBAAmB,KAAK,UAAU,cAAc,MAAM,cAAc,CAAC;AAAA,IACrE;AAAA,IACA,8CAA8C,KAAK,UAAU,cAAc;AAAA,IAC3E;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA;AAGb,SAAS,oBAAoB,CAAC,WAAmB,cAAgC;AAAA,EAC/E,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,aAAa,IAAI,CAAC,cAAc,UAAU,KAAK,UAAU,SAAS,IAAI;AAAA,IACzE;AAAA,IACA;AAAA,IACA;AAAA,IACA,8HAA8H,KAAK,UAAU,SAAS;AAAA,IACtJ;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA;AAGb,SAAS,sBAAsB,CAC7B,WACA,cACA,QACQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,aAAa,IAAI,CAAC,cAAc,UAAU,KAAK,UAAU,SAAS,IAAI;AAAA,IACzE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,KAAK,UAAU,SAAS;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,qCAAqC,WAAW,YAAY,KAAK,aAAa,KAAK,UAAU,MAAM;AAAA,IACnG;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA;AASb,SAAS,oBAAoB,CAC3B,WACA,aACA,QACQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,KAAK,UAAU,SAAS;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,KAAK,UAAU,SAAS;AAAA,IACxC;AAAA,IACA;AAAA,IACA,gBAAgB,KAAK,UAAU,YAAY,aAAa,aAAa,CAAC;AAAA,IACtE,GAAI,WAAW,YAAY,CAAC,IAAI,CAAC,aAAa,KAAK,UAAU,MAAM,IAAI;AAAA,IACvE;AAAA,IACA;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA;AAGb,SAAS,eAAe,CAAC,SAA0B;AAAA,EACjD,MAAM,cAAe,SAA6D;AAAA,EAClF,OAAO,aAAa,QAAQ;AAAA;AAG9B,SAAS,wBAAwB,CAAC,QAA6B;AAAA,EAC7D,MAAM,SAA4B,CAAC,OAAO,WAAyC;AAAA,EACnF,MAAM,eAAgB,OACnB;AAAA,EACH,IAAI,iBAAiB,WAAW;AAAA,IAC9B,WAAW,eAAe,OAAO,OAAO,YAAY,GAAG;AAAA,MACrD,IAAI,YAAY,gBAAgB,WAAW;AAAA,QACzC,OAAO,KAAK,YAAY,WAA8B;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAW,SAAS,QAAQ;AAAA,IAC1B,WAAW,QAAQ,OAAO,OAAO,eAAe,GAAG;AAAA,MACjD,WAAW,UAAU,MAAM,iBAAiB,OAAK,MAAM,KAAK,CAAC,GAAG;AAAA,QAC9D,MAAM,iBAAiB,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA;",
|
|
10
|
+
"debugId": "858C3A2CF24FAEB764756E2164756E21",
|
|
11
11
|
"names": []
|
|
12
12
|
}
|
package/dist/server/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
toWebRequest2,
|
|
9
9
|
sendNodeResponse2,
|
|
10
10
|
installDevMiddleware2
|
|
11
|
-
} from "../index-
|
|
11
|
+
} from "../index-qz9sc74p.js";
|
|
12
12
|
|
|
13
13
|
// src/server/handler.ts
|
|
14
14
|
import {
|
|
@@ -103,7 +103,7 @@ function createRequestHandler(options) {
|
|
|
103
103
|
code: "E_API_HANDLER_INVALID",
|
|
104
104
|
file: route.file,
|
|
105
105
|
message: "modul API tidak mengekspor objek handler",
|
|
106
|
-
details: `Modul \`${route.path}\` harus mengekspor handler method
|
|
106
|
+
details: `Modul \`${route.path}\` harus mengekspor handler method.`,
|
|
107
107
|
suggestions: ["Export `GET`/`POST`/… sebagai fungsi `(args) => Response`"]
|
|
108
108
|
}), route);
|
|
109
109
|
}
|
|
@@ -132,7 +132,7 @@ function createRequestHandler(options) {
|
|
|
132
132
|
code: "E_API_HANDLER_INVALID",
|
|
133
133
|
file: route.file,
|
|
134
134
|
message: `handler \`${requestMethod}\` tidak mengembalikan \`Response\``,
|
|
135
|
-
details: "Handler API wajib mengembalikan `new Response(...)
|
|
135
|
+
details: "Handler API wajib mengembalikan `new Response(...)`.",
|
|
136
136
|
suggestions: ["Kembalikan `new Response(body, { status, headers })`"]
|
|
137
137
|
}), route);
|
|
138
138
|
}
|
|
@@ -204,7 +204,7 @@ function createRequestHandler(options) {
|
|
|
204
204
|
code: "E_MIDDLEWARE_INVALID",
|
|
205
205
|
file: definition.file,
|
|
206
206
|
message: "`_middleware.ts` tidak meng-export default fungsi",
|
|
207
|
-
details: "Middleware direktori mengikuti bentuk `(args) => Promise<Response
|
|
207
|
+
details: "Middleware direktori mengikuti bentuk `(args) => Promise<Response>`.",
|
|
208
208
|
suggestions: ["Export default `async ({ req, ctx, next }) => await next()`"]
|
|
209
209
|
});
|
|
210
210
|
}
|
|
@@ -231,7 +231,7 @@ function createRequestHandler(options) {
|
|
|
231
231
|
code: "E_MIDDLEWARE_INVALID",
|
|
232
232
|
file: definition.file,
|
|
233
233
|
message: "`_middleware.ts` tidak meng-export default fungsi",
|
|
234
|
-
details: "Middleware direktori mengikuti bentuk `(args) => Promise<Response
|
|
234
|
+
details: "Middleware direktori mengikuti bentuk `(args) => Promise<Response>`.",
|
|
235
235
|
suggestions: ["Export default `async ({ req, ctx, next }) => await next()`"]
|
|
236
236
|
});
|
|
237
237
|
}
|
|
@@ -350,7 +350,7 @@ async function runRouteMeta(pageModule, pageData, file) {
|
|
|
350
350
|
code: "E_INTERNAL",
|
|
351
351
|
file,
|
|
352
352
|
message: "export `meta` harus berupa fungsi `({ data }) => RouteMeta`",
|
|
353
|
-
details: "Bentuk `meta` mengikuti
|
|
353
|
+
details: "Bentuk `meta` mengikuti ",
|
|
354
354
|
suggestions: [
|
|
355
355
|
'Ubah menjadi `export const meta = ({ data }) => ({ title: "..." })`',
|
|
356
356
|
"Atau hapus export `meta`"
|
|
@@ -363,7 +363,7 @@ async function runRouteMeta(pageModule, pageData, file) {
|
|
|
363
363
|
code: "E_INTERNAL",
|
|
364
364
|
file,
|
|
365
365
|
message: "`meta()` harus mengembalikan objek RouteMeta",
|
|
366
|
-
details: "Nilai yang dikembalikan dipakai untuk <title>/description/og
|
|
366
|
+
details: "Nilai yang dikembalikan dipakai untuk <title>/description/og.",
|
|
367
367
|
suggestions: ['Kembalikan objek, mis. `({ title: "Halaman" })`']
|
|
368
368
|
});
|
|
369
369
|
}
|
|
@@ -423,7 +423,7 @@ function warnPayloadFindings(payload, scan, warned) {
|
|
|
423
423
|
continue;
|
|
424
424
|
}
|
|
425
425
|
warned.add(label);
|
|
426
|
-
console.warn(`[moons] peringatan dev: payload SSR memuat ${label} — jangan mengembalikan rahasia dari loader
|
|
426
|
+
console.warn(`[moons] peringatan dev: payload SSR memuat ${label} — jangan mengembalikan rahasia dari loader.`);
|
|
427
427
|
}
|
|
428
428
|
}
|
|
429
429
|
// src/server/node-server.ts
|
|
@@ -431,6 +431,53 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
431
431
|
import { createServer } from "node:http";
|
|
432
432
|
import { extname, join, resolve, sep } from "node:path";
|
|
433
433
|
|
|
434
|
+
// src/server/isr.ts
|
|
435
|
+
import { renameSync, writeFileSync } from "node:fs";
|
|
436
|
+
function shouldRevalidate(input) {
|
|
437
|
+
const now = input.now ?? Date.now();
|
|
438
|
+
return now - input.mtimeMs >= input.revalidateSeconds * 1000;
|
|
439
|
+
}
|
|
440
|
+
var inflight = new Map;
|
|
441
|
+
function revalidatePrerendered(options) {
|
|
442
|
+
const existing = inflight.get(options.pathname);
|
|
443
|
+
if (existing !== undefined) {
|
|
444
|
+
return existing;
|
|
445
|
+
}
|
|
446
|
+
const task = runRevalidate(options).finally(() => {
|
|
447
|
+
inflight.delete(options.pathname);
|
|
448
|
+
});
|
|
449
|
+
inflight.set(options.pathname, task);
|
|
450
|
+
return task;
|
|
451
|
+
}
|
|
452
|
+
async function runRevalidate(options) {
|
|
453
|
+
const log = options.log ?? ((message) => console.log(message));
|
|
454
|
+
try {
|
|
455
|
+
const response = await options.handler(new Request(`http://localhost${options.pathname}`, {
|
|
456
|
+
method: "GET",
|
|
457
|
+
headers: { "x-moons-prerender": "1" }
|
|
458
|
+
}));
|
|
459
|
+
if (response.status !== 200) {
|
|
460
|
+
log(`[moons] isr: lewati ${options.pathname} (status ${response.status})`);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const html = await response.text();
|
|
464
|
+
const findings = scanPayloadForSecrets(html, {
|
|
465
|
+
...options.canary === undefined ? {} : { canary: options.canary },
|
|
466
|
+
env: options.env ?? process.env
|
|
467
|
+
});
|
|
468
|
+
if (findings.length > 0) {
|
|
469
|
+
const labels = findings.map((finding) => finding.kind === "canary" ? "canary" : `env(${finding.label})`).join(", ");
|
|
470
|
+
log(`[moons] isr: TIDAK menulis ${options.pathname} — memuat ${labels}`);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const tmp = `${options.file}.tmp-${process.pid}`;
|
|
474
|
+
writeFileSync(tmp, html);
|
|
475
|
+
renameSync(tmp, options.file);
|
|
476
|
+
} catch (error) {
|
|
477
|
+
log(`[moons] isr: gagal regenerasi ${options.pathname}: ${String(error)}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
434
481
|
// src/server/shutdown.ts
|
|
435
482
|
function installGracefulShutdown(server, options = {}) {
|
|
436
483
|
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
@@ -509,6 +556,7 @@ function startNodeServer(handler, options = {}) {
|
|
|
509
556
|
if (req.method === "GET" || req.method === "HEAD") {
|
|
510
557
|
const staticFile = resolveStaticFile(clientDir, url.pathname);
|
|
511
558
|
if (staticFile !== null) {
|
|
559
|
+
scheduleRevalidation(staticFile, url.pathname, handler, options, clientDir);
|
|
512
560
|
const body = readFileSync(staticFile);
|
|
513
561
|
res.statusCode = 200;
|
|
514
562
|
res.setHeader("content-type", MIME_TYPES[extname(staticFile).toLowerCase()] ?? "application/octet-stream");
|
|
@@ -562,7 +610,7 @@ function resolveStaticFile(clientDir, pathname) {
|
|
|
562
610
|
}
|
|
563
611
|
const normalized = decoded.length > 1 ? decoded.replace(/\/+$/, "") : decoded;
|
|
564
612
|
const manifest = readPrerenderManifest(clientDir);
|
|
565
|
-
if (manifest.has(normalized)) {
|
|
613
|
+
if (manifest.paths.has(normalized)) {
|
|
566
614
|
const target = normalized === "/" ? "index.html" : `${normalized.slice(1)}/index.html`;
|
|
567
615
|
const candidate = safeWithin(clientDir, `./${target}`);
|
|
568
616
|
if (candidate !== null && isFile(candidate)) {
|
|
@@ -584,19 +632,64 @@ function isFile(path) {
|
|
|
584
632
|
var prerenderManifestCache = null;
|
|
585
633
|
function readPrerenderManifest(clientDir) {
|
|
586
634
|
const file = join(clientDir, "_moons_prerender.json");
|
|
635
|
+
const empty = { paths: new Set, revalidate: new Map };
|
|
587
636
|
try {
|
|
588
637
|
const mtimeMs = statSync(file).mtimeMs;
|
|
589
638
|
if (prerenderManifestCache !== null && prerenderManifestCache.file === file && prerenderManifestCache.mtimeMs === mtimeMs) {
|
|
590
|
-
return prerenderManifestCache.
|
|
639
|
+
return prerenderManifestCache.info;
|
|
591
640
|
}
|
|
592
641
|
const json = JSON.parse(readFileSync(file, "utf8"));
|
|
593
|
-
const paths = new Set
|
|
594
|
-
|
|
595
|
-
|
|
642
|
+
const paths = new Set;
|
|
643
|
+
const revalidate = new Map;
|
|
644
|
+
if (Array.isArray(json.paths)) {
|
|
645
|
+
for (const path of json.paths) {
|
|
646
|
+
if (typeof path === "string") {
|
|
647
|
+
paths.add(path);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (Array.isArray(json.entries)) {
|
|
652
|
+
for (const entry of json.entries) {
|
|
653
|
+
if (entry === null || typeof entry !== "object" || typeof entry["path"] !== "string") {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
const path = entry["path"];
|
|
657
|
+
paths.add(path);
|
|
658
|
+
const seconds = entry["revalidate"];
|
|
659
|
+
if (typeof seconds === "number" && Number.isFinite(seconds) && seconds >= 0) {
|
|
660
|
+
revalidate.set(path, seconds);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const info = { paths, revalidate };
|
|
665
|
+
prerenderManifestCache = { file, mtimeMs, info };
|
|
666
|
+
return info;
|
|
596
667
|
} catch {
|
|
597
|
-
return
|
|
668
|
+
return empty;
|
|
598
669
|
}
|
|
599
670
|
}
|
|
671
|
+
function scheduleRevalidation(staticFile, pathname, handler, options, clientDir) {
|
|
672
|
+
const normalized = pathname.length > 1 ? pathname.replace(/\/+$/, "") : pathname;
|
|
673
|
+
const seconds = readPrerenderManifest(clientDir).revalidate.get(normalized);
|
|
674
|
+
if (seconds === undefined || seconds < 0) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
let mtimeMs;
|
|
678
|
+
try {
|
|
679
|
+
mtimeMs = statSync(staticFile).mtimeMs;
|
|
680
|
+
} catch {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (!shouldRevalidate({ mtimeMs, revalidateSeconds: seconds })) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
revalidatePrerendered({
|
|
687
|
+
pathname: normalized,
|
|
688
|
+
file: staticFile,
|
|
689
|
+
handler,
|
|
690
|
+
...options.canary === undefined ? {} : { canary: options.canary }
|
|
691
|
+
});
|
|
692
|
+
}
|
|
600
693
|
// src/server/test-server.ts
|
|
601
694
|
function createTestServer(options, baseUrl = "http://localhost") {
|
|
602
695
|
const shell = options.shell ?? ((markup, payload, _url, meta) => injectShell2(DEFAULT_TEMPLATE2, markup, payload, meta));
|
|
@@ -670,7 +763,7 @@ function createPluginRuntime(options) {
|
|
|
670
763
|
}
|
|
671
764
|
// src/server/prerender.ts
|
|
672
765
|
import { MoonsError as MoonsError2 } from "@moonsjs/core";
|
|
673
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
766
|
+
import { mkdirSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
674
767
|
import { dirname, join as join2, resolve as resolve2, sep as sep2 } from "node:path";
|
|
675
768
|
var PRERENDER_MANIFEST_FILE = "_moons_prerender.json";
|
|
676
769
|
async function runPrerender(options) {
|
|
@@ -678,7 +771,7 @@ async function runPrerender(options) {
|
|
|
678
771
|
const env = options.env ?? process.env;
|
|
679
772
|
let written = 0;
|
|
680
773
|
let skipped = 0;
|
|
681
|
-
const
|
|
774
|
+
const entries = [];
|
|
682
775
|
const pages = options.routes.filter((route) => route.kind === "page");
|
|
683
776
|
for (const route of pages) {
|
|
684
777
|
const key = routeKeyOf(options.routesDir, route.file);
|
|
@@ -688,6 +781,21 @@ async function runPrerender(options) {
|
|
|
688
781
|
}
|
|
689
782
|
const module = await load();
|
|
690
783
|
const prerender = module.prerender;
|
|
784
|
+
const revalidate = module.revalidate;
|
|
785
|
+
if (revalidate !== undefined) {
|
|
786
|
+
if (typeof revalidate !== "number" || !Number.isFinite(revalidate) || revalidate < 0 || prerender !== true) {
|
|
787
|
+
throw new MoonsError2({
|
|
788
|
+
code: "E_ISR_INVALID",
|
|
789
|
+
file: route.file,
|
|
790
|
+
message: "`revalidate` tidak valid atau dipakai tanpa `prerender = true`",
|
|
791
|
+
details: "ISR berbasis file: `revalidate` (detik, number >= 0) + `prerender`.",
|
|
792
|
+
suggestions: [
|
|
793
|
+
"Gunakan angka detik, mis. `export const revalidate = 60`",
|
|
794
|
+
"Tambahkan `export const prerender = true` pada page yang sama"
|
|
795
|
+
]
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
}
|
|
691
799
|
if (prerender !== true) {
|
|
692
800
|
if (prerender !== undefined && prerender !== false) {
|
|
693
801
|
throw prerenderError(route, "`prerender` harus boolean (`true`/`false`)");
|
|
@@ -722,7 +830,7 @@ async function runPrerender(options) {
|
|
|
722
830
|
code: "E_PRERENDER_LEAK",
|
|
723
831
|
file: route.file,
|
|
724
832
|
message: `hasil prerender \`${pathname}\` memuat ${labels}`,
|
|
725
|
-
details: "HTML statis permanen — rahasia yang ter-prerender tidak bisa ditarik kembali
|
|
833
|
+
details: "HTML statis permanen — rahasia yang ter-prerender tidak bisa ditarik kembali.",
|
|
726
834
|
suggestions: [
|
|
727
835
|
"Jangan mengembalikan nilai env rahasia dari loader yang di-prerender",
|
|
728
836
|
"Matikan `prerender` untuk route ini atau pindahkan datanya ke serverFn request-time"
|
|
@@ -731,12 +839,12 @@ async function runPrerender(options) {
|
|
|
731
839
|
}
|
|
732
840
|
const file = outputFile(options.clientDir, pathname);
|
|
733
841
|
mkdirSync(dirname(file), { recursive: true });
|
|
734
|
-
|
|
735
|
-
|
|
842
|
+
writeFileSync2(file, html);
|
|
843
|
+
entries.push(typeof revalidate === "number" && revalidate >= 0 ? { path: pathname, revalidate } : { path: pathname });
|
|
736
844
|
written += 1;
|
|
737
845
|
}
|
|
738
846
|
}
|
|
739
|
-
|
|
847
|
+
writeFileSync2(join2(options.clientDir, PRERENDER_MANIFEST_FILE), `${JSON.stringify({ version: 2, entries }, null, 2)}
|
|
740
848
|
`);
|
|
741
849
|
log(`[moons] prerender selesai: ${written} file (${skipped} dilewati)`);
|
|
742
850
|
return { written, skipped };
|
|
@@ -756,7 +864,7 @@ async function resolvePathnames(route, module) {
|
|
|
756
864
|
code: "E_PRERENDER_NO_PATHS",
|
|
757
865
|
file: route.file,
|
|
758
866
|
message: "route dynamic ber-`prerender = true` tanpa `export const paths`",
|
|
759
|
-
details: "Prerender butuh daftar param untuk merender tiap path
|
|
867
|
+
details: "Prerender butuh daftar param untuk merender tiap path.",
|
|
760
868
|
suggestions: [
|
|
761
869
|
'Tambahkan `export const paths = () => [{ id: "…" }]`',
|
|
762
870
|
"Atau hapus `prerender` agar dirender SSR saat request"
|
|
@@ -839,7 +947,7 @@ function prerenderError(route, message) {
|
|
|
839
947
|
code: "E_PRERENDER_INVALID",
|
|
840
948
|
file: route.file,
|
|
841
949
|
message,
|
|
842
|
-
details: "Kontrak prerender mengikuti
|
|
950
|
+
details: "Kontrak prerender mengikuti.",
|
|
843
951
|
suggestions: [
|
|
844
952
|
"Perbaiki bentuk `paths`/param agar cocok dengan pola route",
|
|
845
953
|
"Jangan memakai `redirect()` pada route yang di-prerender"
|
|
@@ -864,4 +972,4 @@ export {
|
|
|
864
972
|
toWebRequest2 as toWebRequest
|
|
865
973
|
};
|
|
866
974
|
|
|
867
|
-
//# debugId=
|
|
975
|
+
//# debugId=CC962AE44069459E64756E2164756E21
|