@moonsjs/vite 0.1.17 → 0.2.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/dist/{index-v5sbd3az.js → index-0agjty3z.js} +21 -18
- package/dist/index-0agjty3z.js.map +15 -0
- package/dist/index-f8w073cm.js +30 -0
- package/dist/index-f8w073cm.js.map +10 -0
- package/dist/{index-snbxks72.js → index-tbph0859.js} +80 -80
- package/dist/{index-snbxks72.js.map → index-tbph0859.js.map} +4 -4
- package/dist/index.js +33 -33
- package/dist/index.js.map +4 -4
- package/dist/server/handler.d.ts.map +1 -1
- package/dist/server/index.js +104 -93
- package/dist/server/index.js.map +10 -10
- package/dist/server/test-server.d.ts +6 -0
- package/dist/server/test-server.d.ts.map +1 -1
- package/dist/testing-preload.d.ts +2 -0
- package/dist/testing-preload.d.ts.map +1 -0
- package/dist/testing-preload.js +10 -0
- package/dist/testing-preload.js.map +10 -0
- package/dist/testing.d.ts +11 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +13 -0
- package/dist/testing.js.map +9 -0
- package/dist/transform.js +1 -1
- package/package.json +15 -5
- package/src/api.ts +14 -14
- package/src/devtools.ts +5 -5
- package/src/manifest.ts +2 -2
- package/src/plugin.ts +21 -21
- package/src/server/dev.ts +6 -1
- package/src/server/handler.ts +69 -47
- package/src/server/isr.ts +5 -5
- package/src/server/node-server.ts +6 -6
- package/src/server/node.ts +2 -2
- package/src/server/plugins.ts +1 -1
- package/src/server/prerender.ts +29 -29
- package/src/server/shell.ts +8 -8
- package/src/server/shutdown.ts +5 -5
- package/src/server/storage.ts +1 -1
- package/src/server/test-server.ts +12 -1
- package/src/server-only.ts +7 -7
- package/src/testing-preload.ts +5 -0
- package/src/testing.ts +34 -0
- package/src/transform.ts +76 -76
- package/dist/index-v5sbd3az.js.map +0 -15
package/dist/server/index.js.map
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/server/handler.ts", "../src/payload-scan.ts", "../src/server/node-server.ts", "../src/server/isr.ts", "../src/server/storage.ts", "../src/server/logger.ts", "../src/server/shutdown.ts", "../src/server/test-server.ts", "../src/server/plugins.ts", "../src/server/prerender.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import {\n MoonsError,\n composeMiddleware,\n findApiDirMiddlewares,\n findDirMiddlewares,\n findErrorBoundary,\n isNotFoundSignal,\n isRedirectSignal,\n resolveRoute,\n routeKeyFromFile,\n runLoaders,\n type ApiMethod,\n type ApiMiddlewareDefinition,\n type ApiRouteDefinition,\n type Middleware,\n type MoonsConfig,\n type ResolvedRoute,\n type RouteDefinition,\n type RouteModule,\n trailingSlashRedirect,\n} from \"@moonsjs/core\";\nimport { encodeSsrPayload, reviveError, serializeError } from \"@moonsjs/core/serialize\";\nimport { API_METHODS, resolveApiRoute } from \"@moonsjs/core\";\nimport { renderToMarkup } from \"@moonsjs/react/ssr\";\nimport type { ClientRouteEntry, RouteModuleShape } from \"@moonsjs/react/internal\";\nimport { createRpcHandler, runWithContext, runWithRequestCache, runWithResponseCollector, takeResponseMutations } from \"@moonsjs/server\";\nimport { NOT_FOUND_ROUTE_KEY } from \"../manifest\";\nimport { scanPayloadForSecrets, type PayloadScanOptions } from \"../payload-scan\";\nimport type { Shell } from \"./shell\";\n\nconst RPC_PREFIX = \"/_moons/fn/\";\nconst HEALTH_PATH = \"/_moons/health\";\n\nexport interface RequestHandlerOptions {\n routes: RouteDefinition[];\n /** Config yang sudah divalidasi. */\n config: MoonsConfig;\n /** Direktori route absolut; dipakai untuk derivasi key stabil. */\n routesDir: string;\n /** Peta import() modul route, key = routeKeyFromFile. */\n loadRoute: Record<string, () => Promise<RouteModule>>;\n shell: Shell;\n /**\n * Dipanggil setelah `config.context` per request (Addendum B.4: extender\n * `extendContext` plugin di-merge ke ctx).\n */\n onContext?: (ctx: Ctx) => void;\n /**\n * A1: pemindaian payload SSR (dev) — peringatan sekali per label bila payload\n * memuat canary/nilai env mirip-rahasia. Production TIDAK mengisi opsi ini\n * (tanpa biaya runtime). Lihat `payload-scan.ts`.\n */\n payloadScan?: PayloadScanOptions;\n /** Endpoint API `src/api` (Addendum D.1) — hasil scan plugin. */\n apiRoutes?: ApiRouteDefinition[];\n /** Peta import() modul API, key = route.path. */\n loadApi?: Record<string, () => Promise<unknown>>;\n /** Middleware direktori pohon `src/api` (Addendum D.3). */\n apiMiddlewares?: ApiMiddlewareDefinition[];\n /** Peta import() `_middleware.ts` pohon api, key = file path. */\n loadApiMiddleware?: Record<string, () => Promise<unknown>>;\n}\n\n/**\n * Handler HTML: context → middleware global → resolve route → loader paralel\n * → render React → inject payload devalue (PRD §11.2, §14.2, §17).\n */\nexport function createRequestHandler(\n options: RequestHandlerOptions,\n): (request: Request) => Promise<Response> { const { routes, config, routesDir, loadRoute, shell } = options;\n const rpc = createRpcHandler(\n config.security === undefined ? {} : { security: config.security },\n );\n const notFoundRoute = routes.find((route) => route.kind === \"404\");\n const errorRoute = routes.find((route) => route.kind === \"error\");\n /** A1: dedupe peringatan payload (sekali per label). */\n const warnedPayloadLabels = new Set<string>();\n\n async function renderRoute(\n resolved: ResolvedRoute,\n request: Request,\n ctx: Ctx,\n ): Promise<Response> {\n const entries = [...resolved.layouts, resolved.route];\n const keys = entries.map((entry) => routeKeyFromFile(routesDir, entry.file));\n const modules = await loadModules(keys, loadRoute);\n\n const data = await runLoaders(\n entries.map((entry, index) => ({ file: keys[index] as string, module: modules[index] as RouteModule })),\n { params: resolved.params, ctx, req: request },\n );\n\n const pageKey = routeKeyFromFile(routesDir, resolved.route.file);\n const pageModule = modules[modules.length - 1] as RouteModule;\n const entry: ClientRouteEntry = { page: pageKey, layouts: keys.slice(0, -1) };\n // Addendum A.3: query string ikut ke payload agar server/client identik.\n const searchParams = Object.fromEntries(new URL(request.url).searchParams);\n // Addendum B.1: eksekusi `meta()` page (data = hasil loader page itu sendiri).\n const meta = await runRouteMeta(pageModule, data[pageKey], resolved.route.file);\n\n const markup = renderToMarkup(\n entry,\n { page: pageModule as RouteModuleShape, layouts: modules.slice(0, -1) as RouteModuleShape[] },\n resolved.params,\n data,\n searchParams,\n );\n const payload = encodeSsrPayload({\n key: pageKey,\n params: resolved.params,\n searchParams,\n data,\n ...(meta === undefined ? {} : { meta }),\n });\n\n // A1: pindai payload SSR (dev saja — `payloadScan` tidak diisi production).\n warnPayloadFindings(payload, options.payloadScan, warnedPayloadLabels);\n\n return htmlResponse(await shell(markup, payload, request.url, meta), 200);\n }\n\n /** Addendum D.1: dispatch endpoint `src/api` (405/HEAD/OPTIONS + error). */\n async function handleApiRequest(\n route: ApiRouteDefinition,\n params: Record<string, string>,\n request: Request,\n ctx: Ctx,\n ): Promise<Response> {\n const load = options.loadApi?.[route.path];\n if (load === undefined) {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: `modul API \\`${route.path}\\` tidak bisa dimuat`,\n details: \"Peta `loadApi` tidak memuat route ini (build/dev tidak sinkron).\",\n suggestions: [\"Jalankan ulang build / restart dev server\"],\n }),\n route,\n );\n }\n\n let mod: unknown;\n try {\n mod = await load();\n } catch (error) {\n return apiErrorResponse(error, route);\n }\n if (mod === null || typeof mod !== \"object\") {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: \"modul API tidak mengekspor objek handler\",\n details: `Modul \\`${route.path}\\` harus mengekspor handler method.`,\n suggestions: [\"Export `GET`/`POST`/… sebagai fungsi `(args) => Response`\"],\n }),\n route,\n );\n }\n\n const record = mod as Record<string, unknown>;\n const methods: ApiMethod[] = API_METHODS.filter(\n (method) => typeof record[method] === \"function\",\n );\n const requestMethod = request.method.toUpperCase();\n type ApiHandlerFn = (args: {\n req: Request;\n params: Record<string, string>;\n ctx: Ctx;\n }) => Response | Promise<Response>;\n let handler = record[requestMethod] as ApiHandlerFn | undefined;\n let stripBody = false;\n\n // D.7 #2: HEAD otomatis dari GET; OPTIONS otomatis → 204 + Allow.\n if (typeof handler !== \"function\" && requestMethod === \"HEAD\" && typeof record[\"GET\"] === \"function\") {\n handler = record[\"GET\"] as ApiHandlerFn;\n stripBody = true;\n }\n if (typeof handler !== \"function\") {\n if (requestMethod === \"OPTIONS\") {\n return new Response(null, { status: 204, headers: { allow: methods.join(\", \") } });\n }\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: { allow: methods.join(\", \") },\n });\n }\n\n try {\n const result = await handler({ req: request, params, ctx });\n if (!(result instanceof Response)) {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: `handler \\`${requestMethod}\\` tidak mengembalikan \\`Response\\``,\n details: \"Handler API wajib mengembalikan `new Response(...)`.\",\n suggestions: [\"Kembalikan `new Response(body, { status, headers })`\"],\n }),\n route,\n );\n }\n if (stripBody) {\n return new Response(null, { status: result.status, headers: result.headers });\n }\n return result;\n } catch (error) {\n return apiErrorResponse(error, route);\n }\n }\n\n /** §11.2: halaman `_404.tsx` kustom (standalone), fallback bawaan. */\n async function notFoundResponse(request: Request): Promise<Response> {\n if (notFoundRoute !== undefined) {\n try {\n const key = routeKeyFromFile(routesDir, notFoundRoute.file);\n const [module] = await loadModules([key], loadRoute);\n const payload = encodeSsrPayload({ key: NOT_FOUND_ROUTE_KEY, params: {}, data: {} });\n const markup = renderToMarkup(\n { page: key, layouts: [] },\n { page: module as RouteModuleShape, layouts: [] },\n {},\n {},\n );\n return htmlResponse(await shell(markup, payload, request.url), 404);\n } catch (error) {\n console.error(\"[moons] gagal merender _404 kustom:\", error);\n }\n }\n\n const payload = encodeSsrPayload({ key: \"\", params: {}, data: {} });\n const html = await shell(\n \"<h1>404</h1><p>Halaman tidak ditemukan.</p>\",\n payload,\n request.url,\n );\n return htmlResponse(html, 404);\n }\n\n /**\n * §11.2/D.3: `_error.tsx` kustom (boundary terdekat dari route; fallback\n * root). Production tidak men-serialisasi error apa pun (§16.6).\n */\n async function routeErrorResponse(\n error: unknown,\n request: Request,\n resolved?: ResolvedRoute,\n ): Promise<Response> {\n console.error(\"[moons] route error:\", error);\n\n const boundary =\n (resolved === undefined ? null : findErrorBoundary(resolved.route, routes)) ??\n errorRoute ??\n null;\n if (boundary !== null) {\n try {\n const key = routeKeyFromFile(routesDir, boundary.file);\n const [module] = await loadModules([key], loadRoute);\n const isProduction = process.env[\"NODE_ENV\"] === \"production\";\n const serialized = isProduction ? undefined : serializeError(error);\n const payload = encodeSsrPayload({\n key,\n params: {},\n data: {},\n ...(serialized === undefined ? {} : { error: serialized }),\n });\n const markup = renderToMarkup(\n { page: key, layouts: [] },\n { page: module as RouteModuleShape, layouts: [] },\n {},\n {},\n {},\n serialized === undefined ? undefined : reviveError(serialized),\n );\n return htmlResponse(await shell(markup, payload, request.url), 500);\n } catch (renderError) {\n console.error(\"[moons] gagal merender _error kustom:\", renderError);\n }\n }\n\n return internalErrorResponse(error, { log: false });\n }\n\n /** Muat middleware direktori (D.3) → `Middleware[]`; error bentuk jelas. */\n async function loadDirMiddlewares(chain: ReadonlyArray<RouteDefinition>): Promise<Middleware[]> {\n const result: Middleware[] = [];\n for (const definition of chain) {\n const key = routeKeyFromFile(routesDir, definition.file);\n const load = options.loadRoute?.[key];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"middleware direktori tidak bisa dimuat\",\n details: \"Peta `loadRoute` tidak memuat `_middleware.ts` ini.\",\n suggestions: [\"Restart dev server / jalankan ulang build\"],\n });\n }\n const module = (await load()) as { default?: unknown };\n const handler = module.default;\n if (typeof handler !== \"function\") {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"`_middleware.ts` tidak meng-export default fungsi\",\n details: \"Middleware direktori mengikuti bentuk `(args) => Promise<Response>`.\",\n suggestions: [\"Export default `async ({ req, ctx, next }) => await next()`\"],\n });\n }\n result.push(handler as Middleware);\n }\n return result;\n }\n\n /** Muat middleware pohon `src/api` (D.3). */\n async function loadApiDirMiddlewares(\n chain: ReadonlyArray<ApiMiddlewareDefinition>,\n ): Promise<Middleware[]> {\n const result: Middleware[] = [];\n for (const definition of chain) {\n const load = options.loadApiMiddleware?.[definition.file];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"middleware API tidak bisa dimuat\",\n details: \"Peta `loadApiMiddleware` tidak memuat `_middleware.ts` ini.\",\n suggestions: [\"Restart dev server / jalankan ulang build\"],\n });\n }\n const module = (await load()) as { default?: unknown };\n if (typeof module.default !== \"function\") {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"`_middleware.ts` tidak meng-export default fungsi\",\n details: \"Middleware direktori mengikuti bentuk `(args) => Promise<Response>`.\",\n suggestions: [\"Export default `async ({ req, ctx, next }) => await next()`\"],\n });\n }\n result.push(module.default as Middleware);\n }\n return result;\n }\n\n const handleCore = async function handler(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n\n // §19.5: health ditangani paling awal — tetap hidup walau kode user rusak.\n if (url.pathname === HEALTH_PATH) {\n return healthResponse(request.method);\n }\n\n // `MoonsConfig.context` bertipe `unknown` (menghindari referensi sirkular\n // ke global `Ctx` — §13); kontraknya tetap `Promise<Ctx>`, jadi cast di\n // batas runtime ini. Tanpa cast, tsc app user yang memuat `@moonsjs/vite/server`\n // (mis. `createTestServer` §19.5) melihat `unknown` vs `Ctx` global app.\n const ctx = (await config.context(request)) as Ctx;\n options.onContext?.(ctx);\n // Addendum D.5: tandai request prerender build-time (aditif §13.1).\n if (request.headers.get(\"x-moons-prerender\") === \"1\") {\n (ctx as Record<string, unknown>)[\"__prerender\"] = true;\n }\n\n const respond = composeMiddleware(config.middleware ?? [], ctx, async () => {\n if (url.pathname.startsWith(RPC_PREFIX)) {\n return await rpc(request, url.pathname.slice(RPC_PREFIX.length), ctx);\n }\n // Addendum D.1: endpoint HTTP mentah `src/api` (semua method).\n if (options.apiRoutes !== undefined && options.apiRoutes.length > 0) {\n const apiMatch = resolveApiRoute(url.pathname, options.apiRoutes);\n if (apiMatch !== null) {\n // Addendum D.3: middleware direktori pohon api.\n const apiChain = findApiDirMiddlewares(\n apiMatch.route.file,\n options.apiMiddlewares ?? [],\n );\n if (apiChain.length === 0) {\n return await handleApiRequest(apiMatch.route, apiMatch.params, request, ctx);\n }\n const middlewares = await loadApiDirMiddlewares(apiChain);\n return await composeMiddleware(\n middlewares,\n ctx,\n () => handleApiRequest(apiMatch.route, apiMatch.params, request, ctx),\n { code: \"E_MIDDLEWARE_INVALID\", label: \"middleware API\" },\n )(request);\n }\n }\n const resolved = resolveRoute(url.pathname, routes);\n if (resolved === null) {\n return await notFoundResponse(request);\n }\n try {\n // Addendum D.3: middleware direktori (root→leaf) untuk page.\n const dirChain = findDirMiddlewares(resolved.route, routes);\n if (dirChain.length === 0) {\n return await renderRoute(resolved, request, ctx);\n }\n const middlewares = await loadDirMiddlewares(dirChain);\n return await composeMiddleware(\n middlewares,\n ctx,\n () => renderRoute(resolved, request, ctx),\n { code: \"E_MIDDLEWARE_INVALID\", label: \"middleware direktori\" },\n )(request);\n } catch (error) {\n // Addendum B.2: sinyal routing dari loader/meta.\n if (isRedirectSignal(error)) {\n return new Response(null, {\n status: error.status,\n headers: { location: new URL(error.to, request.url).toString() },\n });\n }\n if (isNotFoundSignal(error)) {\n return await notFoundResponse(request);\n }\n return await routeErrorResponse(error, request, resolved);\n }\n });\n\n // Addendum D.2: kolektor mutasi respons aktif selama request; helper\n // (setHeader/setCookie) menulis ke store, diterapkan ke Response akhir —\n // termasuk jalur error (mutasi yang sudah dipush tetap dihormati).\n return await runWithResponseCollector(async () => {\n let response: Response;\n try {\n response = await runWithRequestCache(() => runWithContext(ctx, () => respond(request)));\n } catch (error) {\n response = internalErrorResponse(error);\n }\n return applyResponseMutations(response);\n });\n } catch (error) {\n return internalErrorResponse(error);\n }\n };\n\n // Addendum H: redirect statis + hook lifecycle + header statis.\n const staticHeaders = Object.entries(config.headers ?? {});\n const redirects = (config.redirects ?? []).map((entry) => ({\n ...entry,\n status: entry.status ?? 301,\n }));\n\n return async function handler(request: Request): Promise<Response> {\n const isPrerender = request.headers.get(\"x-moons-prerender\") === \"1\";\n const applyHeaders = (response: Response): Response => {\n for (const [name, value] of staticHeaders) {\n if (!response.headers.has(name)) {\n response.headers.set(name, value);\n }\n }\n return response;\n };\n\n try {\n // Addendum M: kanonikalisasi trailing slash sebelum routing (308,\n // query dipertahankan; `/_moons/**`, root, dan aset dikecualikan).\n if (!isPrerender && config.trailingSlash !== undefined) {\n const policyUrl = new URL(request.url);\n const canonical = trailingSlashRedirect(policyUrl.pathname, config.trailingSlash);\n if (canonical !== null) {\n policyUrl.pathname = canonical;\n return applyHeaders(\n new Response(null, { status: 308, headers: { location: policyUrl.toString() } }),\n );\n }\n }\n\n if (!isPrerender && redirects.length > 0) {\n const url = new URL(request.url);\n const path = url.pathname.replace(/\\/$/, \"\");\n for (const entry of redirects) {\n if (path === entry.from.replace(/\\/$/, \"\")) {\n const location = entry.to.startsWith(\"http\")\n ? entry.to\n : new URL(entry.to, url.origin).toString();\n return applyHeaders(\n new Response(null, { status: entry.status, headers: { location } }),\n );\n }\n }\n }\n\n await config.hooks?.onRequest?.(request);\n let response = await handleCore(request);\n const replaced = await config.hooks?.onResponse?.(response, request);\n if (replaced instanceof Response) {\n response = replaced;\n }\n return applyHeaders(response);\n } catch (error) {\n try {\n await config.hooks?.onError?.(error, request);\n } catch {\n // Kegagalan hook tidak boleh menutupi error asli.\n }\n return internalErrorResponse(error);\n }\n };\n}\n\n/** Terapkan mutasi `setHeader`/`appendHeader`/`setCookie` ke respons (D.2). */\nfunction applyResponseMutations(response: Response): Response {\n const mutations = takeResponseMutations();\n if (mutations.length === 0) {\n return response;\n }\n const headers = new Headers(response.headers);\n for (const mutation of mutations) {\n if (mutation.kind === \"header\") {\n if (mutation.append) {\n headers.append(mutation.name, mutation.value);\n } else {\n headers.set(mutation.name, mutation.value);\n }\n } else {\n headers.append(\"set-cookie\", mutation.value);\n }\n }\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nasync function loadModules(\n keys: string[],\n loadRoute: Record<string, () => Promise<RouteModule>>,\n): Promise<RouteModule[]> {\n return await Promise.all(\n keys.map(async (key) => {\n const load = loadRoute[key];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n message: `modul route \\`${key}\\` tidak terdaftar`,\n details: \"Registry route tidak sinkron dengan hasil scan.\",\n suggestions: [\"Jalankan ulang `bun run build`, atau restart dev server\"],\n });\n }\n return await load();\n }),\n );\n}\n\nasync function runRouteMeta(\n pageModule: RouteModule,\n pageData: unknown,\n file: string,\n): Promise<Record<string, unknown> | undefined> {\n const meta = (pageModule as { meta?: unknown }).meta;\n if (meta === undefined) {\n return undefined;\n }\n if (typeof meta !== \"function\") {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"export `meta` harus berupa fungsi `({ data }) => RouteMeta`\",\n details: \"Bentuk `meta` mengikuti \",\n suggestions: [\n \"Ubah menjadi `export const meta = ({ data }) => ({ title: \\\"...\\\" })`\",\n \"Atau hapus export `meta`\",\n ],\n });\n }\n const result = await (meta as (args: { data: unknown }) => unknown)({ data: pageData });\n if (result === null || typeof result !== \"object\" || Array.isArray(result)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"`meta()` harus mengembalikan objek RouteMeta\",\n details: \"Nilai yang dikembalikan dipakai untuk <title>/description/og.\",\n suggestions: [\"Kembalikan objek, mis. `({ title: \\\"Halaman\\\" })`\"],\n });\n }\n return result as Record<string, unknown>;\n}\n\n/**\n * Error endpoint API (Addendum D.1): detail hanya di non-production (§16.6).\n */\nfunction apiErrorResponse(error: unknown, route: ApiRouteDefinition): Response {\n const isProduction = process.env[\"NODE_ENV\"] === \"production\";\n if (error instanceof MoonsError) {\n console.error(`[moons] API ${route.path}: ${error.format()}`);\n return new Response(isProduction ? \"Terjadi kesalahan internal.\" : error.format(), {\n status: 500,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n }\n console.error(`[moons] API ${route.path}:`, error);\n return new Response(isProduction ? \"Terjadi kesalahan internal.\" : String(error), {\n status: 500,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n}\n\nfunction internalErrorResponse(error: unknown, options: { log?: boolean } = {}): Response {\n if (options.log !== false) {\n console.error(\"[moons] request error:\", error);\n }\n\n const detail =\n process.env[\"NODE_ENV\"] !== \"production\" && error instanceof MoonsError\n ? `<pre>${escapeHtml(error.format())}</pre>`\n : \"<p>Terjadi kesalahan internal.</p>\";\n\n return htmlResponse(\n `<!doctype html><html lang=\"id\"><head><meta charset=\"utf-8\"><title>500</title></head><body><h1>500</h1>${detail}</body></html>`,\n 500,\n );\n}\n\nfunction htmlResponse(html: string, status: number): Response {\n return new Response(html, {\n status,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n}\n\n/** §19.5: `/_moons/health` → `{ ok: true }`. */\nfunction healthResponse(method: string): Response {\n const headers = { \"content-type\": \"application/json; charset=utf-8\" };\n if (method === \"GET\" || method === \"HEAD\") {\n return new Response(method === \"HEAD\" ? null : JSON.stringify({ ok: true }), {\n status: 200,\n headers,\n });\n }\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: { allow: \"GET, HEAD\" },\n });\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n\n/**\n * A1: peringatan dev untuk payload SSR yang memuat canary/nilai env\n * mirip-rahasia (sekali per label). Tidak pernah aktif di production karena\n * `payloadScan` hanya diisi runtime dev.\n */\nfunction warnPayloadFindings(\n payload: string,\n scan: PayloadScanOptions | undefined,\n warned: Set<string>,\n): void {\n if (scan === undefined) {\n return;\n }\n for (const finding of scanPayloadForSecrets(payload, scan)) {\n const label = finding.kind === \"canary\" ? \"canary\" : `env(${finding.label})`;\n if (warned.has(label)) {\n continue;\n }\n warned.add(label);\n console.warn(\n `[moons] peringatan dev: payload SSR memuat ${label} — jangan mengembalikan rahasia dari loader.`,\n );\n }\n}\n",
|
|
5
|
+
"import {\n MoonsError,\n composeMiddleware,\n findApiDirMiddlewares,\n findDirMiddlewares,\n findErrorBoundary,\n isNotFoundSignal,\n isRedirectSignal,\n resolveRoute,\n routeKeyFromFile,\n runLoaders,\n type ApiMethod,\n type ApiMiddlewareDefinition,\n type ApiRouteDefinition,\n type Middleware,\n type MoonsConfig,\n type ResolvedRoute,\n type RouteDefinition,\n type RouteModule,\n trailingSlashRedirect,\n} from \"@moonsjs/core\";\nimport { encodeSsrPayload, reviveError, serializeError } from \"@moonsjs/core/serialize\";\nimport { API_METHODS, resolveApiRoute } from \"@moonsjs/core\";\nimport { renderToMarkup } from \"@moonsjs/react/ssr\";\nimport type { ClientRouteEntry, RouteModuleShape } from \"@moonsjs/react/internal\";\nimport { createRpcHandler, runWithContext, runWithRequestCache, runWithResponseCollector, takeResponseMutations } from \"@moonsjs/server\";\nimport { NOT_FOUND_ROUTE_KEY } from \"../manifest\";\nimport { scanPayloadForSecrets, type PayloadScanOptions } from \"../payload-scan\";\nimport type { Shell } from \"./shell\";\n\nconst RPC_PREFIX = \"/_moons/fn/\";\nconst HEALTH_PATH = \"/_moons/health\";\n\nexport interface RequestHandlerOptions {\n routes: RouteDefinition[];\n /** Config yang sudah divalidasi. */\n config: MoonsConfig;\n /** Direktori route absolut; dipakai untuk derivasi key stabil. */\n routesDir: string;\n /** Peta import() modul route, key = routeKeyFromFile. */\n loadRoute: Record<string, () => Promise<RouteModule>>;\n shell: Shell;\n /**\n * Dipanggil setelah `config.context` per request (Addendum B.4: extender\n * `extendContext` plugin di-merge ke ctx).\n */\n onContext?: (ctx: Ctx) => void;\n /**\n * A1: pemindaian payload SSR (dev) — peringatan sekali per label bila payload\n * memuat canary/nilai env mirip-rahasia. Production TIDAK mengisi opsi ini\n * (tanpa biaya runtime). Lihat `payload-scan.ts`.\n */\n payloadScan?: PayloadScanOptions;\n /** Endpoint API `src/api` (Addendum D.1) — hasil scan plugin. */\n apiRoutes?: ApiRouteDefinition[];\n /** Peta import() modul API, key = route.path. */\n loadApi?: Record<string, () => Promise<unknown>>;\n /** Middleware direktori pohon `src/api` (Addendum D.3). */\n apiMiddlewares?: ApiMiddlewareDefinition[];\n /** Peta import() `_middleware.ts` pohon api, key = file path. */\n loadApiMiddleware?: Record<string, () => Promise<unknown>>;\n}\n\n/**\n * Handler HTML: context → middleware global → resolve route → loader paralel\n * → render React → inject payload devalue (PRD §11.2, §14.2, §17).\n */\nexport function createRequestHandler(\n options: RequestHandlerOptions,\n): (request: Request) => Promise<Response> { const { routes, config, routesDir, loadRoute, shell } = options;\n const rpc = createRpcHandler(\n config.security === undefined ? {} : { security: config.security },\n );\n const notFoundRoute = routes.find((route) => route.kind === \"404\");\n const errorRoute = routes.find((route) => route.kind === \"error\");\n /** A1: dedupe peringatan payload (sekali per label). */\n const warnedPayloadLabels = new Set<string>();\n\n async function renderRoute(\n resolved: ResolvedRoute,\n request: Request,\n ctx: Ctx,\n ): Promise<Response> {\n const entries = [...resolved.layouts, resolved.route];\n const keys = entries.map((entry) => routeKeyFromFile(routesDir, entry.file));\n const modules = await loadModules(keys, loadRoute);\n\n const data = await runLoaders(\n entries.map((entry, index) => ({ file: keys[index] as string, module: modules[index] as RouteModule })),\n { params: resolved.params, ctx, req: request },\n );\n\n const pageKey = routeKeyFromFile(routesDir, resolved.route.file);\n const pageModule = modules[modules.length - 1] as RouteModule;\n const entry: ClientRouteEntry = { page: pageKey, layouts: keys.slice(0, -1) };\n // Addendum A.3: query string ikut ke payload agar server/client identik.\n const searchParams = Object.fromEntries(new URL(request.url).searchParams);\n // Addendum B.1: eksekusi `meta()` page (data = hasil loader page itu sendiri).\n const meta = await runRouteMeta(pageModule, data[pageKey], resolved.route.file);\n\n const markup = renderToMarkup(\n entry,\n { page: pageModule as RouteModuleShape, layouts: modules.slice(0, -1) as RouteModuleShape[] },\n resolved.params,\n data,\n searchParams,\n undefined,\n config.trailingSlash,\n );\n const payload = encodeSsrPayload({\n key: pageKey,\n params: resolved.params,\n searchParams,\n data,\n ...(meta === undefined ? {} : { meta }),\n });\n\n // A1: pindai payload SSR (dev saja — `payloadScan` tidak diisi production).\n warnPayloadFindings(payload, options.payloadScan, warnedPayloadLabels);\n\n return htmlResponse(\n withTrailingSlashMeta(await shell(markup, payload, request.url, meta), config.trailingSlash),\n 200,\n );\n }\n\n /** Addendum D.1: dispatch endpoint `src/api` (405/HEAD/OPTIONS + error). */\n async function handleApiRequest(\n route: ApiRouteDefinition,\n params: Record<string, string>,\n request: Request,\n ctx: Ctx,\n ): Promise<Response> {\n const load = options.loadApi?.[route.path];\n if (load === undefined) {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: `API module \\`${route.path}\\` could not be loaded`,\n details: \"The `loadApi` map does not contain this route (build/dev out of sync).\",\n suggestions: [\"Rebuild / restart the dev server\"],\n }),\n route,\n );\n }\n\n let mod: unknown;\n try {\n mod = await load();\n } catch (error) {\n return apiErrorResponse(error, route);\n }\n if (mod === null || typeof mod !== \"object\") {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: \"API module does not export a handler object\",\n details: `Module \\`${route.path}\\` must export method handlers.`,\n suggestions: [\"Export `GET`/`POST`/… as `(args) => Response` functions\"],\n }),\n route,\n );\n }\n\n const record = mod as Record<string, unknown>;\n const methods: ApiMethod[] = API_METHODS.filter(\n (method) => typeof record[method] === \"function\",\n );\n const requestMethod = request.method.toUpperCase();\n type ApiHandlerFn = (args: {\n req: Request;\n params: Record<string, string>;\n ctx: Ctx;\n }) => Response | Promise<Response>;\n let handler = record[requestMethod] as ApiHandlerFn | undefined;\n let stripBody = false;\n\n // D.7 #2: HEAD otomatis dari GET; OPTIONS otomatis → 204 + Allow.\n if (typeof handler !== \"function\" && requestMethod === \"HEAD\" && typeof record[\"GET\"] === \"function\") {\n handler = record[\"GET\"] as ApiHandlerFn;\n stripBody = true;\n }\n if (typeof handler !== \"function\") {\n if (requestMethod === \"OPTIONS\") {\n return new Response(null, { status: 204, headers: { allow: methods.join(\", \") } });\n }\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: { allow: methods.join(\", \") },\n });\n }\n\n try {\n const result = await handler({ req: request, params, ctx });\n if (!(result instanceof Response)) {\n return apiErrorResponse(\n new MoonsError({\n code: \"E_API_HANDLER_INVALID\",\n file: route.file,\n message: `handler \\`${requestMethod}\\` did not return a \\`Response\\``,\n details: \"API handlers must return `new Response(...)`.\",\n suggestions: [\"Return `new Response(body, { status, headers })`\"],\n }),\n route,\n );\n }\n if (stripBody) {\n return new Response(null, { status: result.status, headers: result.headers });\n }\n return result;\n } catch (error) {\n return apiErrorResponse(error, route);\n }\n }\n\n /** §11.2: halaman `_404.tsx` kustom (standalone), fallback bawaan. */\n async function notFoundResponse(request: Request): Promise<Response> {\n if (notFoundRoute !== undefined) {\n try {\n const key = routeKeyFromFile(routesDir, notFoundRoute.file);\n const [module] = await loadModules([key], loadRoute);\n const payload = encodeSsrPayload({ key: NOT_FOUND_ROUTE_KEY, params: {}, data: {} });\n const markup = renderToMarkup(\n { page: key, layouts: [] },\n { page: module as RouteModuleShape, layouts: [] },\n {},\n {},\n {},\n undefined,\n config.trailingSlash,\n );\n return htmlResponse(\n withTrailingSlashMeta(await shell(markup, payload, request.url), config.trailingSlash),\n 404,\n );\n } catch (error) {\n console.error(\"[moons] failed to render custom _404:\", error);\n }\n }\n\n const payload = encodeSsrPayload({ key: \"\", params: {}, data: {} });\n const html = await shell(\"<h1>404</h1><p>Page not found.</p>\", payload, request.url);\n return htmlResponse(withTrailingSlashMeta(html, config.trailingSlash), 404);\n }\n\n /**\n * §11.2/D.3: `_error.tsx` kustom (boundary terdekat dari route; fallback\n * root). Production tidak men-serialisasi error apa pun (§16.6).\n */\n async function routeErrorResponse(\n error: unknown,\n request: Request,\n resolved?: ResolvedRoute,\n ): Promise<Response> {\n console.error(\"[moons] route error:\", error);\n\n const boundary =\n (resolved === undefined ? null : findErrorBoundary(resolved.route, routes)) ??\n errorRoute ??\n null;\n if (boundary !== null) {\n try {\n const key = routeKeyFromFile(routesDir, boundary.file);\n const [module] = await loadModules([key], loadRoute);\n const isProduction = process.env[\"NODE_ENV\"] === \"production\";\n const serialized = isProduction ? undefined : serializeError(error);\n const payload = encodeSsrPayload({\n key,\n params: {},\n data: {},\n ...(serialized === undefined ? {} : { error: serialized }),\n });\n const markup = renderToMarkup(\n { page: key, layouts: [] },\n { page: module as RouteModuleShape, layouts: [] },\n {},\n {},\n {},\n serialized === undefined ? undefined : reviveError(serialized),\n config.trailingSlash,\n );\n return htmlResponse(\n withTrailingSlashMeta(await shell(markup, payload, request.url), config.trailingSlash),\n 500,\n );\n } catch (renderError) {\n console.error(\"[moons] failed to render custom _error:\", renderError);\n }\n }\n\n return internalErrorResponse(error, { log: false });\n }\n\n /** Muat middleware direktori (D.3) → `Middleware[]`; error bentuk jelas. */\n async function loadDirMiddlewares(chain: ReadonlyArray<RouteDefinition>): Promise<Middleware[]> {\n const result: Middleware[] = [];\n for (const definition of chain) {\n const key = routeKeyFromFile(routesDir, definition.file);\n const load = options.loadRoute?.[key];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"directory middleware could not be loaded\",\n details: \"The `loadRoute` map does not contain this `_middleware.ts`.\",\n suggestions: [\"Restart the dev server / rebuild\"],\n });\n }\n const module = (await load()) as { default?: unknown };\n const handler = module.default;\n if (typeof handler !== \"function\") {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"`_middleware.ts` does not default-export a function\",\n details: \"Directory middleware follows the `(args) => Promise<Response>` shape.\",\n suggestions: [\"Export default `async ({ req, ctx, next }) => await next()`\"],\n });\n }\n result.push(handler as Middleware);\n }\n return result;\n }\n\n /** Muat middleware pohon `src/api` (D.3). */\n async function loadApiDirMiddlewares(\n chain: ReadonlyArray<ApiMiddlewareDefinition>,\n ): Promise<Middleware[]> {\n const result: Middleware[] = [];\n for (const definition of chain) {\n const load = options.loadApiMiddleware?.[definition.file];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"API middleware could not be loaded\",\n details: \"The `loadApiMiddleware` map does not contain this `_middleware.ts`.\",\n suggestions: [\"Restart the dev server / rebuild\"],\n });\n }\n const module = (await load()) as { default?: unknown };\n if (typeof module.default !== \"function\") {\n throw new MoonsError({\n code: \"E_MIDDLEWARE_INVALID\",\n file: definition.file,\n message: \"`_middleware.ts` does not default-export a function\",\n details: \"Directory middleware follows the `(args) => Promise<Response>` shape.\",\n suggestions: [\"Export default `async ({ req, ctx, next }) => await next()`\"],\n });\n }\n result.push(module.default as Middleware);\n }\n return result;\n }\n\n const handleCore = async function handler(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n\n // §19.5: health ditangani paling awal — tetap hidup walau kode user rusak.\n if (url.pathname === HEALTH_PATH) {\n return healthResponse(request.method);\n }\n\n // `MoonsConfig.context` bertipe `unknown` (menghindari referensi sirkular\n // ke global `Ctx` — §13); kontraknya tetap `Promise<Ctx>`, jadi cast di\n // batas runtime ini. Tanpa cast, tsc app user yang memuat `@moonsjs/vite/server`\n // (mis. `createTestServer` §19.5) melihat `unknown` vs `Ctx` global app.\n const ctx = (await config.context(request)) as Ctx;\n options.onContext?.(ctx);\n // Addendum D.5: tandai request prerender build-time (aditif §13.1).\n if (request.headers.get(\"x-moons-prerender\") === \"1\") {\n (ctx as Record<string, unknown>)[\"__prerender\"] = true;\n }\n\n const respond = composeMiddleware(config.middleware ?? [], ctx, async () => {\n if (url.pathname.startsWith(RPC_PREFIX)) {\n return await rpc(request, url.pathname.slice(RPC_PREFIX.length), ctx);\n }\n // Addendum D.1: endpoint HTTP mentah `src/api` (semua method).\n if (options.apiRoutes !== undefined && options.apiRoutes.length > 0) {\n const apiMatch = resolveApiRoute(url.pathname, options.apiRoutes);\n if (apiMatch !== null) {\n // Addendum D.3: middleware direktori pohon api.\n const apiChain = findApiDirMiddlewares(\n apiMatch.route.file,\n options.apiMiddlewares ?? [],\n );\n if (apiChain.length === 0) {\n return await handleApiRequest(apiMatch.route, apiMatch.params, request, ctx);\n }\n const middlewares = await loadApiDirMiddlewares(apiChain);\n return await composeMiddleware(\n middlewares,\n ctx,\n () => handleApiRequest(apiMatch.route, apiMatch.params, request, ctx),\n { code: \"E_MIDDLEWARE_INVALID\", label: \"API middleware\" },\n )(request);\n }\n }\n const resolved = resolveRoute(url.pathname, routes);\n if (resolved === null) {\n return await notFoundResponse(request);\n }\n try {\n // Addendum D.3: middleware direktori (root→leaf) untuk page.\n const dirChain = findDirMiddlewares(resolved.route, routes);\n if (dirChain.length === 0) {\n return await renderRoute(resolved, request, ctx);\n }\n const middlewares = await loadDirMiddlewares(dirChain);\n return await composeMiddleware(\n middlewares,\n ctx,\n () => renderRoute(resolved, request, ctx),\n { code: \"E_MIDDLEWARE_INVALID\", label: \"directory middleware\" },\n )(request);\n } catch (error) {\n // Addendum B.2: sinyal routing dari loader/meta.\n if (isRedirectSignal(error)) {\n return new Response(null, {\n status: error.status,\n headers: { location: new URL(error.to, request.url).toString() },\n });\n }\n if (isNotFoundSignal(error)) {\n return await notFoundResponse(request);\n }\n return await routeErrorResponse(error, request, resolved);\n }\n });\n\n // Addendum D.2: kolektor mutasi respons aktif selama request; helper\n // (setHeader/setCookie) menulis ke store, diterapkan ke Response akhir —\n // termasuk jalur error (mutasi yang sudah dipush tetap dihormati).\n return await runWithResponseCollector(async () => {\n let response: Response;\n try {\n response = await runWithRequestCache(() => runWithContext(ctx, () => respond(request)));\n } catch (error) {\n response = internalErrorResponse(error);\n }\n return applyResponseMutations(response);\n });\n } catch (error) {\n return internalErrorResponse(error);\n }\n };\n\n // Addendum H: redirect statis + hook lifecycle + header statis.\n const staticHeaders = Object.entries(config.headers ?? {});\n const redirects = (config.redirects ?? []).map((entry) => ({\n ...entry,\n status: entry.status ?? 301,\n }));\n\n return async function handler(request: Request): Promise<Response> {\n const isPrerender = request.headers.get(\"x-moons-prerender\") === \"1\";\n const applyHeaders = (response: Response): Response => {\n for (const [name, value] of staticHeaders) {\n if (!response.headers.has(name)) {\n response.headers.set(name, value);\n }\n }\n return response;\n };\n\n try {\n // Addendum M: kanonikalisasi trailing slash sebelum routing (308,\n // query dipertahankan; `/_moons/**`, root, dan aset dikecualikan).\n if (!isPrerender && config.trailingSlash !== undefined) {\n const policyUrl = new URL(request.url);\n const canonical = trailingSlashRedirect(policyUrl.pathname, config.trailingSlash);\n if (canonical !== null) {\n policyUrl.pathname = canonical;\n return applyHeaders(\n new Response(null, { status: 308, headers: { location: policyUrl.toString() } }),\n );\n }\n }\n\n if (!isPrerender && redirects.length > 0) {\n const url = new URL(request.url);\n const path = url.pathname.replace(/\\/$/, \"\");\n for (const entry of redirects) {\n if (path === entry.from.replace(/\\/$/, \"\")) {\n const location = entry.to.startsWith(\"http\")\n ? entry.to\n : new URL(entry.to, url.origin).toString();\n return applyHeaders(\n new Response(null, { status: entry.status, headers: { location } }),\n );\n }\n }\n }\n\n await config.hooks?.onRequest?.(request);\n let response = await handleCore(request);\n const replaced = await config.hooks?.onResponse?.(response, request);\n if (replaced instanceof Response) {\n response = replaced;\n }\n return applyHeaders(response);\n } catch (error) {\n try {\n await config.hooks?.onError?.(error, request);\n } catch {\n // Kegagalan hook tidak boleh menutupi error asli.\n }\n return internalErrorResponse(error);\n }\n };\n}\n\n/** Terapkan mutasi `setHeader`/`appendHeader`/`setCookie` ke respons (D.2). */\nfunction applyResponseMutations(response: Response): Response {\n const mutations = takeResponseMutations();\n if (mutations.length === 0) {\n return response;\n }\n const headers = new Headers(response.headers);\n for (const mutation of mutations) {\n if (mutation.kind === \"header\") {\n if (mutation.append) {\n headers.append(mutation.name, mutation.value);\n } else {\n headers.set(mutation.name, mutation.value);\n }\n } else {\n headers.append(\"set-cookie\", mutation.value);\n }\n }\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nasync function loadModules(\n keys: string[],\n loadRoute: Record<string, () => Promise<RouteModule>>,\n): Promise<RouteModule[]> {\n return await Promise.all(\n keys.map(async (key) => {\n const load = loadRoute[key];\n if (load === undefined) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n message: `route module \\`${key}\\` is not registered`,\n details: \"The route registry is out of sync with the scan result.\",\n suggestions: [\"Run `bun run build` again, or restart the dev server\"],\n });\n }\n return await load();\n }),\n );\n}\n\nasync function runRouteMeta(\n pageModule: RouteModule,\n pageData: unknown,\n file: string,\n): Promise<Record<string, unknown> | undefined> {\n const meta = (pageModule as { meta?: unknown }).meta;\n if (meta === undefined) {\n return undefined;\n }\n if (typeof meta !== \"function\") {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"export `meta` must be a function `({ data }) => RouteMeta`\",\n details: \"The `meta` shape follows `RouteMeta`.\",\n suggestions: [\n \"Change it to `export const meta = ({ data }) => ({ title: \\\"...\\\" })`\",\n \"Or remove the `meta` export\",\n ],\n });\n }\n const result = await (meta as (args: { data: unknown }) => unknown)({ data: pageData });\n if (result === null || typeof result !== \"object\" || Array.isArray(result)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"`meta()` must return a RouteMeta object\",\n details: \"The returned value is used for <title>/description/og.\",\n suggestions: [\"Return an object, e.g. `({ title: \\\"Home\\\" })`\"],\n });\n }\n return result as Record<string, unknown>;\n}\n\n/**\n * Error endpoint API (Addendum D.1): detail hanya di non-production (§16.6).\n */\nfunction apiErrorResponse(error: unknown, route: ApiRouteDefinition): Response {\n const isProduction = process.env[\"NODE_ENV\"] === \"production\";\n if (error instanceof MoonsError) {\n console.error(`[moons] API ${route.path}: ${error.format()}`);\n return new Response(isProduction ? \"Internal server error.\" : error.format(), {\n status: 500,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n }\n console.error(`[moons] API ${route.path}:`, error);\n return new Response(isProduction ? \"Internal server error.\" : String(error), {\n status: 500,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n}\n\nfunction internalErrorResponse(error: unknown, options: { log?: boolean } = {}): Response {\n if (options.log !== false) {\n console.error(\"[moons] request error:\", error);\n }\n\n const detail =\n process.env[\"NODE_ENV\"] !== \"production\" && error instanceof MoonsError\n ? `<pre>${escapeHtml(error.format())}</pre>`\n : \"<p>Internal server error.</p>\";\n\n return htmlResponse(\n `<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>500</title></head><body><h1>500</h1>${detail}</body></html>`,\n 500,\n );\n}\n\n/** Addendum O: expose the trailing-slash policy to the client runtime. */\nfunction withTrailingSlashMeta(html: string, policy?: \"never\" | \"always\"): string {\n if (policy === undefined) {\n return html;\n }\n return html.replace(\n \"</head>\",\n ` <meta name=\"moons:trailing-slash\" content=\"${policy}\" />\\n</head>`,\n );\n}\n\nfunction htmlResponse(html: string, status: number): Response {\n return new Response(html, {\n status,\n headers: { \"content-type\": \"text/html; charset=utf-8\" },\n });\n}\n\n/** §19.5: `/_moons/health` → `{ ok: true }`. */\nfunction healthResponse(method: string): Response {\n const headers = { \"content-type\": \"application/json; charset=utf-8\" };\n if (method === \"GET\" || method === \"HEAD\") {\n return new Response(method === \"HEAD\" ? null : JSON.stringify({ ok: true }), {\n status: 200,\n headers,\n });\n }\n return new Response(\"Method Not Allowed\", {\n status: 405,\n headers: { allow: \"GET, HEAD\" },\n });\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n\n/**\n * A1: peringatan dev untuk payload SSR yang memuat canary/nilai env\n * mirip-rahasia (sekali per label). Tidak pernah aktif di production karena\n * `payloadScan` hanya diisi runtime dev.\n */\nfunction warnPayloadFindings(\n payload: string,\n scan: PayloadScanOptions | undefined,\n warned: Set<string>,\n): void {\n if (scan === undefined) {\n return;\n }\n for (const finding of scanPayloadForSecrets(payload, scan)) {\n const label = finding.kind === \"canary\" ? \"canary\" : `env(${finding.label})`;\n if (warned.has(label)) {\n continue;\n }\n warned.add(label);\n console.warn(\n `[moons] dev warning: SSR payload contains ${label} — do not return secrets from loaders.`,\n );\n }\n}\n",
|
|
6
6
|
"/**\n * Pemindaian payload SSR (nilai A1 / PRD §2): HANYA dipakai di dev sebagai\n * peringatan — tidak ada biaya runtime di production (production tidak pernah\n * memanggil fungsi ini; lihat `RequestHandlerOptions.payloadScan`).\n */\n\nexport interface PayloadScanOptions {\n /** Canary `leakTest.canary` (bila dikonfigurasi). */\n canary?: string;\n /** Lingkungan server (biasanya `process.env`). */\n env?: Record<string, string | undefined>;\n}\n\nexport interface PayloadScanFinding {\n kind: \"canary\" | \"env\";\n /** Label untuk pesan: `canary` atau nama env var. */\n label: string;\n}\n\n/**\n * Nama env yang \"mirip rahasia\" — dideteksi lewat pola nama + panjang nilai\n * minimum 12 karakter untuk menghindari false positive (keputusan pemilik).\n */\nconst SECRET_KEY_PATTERN =\n /(SECRET|TOKEN|PASSWORD|PASSWD|PRIVATE|CREDENTIAL|AUTH|API_KEY|ACCESS_KEY|SIGNING)/i;\n\nconst MIN_SECRET_LENGTH = 12;\n\nexport function scanPayloadForSecrets(\n payload: string,\n options: PayloadScanOptions = {},\n): PayloadScanFinding[] {\n const findings: PayloadScanFinding[] = [];\n\n const canary = options.canary;\n if (canary !== undefined && canary.length > 0 && payload.includes(canary)) {\n findings.push({ kind: \"canary\", label: \"canary\" });\n }\n\n for (const [key, value] of Object.entries(options.env ?? {})) {\n if (typeof value !== \"string\" || value.length < MIN_SECRET_LENGTH) {\n continue;\n }\n if (!SECRET_KEY_PATTERN.test(key) || /PUBLIC/i.test(key)) {\n continue;\n }\n if (payload.includes(value)) {\n findings.push({ kind: \"env\", label: key });\n }\n }\n\n return findings;\n}\n",
|
|
7
|
-
"import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { gzipSync } from \"node:zlib\";\nimport { createServer, type Server } from \"node:http\";\nimport { extname, join, resolve, sep } from \"node:path\";\nimport {\n DEFAULT_BODY_LIMIT_BYTES,\n MoonsError,\n trailingSlashRedirect,\n type PrerenderStorage,\n} from \"@moonsjs/core\";\nimport { revalidatePrerendered, shouldRevalidate } from \"./isr\";\nimport { contentTypeForPathname } from \"./storage\";\nimport {\n BodyLimitError,\n DEFAULT_SECURITY_HEADERS,\n InvalidRequestError,\n resolveClientIp,\n resolveRequestUrl,\n sendNodeResponse,\n toWebRequest,\n} from \"./node\";\nimport { createLogger, type Logger } from \"./logger\";\nimport type { PluginRuntime } from \"./plugins\";\nimport { installGracefulShutdown } from \"./shutdown\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".wasm\": \"application/wasm\",\n};\n\nexport interface NodeServerOptions {\n port?: number;\n clientDir?: string;\n /** Pasang handler SIGTERM/SIGINT (default true). */\n handleSignals?: boolean;\n /** Batas drain shutdown (default 10_000 ms). */\n shutdownTimeoutMs?: number;\n /** Lifecycle plugin (Addendum B.4) — onStart/onReady/onShutdown. */\n plugins?: PluginRuntime;\n /** Canary `leakTest.canary` untuk guard ISR (Addendum E.1). */\n canary?: string;\n /**\n * Header statis dari config (Addendum H). Diterapkan juga pada file\n * prerender yang disajikan langsung (static host memakai `_headers`).\n */\n headers?: Record<string, string>;\n /**\n * Storage bersama untuk file prerender (Addendum I, ISR multi-instance).\n * Bila diisi, penyajian file prerender dan penulisan hasil regenerasi\n * memakai storage ini; default: file sistem lokal.\n */\n storage?: PrerenderStorage;\n /** Addendum J.1: percayai `x-forwarded-proto`/`x-forwarded-host` (default false). */\n trustProxy?: boolean;\n /** Addendum J.2: batas body RPC di transport (default `DEFAULT_BODY_LIMIT_BYTES`). */\n bodyLimitBytes?: number;\n /** Addendum L.3: log akses terstruktur (default senyap). */\n logging?: { accessLog?: boolean; json?: boolean; redact?: string[] };\n /** Addendum M: kebijakan trailing slash (juga untuk path prerender/static). */\n trailingSlash?: \"never\" | \"always\";\n}\n\n/**\n * Serve produksi (M1 §19.2, §18): static dari `dist/client` + handler SSR.\n * Berjalan di Bun dan Node (hanya API `node:*`).\n */\nexport function startNodeServer(\n handler: (request: Request) => Promise<Response>,\n options: NodeServerOptions = {},\n): Server {\n const clientDir = resolve(options.clientDir ?? join(process.cwd(), \"dist/client\"));\n const port = options.port ?? Number(process.env[\"PORT\"] ?? 3000);\n\n const accessLogger: Logger | null =\n options.logging?.accessLog === true\n ? createLogger({\n json: options.logging.json !== false,\n redact: options.logging.redact ?? [],\n })\n : null;\n\n const server = createServer((req, res) => {\n const requestStartedAt = performance.now();\n if (accessLogger !== null) {\n res.once(\"finish\", () => {\n const ip = resolveClientIp(req, options.trustProxy === true);\n accessLogger({\n msg: \"request\",\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n status: res.statusCode,\n durationMs: Math.round(performance.now() - requestStartedAt),\n ...(ip === null ? {} : { ip }),\n });\n });\n }\n void (async () => {\n let url: URL;\n try {\n // Addendum J.1: URL/Origin mengikuti `x-forwarded-*` bila trustProxy aktif;\n // request malformed → 400 (bukan 500 + stack).\n url = resolveRequestUrl(req, { trustProxy: options.trustProxy === true });\n } catch (error) {\n if (error instanceof InvalidRequestError) {\n console.warn(`[moons] ${error.message} — 400`);\n respondBadRequest(res);\n return;\n }\n throw error;\n }\n\n try {\n // Addendum M: kanonikalisasi trailing slash di transport — mencakup\n // path prerender yang dilayani langsung (tidak lewat handler).\n if (options.trailingSlash !== undefined) {\n const canonical = trailingSlashRedirect(url.pathname, options.trailingSlash);\n if (canonical !== null) {\n url.pathname = canonical;\n res.statusCode = 308;\n res.setHeader(\"location\", url.toString());\n res.end();\n return;\n }\n }\n\n if (req.method === \"GET\" || req.method === \"HEAD\") {\n // Addendum I: storage bersama (bila dikonfigurasi) diutamakan.\n if (options.storage !== undefined) {\n const entry = await options.storage.read(url.pathname);\n if (entry !== null) {\n scheduleRevalidation({\n pathname: url.pathname,\n mtimeMs: entry.mtimeMs,\n storage: options.storage,\n handler,\n options,\n clientDir,\n logger: accessLogger,\n });\n res.statusCode = 200;\n res.setHeader(\"content-type\", contentTypeForPathname(url.pathname));\n applyStaticHeaders(res, url.pathname, options.headers);\n res.end(req.method === \"HEAD\" ? undefined : Buffer.from(entry.body));\n return;\n }\n // L.2 (temuan F1): storage MISS → jatuh ke file `dist/client`\n // (aset/non-ISR); storage tetap menang untuk path yang dimilikinya.\n }\n {\n const staticFile = resolveStaticFile(clientDir, url.pathname);\n if (staticFile !== null) {\n scheduleRevalidation({\n pathname: url.pathname,\n mtimeMs: statSync(staticFile).mtimeMs,\n file: staticFile,\n // Bila storage dikonfigurasi, hasil regenerasi (walau fallback\n // dari file) tetap ditulis ke storage bersama (L.2).\n ...(options.storage === undefined ? {} : { storage: options.storage }),\n handler,\n options,\n clientDir,\n logger: accessLogger,\n });\n const body = readFileSync(staticFile);\n const stat = statSync(staticFile);\n res.statusCode = 200;\n res.setHeader(\"content-type\", MIME_TYPES[extname(staticFile).toLowerCase()] ?? \"application/octet-stream\");\n applyStaticHeaders(res, url.pathname, options.headers);\n\n // Addendum K.5: ETag + 304.\n const etag = `W/\"${stat.size}-${Math.floor(stat.mtimeMs)}\"`;\n res.setHeader(\"etag\", etag);\n const ifNoneMatch = req.headers[\"if-none-match\"];\n if (\n typeof ifNoneMatch === \"string\" &&\n ifNoneMatch.split(\",\").some((value) => value.trim() === etag)\n ) {\n res.statusCode = 304;\n res.end();\n return;\n }\n\n // Addendum K.5: gzip untuk aset teks (cache per mtime).\n let payload: Buffer = body;\n if (\n req.method === \"GET\" &&\n COMPRESSIBLE_FILE.test(staticFile) &&\n body.byteLength >= GZIP_MIN_BYTES &&\n acceptsGzip(req)\n ) {\n payload = gzipCached(staticFile, stat.mtimeMs, body);\n res.setHeader(\"content-encoding\", \"gzip\");\n appendVary(res, \"accept-encoding\");\n }\n res.end(req.method === \"HEAD\" ? undefined : payload);\n return;\n }\n }\n }\n\n // Addendum J.2: batas body RPC ditegakkan di transport — lebih awal dari\n // pipeline, tanpa membaca penuh; `content-length` diperiksa lebih dulu.\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n const rpcLimit = options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES;\n if (isRpc) {\n const contentLength = Number(req.headers[\"content-length\"] ?? \"0\");\n if (Number.isFinite(contentLength) && contentLength > rpcLimit) {\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(rpcBodyTooLargeText(rpcLimit, contentLength));\n res.once(\"finish\", () => req.destroy());\n return;\n }\n }\n\n const request = await toWebRequest(req, {\n trustProxy: options.trustProxy === true,\n ...(isRpc ? { maxBodyBytes: rpcLimit } : {}),\n });\n const response = await handler(request);\n await sendNodeResponse(res, response);\n } catch (error) {\n if (error instanceof BodyLimitError) {\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(isRpc ? rpcBodyTooLargeText(error.limit, null) : \"Payload Too Large\");\n // Sisa body tidak perlu dibaca — putuskan setelah respons terkirim.\n res.once(\"finish\", () => req.destroy());\n return;\n }\n console.error(\"[moons] server error:\", error);\n res.statusCode = 500;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Internal Server Error\");\n }\n })();\n });\n\n // Addendum B.4: onStart sebelum listen, onReady setelah listen.\n const listenAfterStart = (): void => {\n server.listen(port, () => {\n const address = server.address();\n const boundPort = typeof address === \"object\" && address !== null ? address.port : port;\n console.log(`[moons] server listening on http://localhost:${boundPort}`);\n void options.plugins?.ready();\n });\n };\n if (options.plugins !== undefined) {\n void options.plugins.start().then(listenAfterStart);\n } else {\n listenAfterStart();\n }\n\n if (options.handleSignals !== false) {\n const shutdown = installGracefulShutdown(server, {\n ...(options.shutdownTimeoutMs === undefined ? {} : { timeoutMs: options.shutdownTimeoutMs }),\n ...(options.plugins === undefined\n ? {}\n : { onShutdown: () => options.plugins?.shutdown() }),\n });\n // `once`: sinyal kedua memakai perilaku default (proses langsung berhenti).\n process.once(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.once(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n return server;\n}\n\n/**\n * Addendum J.7: header konfigurasi (menang), default aman, dan\n * `Cache-Control: immutable` untuk aset ber-hash di `/assets/*`.\n */\nfunction applyStaticHeaders(\n res: import(\"node:http\").ServerResponse,\n pathname: string,\n configured: Record<string, string> | undefined,\n): void {\n for (const [name, value] of Object.entries(configured ?? {})) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n for (const [name, value] of Object.entries(DEFAULT_SECURITY_HEADERS)) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n if (pathname.startsWith(\"/assets/\") && !res.hasHeader(\"cache-control\")) {\n res.setHeader(\"cache-control\", \"public, max-age=31536000, immutable\");\n }\n}\n\nconst COMPRESSIBLE_FILE = /\\.(js|mjs|css|html|json|svg|txt|map|xml)$/i;\nconst GZIP_MIN_BYTES = 1024;\nconst GZIP_CACHE_MAX = 64;\nconst gzipCache = new Map<string, { mtimeMs: number; gzip: Buffer }>();\n\nfunction acceptsGzip(req: import(\"node:http\").IncomingMessage): boolean {\n const header = req.headers[\"accept-encoding\"];\n if (typeof header !== \"string\") {\n return false;\n }\n return header\n .toLowerCase()\n .split(\",\")\n .map((part) => part.trim())\n .some((part) => part === \"gzip\" || part === \"*\" || part.startsWith(\"gzip;\"));\n}\n\n/** Varian gzip ter-cache per file+mtime (bounded FIFO) — Addendum K.5. */\nfunction gzipCached(file: string, mtimeMs: number, body: Buffer): Buffer {\n const cached = gzipCache.get(file);\n if (cached !== undefined && cached.mtimeMs === mtimeMs) {\n return cached.gzip;\n }\n const gzip = gzipSync(body);\n if (gzipCache.size >= GZIP_CACHE_MAX) {\n const oldest = gzipCache.keys().next().value;\n if (oldest !== undefined) {\n gzipCache.delete(oldest);\n }\n }\n gzipCache.set(file, { mtimeMs, gzip });\n return gzip;\n}\n\nfunction appendVary(res: import(\"node:http\").ServerResponse, value: string): void {\n const existing = res.getHeader(\"vary\");\n if (typeof existing === \"string\" && existing.length > 0) {\n if (!existing.toLowerCase().includes(value)) {\n res.setHeader(\"vary\", `${existing}, ${value}`);\n }\n return;\n }\n res.setHeader(\"vary\", value);\n}\n\nfunction respondBadRequest(res: import(\"node:http\").ServerResponse): void {\n res.statusCode = 400;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Bad Request\");\n}\n\n/** 413 transport dengan format §15 yang sama seperti `rpc.ts` (Addendum J.2). */\nfunction rpcBodyTooLargeText(limit: number, size: number | null): string {\n const megabytes = (bytes: number): string => (bytes / 1_000_000).toFixed(1);\n return new MoonsError({\n code: \"E_RPC_BODY_TOO_LARGE\",\n message:\n size === null\n ? `body melebihi limit ${megabytes(limit)} MB`\n : `body ${megabytes(size)} MB melebihi limit ${megabytes(limit)} MB`,\n details:\n \"Body melebihi `security.bodyLimitBytes`; pembacaan dihentikan di transport sebelum penuh.\",\n suggestions: [\n \"Kurangi ukuran payload, atau\",\n \"Naikkan security.bodyLimitBytes jika memang perlu\",\n ],\n }).format();\n}\n\n/** Resolve file static dengan proteksi path traversal (+ manifest prerender D.5). */\nexport function resolveStaticFile(clientDir: string, pathname: string): string | null {\n const target = staticFileTarget(clientDir, pathname);\n return target !== null && isFile(target) ? target : null;\n}\n\n/**\n * Target file untuk `pathname` (tanpa cek keberadaan) — dipakai penyajian,\n * `createFileStorage().write`, dan test. Proteksi path traversal tetap.\n */\nexport function staticFileTarget(clientDir: string, pathname: string): string | null {\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n\n // 1) File persis (aset: js/css/png/…, atau HTML yang diminta eksplisit).\n const exact = safeWithin(clientDir, `.${decoded}`);\n if (exact !== null && isFile(exact)) {\n return exact;\n }\n\n // 2) Hasil prerender: hanya path yang tercatat di manifest yang dilayani\n // statis — bukan shell `index.html` biasa (yang berarti bypass SSR).\n const normalized = decoded.length > 1 ? decoded.replace(/\\/+$/, \"\") : decoded;\n const manifest = readPrerenderManifest(clientDir);\n if (manifest.paths.has(normalized)) {\n const target = normalized === \"/\" ? \"index.html\" : `${normalized.slice(1)}/index.html`;\n return safeWithin(clientDir, `./${target}`);\n }\n\n return null;\n}\n\nfunction safeWithin(clientDir: string, relative: string): string | null {\n const candidate = resolve(clientDir, relative);\n if (candidate !== clientDir && !candidate.startsWith(clientDir + sep)) {\n return null;\n }\n return candidate;\n}\n\nfunction isFile(path: string): boolean {\n return existsSync(path) && statSync(path).isFile();\n}\n\nexport interface PrerenderManifestInfo {\n paths: Set<string>;\n revalidate: Map<string, number>;\n}\n\nlet prerenderManifestCache:\n | { file: string; mtimeMs: number; info: PrerenderManifestInfo }\n | null = null;\n\nfunction readPrerenderManifest(clientDir: string): PrerenderManifestInfo {\n const file = join(clientDir, \"_moons_prerender.json\");\n const empty: PrerenderManifestInfo = { paths: new Set(), revalidate: new Map() };\n try {\n const mtimeMs = statSync(file).mtimeMs;\n if (\n prerenderManifestCache !== null &&\n prerenderManifestCache.file === file &&\n prerenderManifestCache.mtimeMs === mtimeMs\n ) {\n return prerenderManifestCache.info;\n }\n const json = JSON.parse(readFileSync(file, \"utf8\")) as {\n paths?: unknown;\n version?: unknown;\n entries?: unknown;\n };\n const paths = new Set<string>();\n const revalidate = new Map<string, number>();\n if (Array.isArray(json.paths)) {\n // Manifest v1 (D.5) — tanpa revalidate.\n for (const path of json.paths) {\n if (typeof path === \"string\") {\n paths.add(path);\n }\n }\n }\n if (Array.isArray(json.entries)) {\n // Manifest v2 (E.1).\n for (const entry of json.entries as Array<Record<string, unknown>>) {\n if (entry === null || typeof entry !== \"object\" || typeof entry[\"path\"] !== \"string\") {\n continue;\n }\n const path = entry[\"path\"] as string;\n paths.add(path);\n const seconds = entry[\"revalidate\"];\n if (typeof seconds === \"number\" && Number.isFinite(seconds) && seconds >= 0) {\n revalidate.set(path, seconds);\n }\n }\n }\n const info = { paths, revalidate };\n prerenderManifestCache = { file, mtimeMs, info };\n return info;\n } catch {\n return empty;\n }\n}\n\n/** ISR: jika file prerender kedaluwarsa, regenerasi background (SWR). */\nfunction scheduleRevalidation(input: {\n pathname: string;\n mtimeMs: number;\n file?: string;\n storage?: PrerenderStorage;\n handler: (request: Request) => Promise<Response>;\n options: NodeServerOptions;\n clientDir: string;\n logger?: Logger | null;\n}): void {\n const normalized = input.pathname.length > 1 ? input.pathname.replace(/\\/+$/, \"\") : input.pathname;\n const seconds = readPrerenderManifest(input.clientDir).revalidate.get(normalized);\n if (seconds === undefined || seconds < 0) {\n return;\n }\n if (!shouldRevalidate({ mtimeMs: input.mtimeMs, revalidateSeconds: seconds })) {\n return;\n }\n const regeneratedAt = performance.now();\n const logger = input.logger ?? null;\n void revalidatePrerendered({\n pathname: normalized,\n ...(input.file === undefined ? {} : { file: input.file }),\n ...(input.storage === undefined ? {} : { storage: input.storage }),\n handler: input.handler,\n ...(input.options.canary === undefined ? {} : { canary: input.options.canary }),\n env: process.env,\n })\n .then(() => {\n logger?.({\n msg: \"isr:regenerated\",\n path: normalized,\n durationMs: Math.round(performance.now() - regeneratedAt),\n });\n })\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n if (logger !== null) {\n logger({ msg: \"isr:revalidate-failed\", level: \"warn\", path: normalized, error: message });\n } else {\n console.error(`[moons] isr regenerasi gagal (${normalized}): ${message}`);\n }\n });\n}\n\n",
|
|
8
|
-
"import { renameSync, writeFileSync } from \"node:fs\";\nimport type { PrerenderStorage } from \"@moonsjs/core\";\nimport { scanPayloadForSecrets } from \"../payload-scan\";\n\n/**\n * ISR / revalidate on-demand (PRD Addendum E.1): file prerender yang kedaluwarsa\n * disajikan apa adanya (stale-while-revalidate) sambil diregenerasi via handler\n * SSR in-process. Tulis atomik + guard kebocoran fail-closed.\n */\nexport function shouldRevalidate(input: {\n mtimeMs: number;\n revalidateSeconds: number;\n now?: number;\n}): boolean {\n const now = input.now ?? Date.now();\n return now - input.mtimeMs >= input.revalidateSeconds * 1000;\n}\n\nexport interface RevalidateOptions {\n /** Path URL ternormalisasi (mis. \"/blog/hello\"). */\n pathname: string;\n /** File HTML yang akan ditimpa (default file storage). */\n file?: string;\n /**\n * Storage alternatif (Addendum I). Bila diisi, `file` diabaikan dan hasil\n * regenerasi ditulis lewat `storage.write(pathname, body)`.\n */\n storage?: PrerenderStorage;\n handler: (request: Request) => Promise<Response>;\n canary?: string;\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n}\n\nconst inflight = new Map<string, Promise<void>>();\n\n/** Regenerasi ter-dedupe per path (panggilan paralel berbagi promise). */\nexport function revalidatePrerendered(options: RevalidateOptions): Promise<void> {\n const existing = inflight.get(options.pathname);\n if (existing !== undefined) {\n return existing;\n }\n const task = runRevalidate(options).finally(() => {\n inflight.delete(options.pathname);\n });\n inflight.set(options.pathname, task);\n return task;\n}\n\nasync function runRevalidate(options: RevalidateOptions): Promise<void> {\n const log = options.log ?? ((message: string) => console.log(message));\n try {\n const response = await options.handler(\n new Request(`http://localhost${options.pathname}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n if (response.status !== 200) {\n log(`[moons] isr:
|
|
9
|
-
"import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, extname } from \"node:path\";\nimport type { PrerenderStorage, PrerenderStorageEntry } from \"@moonsjs/core\";\nimport { resolveStaticFile, staticFileTarget } from \"./node-server\";\n\n/**\n * Addendum I: storage file sistem (default) untuk file prerender/ISR.\n * Read hanya melayani path yang benar-benar ada (manifest-aware);\n * write atomik (tmp + rename) dan membuat direktori bila perlu.\n */\nexport function createFileStorage(clientDir: string): PrerenderStorage {\n return {\n async read(pathname: string): Promise<PrerenderStorageEntry | null> {\n const file = resolveStaticFile(clientDir, pathname);\n if (file === null) {\n return null;\n }\n const stat = statSync(file);\n return { body: readFileSync(file), mtimeMs: stat.mtimeMs };\n },\n async write(pathname: string, body: Uint8Array): Promise<void> {\n const target = staticFileTarget(clientDir, pathname);\n if (target === null) {\n throw new Error(`[moons] isr: path
|
|
7
|
+
"import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { gzipSync } from \"node:zlib\";\nimport { createServer, type Server } from \"node:http\";\nimport { extname, join, resolve, sep } from \"node:path\";\nimport {\n DEFAULT_BODY_LIMIT_BYTES,\n MoonsError,\n trailingSlashRedirect,\n type PrerenderStorage,\n} from \"@moonsjs/core\";\nimport { revalidatePrerendered, shouldRevalidate } from \"./isr\";\nimport { contentTypeForPathname } from \"./storage\";\nimport {\n BodyLimitError,\n DEFAULT_SECURITY_HEADERS,\n InvalidRequestError,\n resolveClientIp,\n resolveRequestUrl,\n sendNodeResponse,\n toWebRequest,\n} from \"./node\";\nimport { createLogger, type Logger } from \"./logger\";\nimport type { PluginRuntime } from \"./plugins\";\nimport { installGracefulShutdown } from \"./shutdown\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".wasm\": \"application/wasm\",\n};\n\nexport interface NodeServerOptions {\n port?: number;\n clientDir?: string;\n /** Pasang handler SIGTERM/SIGINT (default true). */\n handleSignals?: boolean;\n /** Batas drain shutdown (default 10_000 ms). */\n shutdownTimeoutMs?: number;\n /** Lifecycle plugin (Addendum B.4) — onStart/onReady/onShutdown. */\n plugins?: PluginRuntime;\n /** Canary `leakTest.canary` untuk guard ISR (Addendum E.1). */\n canary?: string;\n /**\n * Header statis dari config (Addendum H). Diterapkan juga pada file\n * prerender yang disajikan langsung (static host memakai `_headers`).\n */\n headers?: Record<string, string>;\n /**\n * Storage bersama untuk file prerender (Addendum I, ISR multi-instance).\n * Bila diisi, penyajian file prerender dan penulisan hasil regenerasi\n * memakai storage ini; default: file sistem lokal.\n */\n storage?: PrerenderStorage;\n /** Addendum J.1: percayai `x-forwarded-proto`/`x-forwarded-host` (default false). */\n trustProxy?: boolean;\n /** Addendum J.2: batas body RPC di transport (default `DEFAULT_BODY_LIMIT_BYTES`). */\n bodyLimitBytes?: number;\n /** Addendum L.3: log akses terstruktur (default senyap). */\n logging?: { accessLog?: boolean; json?: boolean; redact?: string[] };\n /** Addendum M: kebijakan trailing slash (juga untuk path prerender/static). */\n trailingSlash?: \"never\" | \"always\";\n}\n\n/**\n * Serve produksi (M1 §19.2, §18): static dari `dist/client` + handler SSR.\n * Berjalan di Bun dan Node (hanya API `node:*`).\n */\nexport function startNodeServer(\n handler: (request: Request) => Promise<Response>,\n options: NodeServerOptions = {},\n): Server {\n const clientDir = resolve(options.clientDir ?? join(process.cwd(), \"dist/client\"));\n const port = options.port ?? Number(process.env[\"PORT\"] ?? 3000);\n\n const accessLogger: Logger | null =\n options.logging?.accessLog === true\n ? createLogger({\n json: options.logging.json !== false,\n redact: options.logging.redact ?? [],\n })\n : null;\n\n const server = createServer((req, res) => {\n const requestStartedAt = performance.now();\n if (accessLogger !== null) {\n res.once(\"finish\", () => {\n const ip = resolveClientIp(req, options.trustProxy === true);\n accessLogger({\n msg: \"request\",\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n status: res.statusCode,\n durationMs: Math.round(performance.now() - requestStartedAt),\n ...(ip === null ? {} : { ip }),\n });\n });\n }\n void (async () => {\n let url: URL;\n try {\n // Addendum J.1: URL/Origin mengikuti `x-forwarded-*` bila trustProxy aktif;\n // request malformed → 400 (bukan 500 + stack).\n url = resolveRequestUrl(req, { trustProxy: options.trustProxy === true });\n } catch (error) {\n if (error instanceof InvalidRequestError) {\n console.warn(`[moons] ${error.message} — 400`);\n respondBadRequest(res);\n return;\n }\n throw error;\n }\n\n try {\n // Addendum M: kanonikalisasi trailing slash di transport — mencakup\n // path prerender yang dilayani langsung (tidak lewat handler).\n if (options.trailingSlash !== undefined) {\n const canonical = trailingSlashRedirect(url.pathname, options.trailingSlash);\n if (canonical !== null) {\n url.pathname = canonical;\n res.statusCode = 308;\n res.setHeader(\"location\", url.toString());\n res.end();\n return;\n }\n }\n\n if (req.method === \"GET\" || req.method === \"HEAD\") {\n // Addendum I: storage bersama (bila dikonfigurasi) diutamakan.\n if (options.storage !== undefined) {\n const entry = await options.storage.read(url.pathname);\n if (entry !== null) {\n scheduleRevalidation({\n pathname: url.pathname,\n mtimeMs: entry.mtimeMs,\n storage: options.storage,\n handler,\n options,\n clientDir,\n logger: accessLogger,\n });\n res.statusCode = 200;\n res.setHeader(\"content-type\", contentTypeForPathname(url.pathname));\n applyStaticHeaders(res, url.pathname, options.headers);\n res.end(req.method === \"HEAD\" ? undefined : Buffer.from(entry.body));\n return;\n }\n // L.2 (temuan F1): storage MISS → jatuh ke file `dist/client`\n // (aset/non-ISR); storage tetap menang untuk path yang dimilikinya.\n }\n {\n const staticFile = resolveStaticFile(clientDir, url.pathname);\n if (staticFile !== null) {\n scheduleRevalidation({\n pathname: url.pathname,\n mtimeMs: statSync(staticFile).mtimeMs,\n file: staticFile,\n // Bila storage dikonfigurasi, hasil regenerasi (walau fallback\n // dari file) tetap ditulis ke storage bersama (L.2).\n ...(options.storage === undefined ? {} : { storage: options.storage }),\n handler,\n options,\n clientDir,\n logger: accessLogger,\n });\n const body = readFileSync(staticFile);\n const stat = statSync(staticFile);\n res.statusCode = 200;\n res.setHeader(\"content-type\", MIME_TYPES[extname(staticFile).toLowerCase()] ?? \"application/octet-stream\");\n applyStaticHeaders(res, url.pathname, options.headers);\n\n // Addendum K.5: ETag + 304.\n const etag = `W/\"${stat.size}-${Math.floor(stat.mtimeMs)}\"`;\n res.setHeader(\"etag\", etag);\n const ifNoneMatch = req.headers[\"if-none-match\"];\n if (\n typeof ifNoneMatch === \"string\" &&\n ifNoneMatch.split(\",\").some((value) => value.trim() === etag)\n ) {\n res.statusCode = 304;\n res.end();\n return;\n }\n\n // Addendum K.5: gzip untuk aset teks (cache per mtime).\n let payload: Buffer = body;\n if (\n req.method === \"GET\" &&\n COMPRESSIBLE_FILE.test(staticFile) &&\n body.byteLength >= GZIP_MIN_BYTES &&\n acceptsGzip(req)\n ) {\n payload = gzipCached(staticFile, stat.mtimeMs, body);\n res.setHeader(\"content-encoding\", \"gzip\");\n appendVary(res, \"accept-encoding\");\n }\n res.end(req.method === \"HEAD\" ? undefined : payload);\n return;\n }\n }\n }\n\n // Addendum J.2: batas body RPC ditegakkan di transport — lebih awal dari\n // pipeline, tanpa membaca penuh; `content-length` diperiksa lebih dulu.\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n const rpcLimit = options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES;\n if (isRpc) {\n const contentLength = Number(req.headers[\"content-length\"] ?? \"0\");\n if (Number.isFinite(contentLength) && contentLength > rpcLimit) {\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(rpcBodyTooLargeText(rpcLimit, contentLength));\n res.once(\"finish\", () => req.destroy());\n return;\n }\n }\n\n const request = await toWebRequest(req, {\n trustProxy: options.trustProxy === true,\n ...(isRpc ? { maxBodyBytes: rpcLimit } : {}),\n });\n const response = await handler(request);\n await sendNodeResponse(res, response);\n } catch (error) {\n if (error instanceof BodyLimitError) {\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(isRpc ? rpcBodyTooLargeText(error.limit, null) : \"Payload Too Large\");\n // Sisa body tidak perlu dibaca — putuskan setelah respons terkirim.\n res.once(\"finish\", () => req.destroy());\n return;\n }\n console.error(\"[moons] server error:\", error);\n res.statusCode = 500;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Internal Server Error\");\n }\n })();\n });\n\n // Addendum B.4: onStart sebelum listen, onReady setelah listen.\n const listenAfterStart = (): void => {\n server.listen(port, () => {\n const address = server.address();\n const boundPort = typeof address === \"object\" && address !== null ? address.port : port;\n console.log(`[moons] server listening on http://localhost:${boundPort}`);\n void options.plugins?.ready();\n });\n };\n if (options.plugins !== undefined) {\n void options.plugins.start().then(listenAfterStart);\n } else {\n listenAfterStart();\n }\n\n if (options.handleSignals !== false) {\n const shutdown = installGracefulShutdown(server, {\n ...(options.shutdownTimeoutMs === undefined ? {} : { timeoutMs: options.shutdownTimeoutMs }),\n ...(options.plugins === undefined\n ? {}\n : { onShutdown: () => options.plugins?.shutdown() }),\n });\n // `once`: sinyal kedua memakai perilaku default (proses langsung berhenti).\n process.once(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n process.once(\"SIGINT\", () => shutdown(\"SIGINT\"));\n }\n\n return server;\n}\n\n/**\n * Addendum J.7: header konfigurasi (menang), default aman, dan\n * `Cache-Control: immutable` untuk aset ber-hash di `/assets/*`.\n */\nfunction applyStaticHeaders(\n res: import(\"node:http\").ServerResponse,\n pathname: string,\n configured: Record<string, string> | undefined,\n): void {\n for (const [name, value] of Object.entries(configured ?? {})) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n for (const [name, value] of Object.entries(DEFAULT_SECURITY_HEADERS)) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n if (pathname.startsWith(\"/assets/\") && !res.hasHeader(\"cache-control\")) {\n res.setHeader(\"cache-control\", \"public, max-age=31536000, immutable\");\n }\n}\n\nconst COMPRESSIBLE_FILE = /\\.(js|mjs|css|html|json|svg|txt|map|xml)$/i;\nconst GZIP_MIN_BYTES = 1024;\nconst GZIP_CACHE_MAX = 64;\nconst gzipCache = new Map<string, { mtimeMs: number; gzip: Buffer }>();\n\nfunction acceptsGzip(req: import(\"node:http\").IncomingMessage): boolean {\n const header = req.headers[\"accept-encoding\"];\n if (typeof header !== \"string\") {\n return false;\n }\n return header\n .toLowerCase()\n .split(\",\")\n .map((part) => part.trim())\n .some((part) => part === \"gzip\" || part === \"*\" || part.startsWith(\"gzip;\"));\n}\n\n/** Varian gzip ter-cache per file+mtime (bounded FIFO) — Addendum K.5. */\nfunction gzipCached(file: string, mtimeMs: number, body: Buffer): Buffer {\n const cached = gzipCache.get(file);\n if (cached !== undefined && cached.mtimeMs === mtimeMs) {\n return cached.gzip;\n }\n const gzip = gzipSync(body);\n if (gzipCache.size >= GZIP_CACHE_MAX) {\n const oldest = gzipCache.keys().next().value;\n if (oldest !== undefined) {\n gzipCache.delete(oldest);\n }\n }\n gzipCache.set(file, { mtimeMs, gzip });\n return gzip;\n}\n\nfunction appendVary(res: import(\"node:http\").ServerResponse, value: string): void {\n const existing = res.getHeader(\"vary\");\n if (typeof existing === \"string\" && existing.length > 0) {\n if (!existing.toLowerCase().includes(value)) {\n res.setHeader(\"vary\", `${existing}, ${value}`);\n }\n return;\n }\n res.setHeader(\"vary\", value);\n}\n\nfunction respondBadRequest(res: import(\"node:http\").ServerResponse): void {\n res.statusCode = 400;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Bad Request\");\n}\n\n/** 413 transport dengan format §15 yang sama seperti `rpc.ts` (Addendum J.2). */\nfunction rpcBodyTooLargeText(limit: number, size: number | null): string {\n const megabytes = (bytes: number): string => (bytes / 1_000_000).toFixed(1);\n return new MoonsError({\n code: \"E_RPC_BODY_TOO_LARGE\",\n message:\n size === null\n ? `body exceeds the ${megabytes(limit)} MB limit`\n : `body ${megabytes(size)} MB exceeds the ${megabytes(limit)} MB limit`,\n details:\n \"Body exceeds `security.bodyLimitBytes`; reading stops at the transport before the body is fully buffered.\",\n suggestions: [\n \"Reduce the payload size, or\",\n \"Increase security.bodyLimitBytes if you really need to\",\n ],\n }).format();\n}\n\n/** Resolve file static dengan proteksi path traversal (+ manifest prerender D.5). */\nexport function resolveStaticFile(clientDir: string, pathname: string): string | null {\n const target = staticFileTarget(clientDir, pathname);\n return target !== null && isFile(target) ? target : null;\n}\n\n/**\n * Target file untuk `pathname` (tanpa cek keberadaan) — dipakai penyajian,\n * `createFileStorage().write`, dan test. Proteksi path traversal tetap.\n */\nexport function staticFileTarget(clientDir: string, pathname: string): string | null {\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return null;\n }\n\n // 1) File persis (aset: js/css/png/…, atau HTML yang diminta eksplisit).\n const exact = safeWithin(clientDir, `.${decoded}`);\n if (exact !== null && isFile(exact)) {\n return exact;\n }\n\n // 2) Hasil prerender: hanya path yang tercatat di manifest yang dilayani\n // statis — bukan shell `index.html` biasa (yang berarti bypass SSR).\n const normalized = decoded.length > 1 ? decoded.replace(/\\/+$/, \"\") : decoded;\n const manifest = readPrerenderManifest(clientDir);\n if (manifest.paths.has(normalized)) {\n const target = normalized === \"/\" ? \"index.html\" : `${normalized.slice(1)}/index.html`;\n return safeWithin(clientDir, `./${target}`);\n }\n\n return null;\n}\n\nfunction safeWithin(clientDir: string, relative: string): string | null {\n const candidate = resolve(clientDir, relative);\n if (candidate !== clientDir && !candidate.startsWith(clientDir + sep)) {\n return null;\n }\n return candidate;\n}\n\nfunction isFile(path: string): boolean {\n return existsSync(path) && statSync(path).isFile();\n}\n\nexport interface PrerenderManifestInfo {\n paths: Set<string>;\n revalidate: Map<string, number>;\n}\n\nlet prerenderManifestCache:\n | { file: string; mtimeMs: number; info: PrerenderManifestInfo }\n | null = null;\n\nfunction readPrerenderManifest(clientDir: string): PrerenderManifestInfo {\n const file = join(clientDir, \"_moons_prerender.json\");\n const empty: PrerenderManifestInfo = { paths: new Set(), revalidate: new Map() };\n try {\n const mtimeMs = statSync(file).mtimeMs;\n if (\n prerenderManifestCache !== null &&\n prerenderManifestCache.file === file &&\n prerenderManifestCache.mtimeMs === mtimeMs\n ) {\n return prerenderManifestCache.info;\n }\n const json = JSON.parse(readFileSync(file, \"utf8\")) as {\n paths?: unknown;\n version?: unknown;\n entries?: unknown;\n };\n const paths = new Set<string>();\n const revalidate = new Map<string, number>();\n if (Array.isArray(json.paths)) {\n // Manifest v1 (D.5) — tanpa revalidate.\n for (const path of json.paths) {\n if (typeof path === \"string\") {\n paths.add(path);\n }\n }\n }\n if (Array.isArray(json.entries)) {\n // Manifest v2 (E.1).\n for (const entry of json.entries as Array<Record<string, unknown>>) {\n if (entry === null || typeof entry !== \"object\" || typeof entry[\"path\"] !== \"string\") {\n continue;\n }\n const path = entry[\"path\"] as string;\n paths.add(path);\n const seconds = entry[\"revalidate\"];\n if (typeof seconds === \"number\" && Number.isFinite(seconds) && seconds >= 0) {\n revalidate.set(path, seconds);\n }\n }\n }\n const info = { paths, revalidate };\n prerenderManifestCache = { file, mtimeMs, info };\n return info;\n } catch {\n return empty;\n }\n}\n\n/** ISR: jika file prerender kedaluwarsa, regenerasi background (SWR). */\nfunction scheduleRevalidation(input: {\n pathname: string;\n mtimeMs: number;\n file?: string;\n storage?: PrerenderStorage;\n handler: (request: Request) => Promise<Response>;\n options: NodeServerOptions;\n clientDir: string;\n logger?: Logger | null;\n}): void {\n const normalized = input.pathname.length > 1 ? input.pathname.replace(/\\/+$/, \"\") : input.pathname;\n const seconds = readPrerenderManifest(input.clientDir).revalidate.get(normalized);\n if (seconds === undefined || seconds < 0) {\n return;\n }\n if (!shouldRevalidate({ mtimeMs: input.mtimeMs, revalidateSeconds: seconds })) {\n return;\n }\n const regeneratedAt = performance.now();\n const logger = input.logger ?? null;\n void revalidatePrerendered({\n pathname: normalized,\n ...(input.file === undefined ? {} : { file: input.file }),\n ...(input.storage === undefined ? {} : { storage: input.storage }),\n handler: input.handler,\n ...(input.options.canary === undefined ? {} : { canary: input.options.canary }),\n env: process.env,\n })\n .then(() => {\n logger?.({\n msg: \"isr:regenerated\",\n path: normalized,\n durationMs: Math.round(performance.now() - regeneratedAt),\n });\n })\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n if (logger !== null) {\n logger({ msg: \"isr:revalidate-failed\", level: \"warn\", path: normalized, error: message });\n } else {\n console.error(`[moons] isr regeneration failed (${normalized}): ${message}`);\n }\n });\n}\n\n",
|
|
8
|
+
"import { renameSync, writeFileSync } from \"node:fs\";\nimport type { PrerenderStorage } from \"@moonsjs/core\";\nimport { scanPayloadForSecrets } from \"../payload-scan\";\n\n/**\n * ISR / revalidate on-demand (PRD Addendum E.1): file prerender yang kedaluwarsa\n * disajikan apa adanya (stale-while-revalidate) sambil diregenerasi via handler\n * SSR in-process. Tulis atomik + guard kebocoran fail-closed.\n */\nexport function shouldRevalidate(input: {\n mtimeMs: number;\n revalidateSeconds: number;\n now?: number;\n}): boolean {\n const now = input.now ?? Date.now();\n return now - input.mtimeMs >= input.revalidateSeconds * 1000;\n}\n\nexport interface RevalidateOptions {\n /** Path URL ternormalisasi (mis. \"/blog/hello\"). */\n pathname: string;\n /** File HTML yang akan ditimpa (default file storage). */\n file?: string;\n /**\n * Storage alternatif (Addendum I). Bila diisi, `file` diabaikan dan hasil\n * regenerasi ditulis lewat `storage.write(pathname, body)`.\n */\n storage?: PrerenderStorage;\n handler: (request: Request) => Promise<Response>;\n canary?: string;\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n}\n\nconst inflight = new Map<string, Promise<void>>();\n\n/** Regenerasi ter-dedupe per path (panggilan paralel berbagi promise). */\nexport function revalidatePrerendered(options: RevalidateOptions): Promise<void> {\n const existing = inflight.get(options.pathname);\n if (existing !== undefined) {\n return existing;\n }\n const task = runRevalidate(options).finally(() => {\n inflight.delete(options.pathname);\n });\n inflight.set(options.pathname, task);\n return task;\n}\n\nasync function runRevalidate(options: RevalidateOptions): Promise<void> {\n const log = options.log ?? ((message: string) => console.log(message));\n try {\n const response = await options.handler(\n new Request(`http://localhost${options.pathname}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n if (response.status !== 200) {\n log(`[moons] isr: skipped ${options.pathname} (status ${response.status})`);\n return;\n }\n const html = await response.text();\n const findings = scanPayloadForSecrets(html, {\n ...(options.canary === undefined ? {} : { canary: options.canary }),\n env: options.env ?? process.env,\n });\n if (findings.length > 0) {\n const labels = findings\n .map((finding) => (finding.kind === \"canary\" ? \"canary\" : `env(${finding.label})`))\n .join(\", \");\n // Fail-closed: tidak menimpa file statis dengan konten bocor.\n log(`[moons] isr: NOT writing ${options.pathname} — contains ${labels}`);\n return;\n }\n if (options.storage !== undefined) {\n await options.storage.write(options.pathname, new TextEncoder().encode(html));\n return;\n }\n if (options.file === undefined) {\n log(`[moons] isr: skipped ${options.pathname} — no destination file/storage`);\n return;\n }\n const tmp = `${options.file}.tmp-${process.pid}`;\n writeFileSync(tmp, html);\n renameSync(tmp, options.file);\n } catch (error) {\n log(`[moons] isr: failed to regenerate ${options.pathname}: ${String(error)}`);\n }\n}\n\n/** Test helper: bersihkan dedupe in-flight. */\nexport function __resetIsrInflight(): void {\n inflight.clear();\n}\n",
|
|
9
|
+
"import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, extname } from \"node:path\";\nimport type { PrerenderStorage, PrerenderStorageEntry } from \"@moonsjs/core\";\nimport { resolveStaticFile, staticFileTarget } from \"./node-server\";\n\n/**\n * Addendum I: storage file sistem (default) untuk file prerender/ISR.\n * Read hanya melayani path yang benar-benar ada (manifest-aware);\n * write atomik (tmp + rename) dan membuat direktori bila perlu.\n */\nexport function createFileStorage(clientDir: string): PrerenderStorage {\n return {\n async read(pathname: string): Promise<PrerenderStorageEntry | null> {\n const file = resolveStaticFile(clientDir, pathname);\n if (file === null) {\n return null;\n }\n const stat = statSync(file);\n return { body: readFileSync(file), mtimeMs: stat.mtimeMs };\n },\n async write(pathname: string, body: Uint8Array): Promise<void> {\n const target = staticFileTarget(clientDir, pathname);\n if (target === null) {\n throw new Error(`[moons] isr: invalid path to write: ${pathname}`);\n }\n mkdirSync(dirname(target), { recursive: true });\n const tmp = `${target}.tmp-${process.pid}`;\n writeFileSync(tmp, body);\n renameSync(tmp, target);\n },\n };\n}\n\n/** Ekstensi pathname (untuk `content-type`) tanpa membaca storage. */\nexport function contentTypeForPathname(pathname: string): string {\n const ext = extname(pathname.split(\"?\")[0] ?? \"\").toLowerCase();\n return MIME[ext] ?? MIME[\".html\"] ?? \"text/html; charset=utf-8\";\n}\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".png\": \"image/png\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n",
|
|
10
10
|
"/**\n * Addendum L.3: logger akses terstruktur — JSON default, redaksi nilai\n * query-param (mis. `?token=…`), dan target tulis injectable (untuk test).\n * Semua field tambahan diteruskan apa adanya; `path` selalu di-redaksi.\n */\nexport interface LogEvent {\n /** Default `info`. */\n level?: \"info\" | \"warn\" | \"error\";\n /** Nama event, mis. `request` atau `isr:regenerated`. */\n msg: string;\n [field: string]: unknown;\n}\n\nexport interface LoggerOptions {\n /** Default `true` (JSON). `false` = teks ringkas. */\n json?: boolean;\n /** Nama query-param yang nilainya diganti `[redacted]`. */\n redact?: readonly string[];\n /** Tujuan tulis; default `console.log`. */\n write?: (line: string) => void;\n}\n\nexport type Logger = (event: LogEvent) => void;\n\n/** Ganti nilai query-param bernama `redact` menjadi `[redacted]`. */\nexport function redactPath(path: string, redact: readonly string[]): string {\n if (redact.length === 0 || !path.includes(\"?\")) {\n return path;\n }\n const index = path.indexOf(\"?\");\n const pathname = path.slice(0, index);\n const params = new URLSearchParams(path.slice(index + 1));\n let changed = false;\n for (const name of redact) {\n if (params.has(name)) {\n params.set(name, \"[redacted]\");\n changed = true;\n }\n }\n return changed ? `${pathname}?${params.toString()}` : path;\n}\n\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const json = options.json !== false;\n const redact = options.redact ?? [];\n const write = options.write ?? ((line: string): void => console.log(line));\n\n return (event) => {\n const fields: Record<string, unknown> = { level: \"info\", ...event };\n if (typeof fields[\"path\"] === \"string\") {\n fields[\"path\"] = redactPath(fields[\"path\"], redact);\n }\n if (json) {\n write(JSON.stringify({ time: new Date().toISOString(), ...fields }));\n return;\n }\n const parts = [\"[moons]\", String(fields[\"level\"]).toUpperCase(), String(fields[\"msg\"])];\n if (fields[\"path\"] !== undefined) {\n parts.push(String(fields[\"path\"]));\n }\n if (fields[\"status\"] !== undefined) {\n parts.push(String(fields[\"status\"]));\n }\n if (fields[\"durationMs\"] !== undefined) {\n parts.push(`${String(fields[\"durationMs\"])}ms`);\n }\n write(parts.join(\" \"));\n };\n}\n",
|
|
11
|
-
"import type { Server } from \"node:http\";\n\nexport interface ShutdownOptions {\n /** Batas drain sebelum keluar paksa (default 10_000 ms). */\n timeoutMs?: number;\n log?: (message: string) => void;\n /** Injectable untuk test; default `process.exit`. */\n exit?: (code: number) => void;\n /**\n * Dipanggil setelah drain penuh, sebelum exit (Addendum B.4: onShutdown\n * plugin). Berbagi batas waktu dengan drain; error dilaporkan, tidak\n * menggagalkan shutdown.\n */\n onShutdown?: () => void | Promise<void>;\n}\n\n/**\n * Graceful shutdown (PRD §19.5): SIGTERM/SIGINT → stop menerima koneksi baru →\n * drain request berjalan → exit 0. Melewati timeout → keluar paksa exit 1.\n *\n * Handler dipasang `once` oleh pemanggil, sehingga sinyal kedua memakai\n * perilaku default (proses langsung berhenti).\n */\nexport function installGracefulShutdown(\n server: Server,\n options: ShutdownOptions = {},\n): (signal: NodeJS.Signals) => void {\n const timeoutMs = options.timeoutMs ?? 10_000;\n const log = options.log ?? ((message: string) => console.log(message));\n const exit = options.exit ?? ((code: number) => process.exit(code));\n\n let shuttingDown = false;\n\n return (signal: NodeJS.Signals): void => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n log(`[moons]
|
|
12
|
-
"import type { MoonsConfig, RouteDefinition, RouteModule } from \"@moonsjs/core\";\nimport { createRequestHandler } from \"./handler\";\nimport { DEFAULT_TEMPLATE, injectShell, type Shell } from \"./shell\";\n\nexport interface TestServerOptions {\n routes: RouteDefinition[];\n config: MoonsConfig;\n routesDir: string;\n loadRoute: Record<string, () => Promise<RouteModule>>;\n /** Default: shell in-memory dari `DEFAULT_TEMPLATE` (tanpa file). */\n shell?: Shell;\n}\n\nexport interface TestServer {\n handler: (request: Request) => Promise<Response>;\n /** Dispatch request langsung ke handler — tanpa port/jaringan (§19.5). */\n fetch(input: string, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Utility test in-process (PRD §19.5): jalankan handler tanpa listen port.\n * Dipakai test aplikasi user maupun test internal framework.\n */\nexport function createTestServer(\n options: TestServerOptions,\n baseUrl = \"http://localhost\",\n): TestServer {\n const shell: Shell =\n options.shell ??\n ((markup, payload, _url, meta) => injectShell(DEFAULT_TEMPLATE, markup, payload, meta));\n\n const handler = createRequestHandler({\n routes: options.routes,\n config: options.config,\n routesDir: options.routesDir,\n loadRoute: options.loadRoute,\n shell,\n });\n\n return {\n handler,\n fetch: (input: string, init?: RequestInit) =>\n handler(new Request(new URL(input, baseUrl), init)),\n };\n}\n",
|
|
13
|
-
"import { MOONS_VERSION, type App, type Middleware, type MoonsConfig, type RouteDefinition } from \"@moonsjs/core\";\n\n/**\n * Eksekusi lifecycle plugin (PRD §14.4 / Addendum B.4).\n * Urutan: registrasi (addRoute per route → addMiddleware per middleware →\n * extendContext(register)) → onStart → ready/onReady → shutdown/onShutdown.\n */\nexport interface PluginRuntime {\n readonly app: App;\n /** Registrasi + `onStart` (sebelum server siap). */\n start(): Promise<void>;\n /** Tandai `app.ready = true` lalu panggil `onReady` (server siap). */\n ready(): Promise<void>;\n /** Panggil `onShutdown` (selama drain; error dilaporkan, tidak menggagalkan). */\n shutdown(): Promise<void>;\n /** Terapkan extender `extendContext` ke ctx request (dipanggil handler). */\n applyExtensions(ctx: unknown): void;\n}\n\nexport interface PluginRuntimeOptions {\n config: MoonsConfig;\n routes: RouteDefinition[];\n /** Rantai middleware final (config.middleware). */\n middlewares: Middleware[];\n log?: (message: string) => void;\n}\n\nexport function createPluginRuntime(options: PluginRuntimeOptions): PluginRuntime {\n const log = options.log ?? ((message: string) => console.warn(message));\n const plugins = options.config.plugins ?? [];\n const state = { ready: false, version: MOONS_VERSION };\n const app = state as App;\n const extensions: Array<(ctx: unknown) => unknown> = [];\n const register = (fn: (ctx: unknown) => unknown): void => {\n extensions.push(fn);\n };\n\n // Fase registrasi (sinkron): addRoute → addMiddleware → extendContext.\n for (const plugin of plugins) {\n for (const route of options.routes) {\n // Objek beku: hook bersifat observasi di v1 (lihat docs/decisions/0022).\n const frozen = Object.freeze({\n ...route,\n params: [...route.params],\n }) as RouteDefinition;\n plugin.addRoute?.(frozen);\n }\n for (const middleware of options.middlewares) {\n plugin.addMiddleware?.(middleware);\n }\n plugin.extendContext?.(register as never);\n }\n\n return {\n app,\n async start(): Promise<void> {\n for (const plugin of plugins) {\n await plugin.onStart?.(app);\n }\n },\n async ready(): Promise<void> {\n state.ready = true;\n for (const plugin of plugins) {\n await plugin.onReady?.(app);\n }\n },\n async shutdown(): Promise<void> {\n for (const plugin of plugins) {\n try {\n await plugin.onShutdown?.(app);\n } catch (error) {\n log(`[moons] plugin \\`${plugin.name}\\`
|
|
14
|
-
"import { MoonsError, type RouteDefinition, type RouteModule } from \"@moonsjs/core\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { scanPayloadForSecrets } from \"../payload-scan\";\n\n/**\n * Prerender statis (PRD Addendum D.5): render route ber-`prerender = true`\n * saat build → `dist/client/<path>/index.html` (guard: payload scan fail-mode).\n */\n/** Addendum H: config statis yang ditulis saat prerender (deploy kit). */\nexport interface PrerenderStaticConfig {\n headers?: Record<string, string>;\n redirects?: Array<{ from: string; to: string; status?: number }>;\n sitemap?: { site: string; exclude?: string[] };\n robots?: { sitemap?: boolean; disallow?: string[] };\n}\n\nexport interface PrerenderOptions {\n routes: RouteDefinition[];\n routesDir: string;\n loadRoute: Record<string, () => Promise<RouteModule>>;\n /** Handler SSR yang sudah dibuat runtime (createRequestHandler). */\n handler: (request: Request) => Promise<Response>;\n /** Tujuan file statis (biasanya `<root>/dist/client`). */\n clientDir: string;\n canary?: string;\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n /** Addendum H: `headers`/`redirects`/`sitemap`/`robots` dari config. */\n staticConfig?: PrerenderStaticConfig;\n}\n\nexport interface PrerenderResult {\n written: number;\n skipped: number;\n}\n\n/**\n * Manifest path yang benar-benar di-prerender (dibaca static server agar hanya\n * file hasil prerender yang \"menang\" atas SSR — bukan shell index.html biasa).\n */\nexport const PRERENDER_MANIFEST_FILE = \"_moons_prerender.json\";\n\n/**\n * Addendum G: sentinel internal untuk merender halaman 404 statis. Path ini\n * tidak pernah menjadi route publik; handler merendernya seperti request tak\n * dikenal (route `_404` atau 404 bawaan).\n */\nexport const NOT_FOUND_SENTINEL = \"/_moons/404\";\n\n/** Addendum G: nama file 404 untuk static host (konvensi Cloudflare Pages/Netlify). */\nexport const NOT_FOUND_FILE = \"404.html\";\n\nexport async function runPrerender(options: PrerenderOptions): Promise<PrerenderResult> {\n const log = options.log ?? ((message: string) => console.log(message));\n const env = options.env ?? process.env;\n let written = 0;\n let skipped = 0;\n const entries: Array<{ path: string; revalidate?: number }> = [];\n\n const pages = options.routes.filter((route) => route.kind === \"page\");\n for (const route of pages) {\n const key = routeKeyOf(options.routesDir, route.file);\n const load = options.loadRoute[key];\n if (load === undefined) {\n continue;\n }\n const module = (await load()) as RouteModule;\n const prerender = module.prerender;\n const revalidate = module.revalidate;\n\n // Addendum E.1: `revalidate` hanya sah bersama `prerender`.\n if (revalidate !== undefined) {\n if (\n typeof revalidate !== \"number\" ||\n !Number.isFinite(revalidate) ||\n revalidate < 0 ||\n prerender !== true\n ) {\n throw new MoonsError({\n code: \"E_ISR_INVALID\",\n file: route.file,\n message: \"`revalidate` tidak valid atau dipakai tanpa `prerender = true`\",\n details: \"ISR berbasis file: `revalidate` (detik, number >= 0) + `prerender`.\",\n suggestions: [\n \"Gunakan angka detik, mis. `export const revalidate = 60`\",\n \"Tambahkan `export const prerender = true` pada page yang sama\",\n ],\n });\n }\n }\n\n if (prerender !== true) {\n if (prerender !== undefined && prerender !== false) {\n throw prerenderError(route, \"`prerender` harus boolean (`true`/`false`)\");\n }\n continue;\n }\n\n const pathnames = await resolvePathnames(route, module);\n for (const pathname of pathnames) {\n const response = await options.handler(\n new Request(`http://localhost${pathname}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n\n if (response.status === 404) {\n log(`[moons] prerender: lewati ${pathname} (notFound)`);\n skipped += 1;\n continue;\n }\n if (response.status >= 300 && response.status < 400) {\n throw prerenderError(route, `\\`redirect()\\` tidak didukung saat prerender (${pathname})`);\n }\n if (response.status !== 200) {\n throw prerenderError(route, `status ${response.status} saat merender ${pathname}`);\n }\n\n const html = await response.text();\n assertNoLeak(html, pathname, route.file, options, env);\n\n const file = outputFile(options.clientDir, pathname);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, html);\n entries.push(\n typeof revalidate === \"number\" && revalidate >= 0\n ? { path: pathname, revalidate }\n : { path: pathname },\n );\n written += 1;\n }\n }\n\n // Addendum G: `404.html` untuk static host, bila app punya route `_404`.\n const notFound = await renderStaticNotFound(options, env, log);\n let wrote404 = false;\n if (notFound !== null) {\n writeFileSync(join(options.clientDir, NOT_FOUND_FILE), notFound);\n wrote404 = true;\n }\n\n // Manifest v2 (Addendum E.1): entries + revalidate; reader tetap menerima v1.\n writeFileSync(\n join(options.clientDir, PRERENDER_MANIFEST_FILE),\n `${JSON.stringify({ version: 2, entries }, null, 2)}\\n`,\n );\n\n // Addendum H: deploy kit statis (headers/redirects/sitemap/robots).\n const emitted = emitStaticFiles(options.clientDir, options.staticConfig, entries);\n\n const extras = [...(wrote404 ? [NOT_FOUND_FILE] : []), ...emitted];\n log(\n `[moons] prerender selesai: ${written} file${extras.length > 0 ? ` + ${extras.join(\" + \")}` : \"\"} (${skipped} dilewati)`,\n );\n return { written, skipped };\n}\n\n/** Tulis file deploy statis dari config; mengembalikan nama file yang ditulis. */\nfunction emitStaticFiles(\n clientDir: string,\n staticConfig: PrerenderStaticConfig | undefined,\n entries: Array<{ path: string }>,\n): string[] {\n if (staticConfig === undefined) {\n return [];\n }\n const emitted: string[] = [];\n\n const headers = Object.entries(staticConfig.headers ?? {});\n if (headers.length > 0) {\n const lines = [\"/*\", ...headers.map(([name, value]) => ` ${name}: ${value}`)];\n writeFileSync(join(clientDir, \"_headers\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"_headers\");\n }\n\n const redirects = staticConfig.redirects ?? [];\n if (redirects.length > 0) {\n const lines = redirects.map((entry) => `${entry.from} ${entry.to} ${entry.status ?? 301}`);\n writeFileSync(join(clientDir, \"_redirects\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"_redirects\");\n }\n\n const sitemap = staticConfig.sitemap;\n if (sitemap !== undefined) {\n const site = sitemap.site.replace(/\\/$/, \"\");\n const exclude = sitemap.exclude ?? [];\n const paths = [...new Set(entries.map((entry) => entry.path))]\n .filter((path) => !exclude.some((prefix) => path.startsWith(prefix)))\n .sort();\n const xml = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ...paths.map((path) => ` <url><loc>${site}${path === \"/\" ? \"/\" : path}</loc></url>`),\n \"</urlset>\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(join(clientDir, \"sitemap.xml\"), xml);\n emitted.push(\"sitemap.xml\");\n }\n\n const robots = staticConfig.robots;\n if (robots !== undefined) {\n const lines = [\"User-agent: *\"];\n for (const path of robots.disallow ?? []) {\n lines.push(`Disallow: ${path}`);\n }\n if ((robots.sitemap ?? true) && sitemap !== undefined) {\n lines.push(\"\", `Sitemap: ${sitemap.site.replace(/\\/$/, \"\")}/sitemap.xml`);\n }\n writeFileSync(join(clientDir, \"robots.txt\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"robots.txt\");\n }\n\n return emitted;\n}\n\n/**\n * Addendum G: render halaman 404 ke `dist/client/404.html` (static export).\n * Ditulis hanya bila app memiliki route `_404` dan sentinel menghasilkan 404;\n * hasilnya tetap melewati guard kebocoran (fail-mode).\n */\nasync function renderStaticNotFound(\n options: PrerenderOptions,\n env: Record<string, string | undefined>,\n log: (message: string) => void,\n): Promise<string | null> {\n if (!options.routes.some((route) => route.kind === \"404\")) {\n return null;\n }\n const response = await options.handler(\n new Request(`http://localhost${NOT_FOUND_SENTINEL}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n if (response.status !== 404) {\n log(\n `[moons] prerender: ${NOT_FOUND_FILE} dilewati (sentinel \\`${NOT_FOUND_SENTINEL}\\` → ${response.status})`,\n );\n return null;\n }\n const html = await response.text();\n assertNoLeak(html, NOT_FOUND_SENTINEL, NOT_FOUND_FILE, options, env);\n return html;\n}\n\n/** Guard kebocoran fail-mode (Addendum D.5) — dipakai halaman & 404 statis. */\nfunction assertNoLeak(\n html: string,\n pathname: string,\n file: string,\n options: PrerenderOptions,\n env: Record<string, string | undefined>,\n): void {\n const findings = scanPayloadForSecrets(html, {\n ...(options.canary === undefined ? {} : { canary: options.canary }),\n env,\n });\n if (findings.length === 0) {\n return;\n }\n const labels = findings\n .map((finding) => (finding.kind === \"canary\" ? \"canary\" : `env(${finding.label})`))\n .join(\", \");\n throw new MoonsError({\n code: \"E_PRERENDER_LEAK\",\n file,\n message: `hasil prerender \\`${pathname}\\` memuat ${labels}`,\n details: \"HTML statis permanen — rahasia yang ter-prerender tidak bisa ditarik kembali.\",\n suggestions: [\n \"Jangan mengembalikan nilai env rahasia dari loader yang di-prerender\",\n \"Matikan `prerender` untuk route ini atau pindahkan datanya ke serverFn request-time\",\n ],\n });\n}\n\nfunction routeKeyOf(routesDir: string, file: string): string {\n const relative = file.startsWith(routesDir) ? file.slice(routesDir.length + 1) : file;\n return relative.split(\"\\\\\").join(\"/\").replace(/\\.(tsx|ts)$/, \"\");\n}\n\nasync function resolvePathnames(route: RouteDefinition, module: RouteModule): Promise<string[]> {\n const isDynamic = route.params.length > 0;\n if (!isDynamic) {\n return [route.path];\n }\n const paths = module.paths;\n if (typeof paths !== \"function\") {\n throw new MoonsError({\n code: \"E_PRERENDER_NO_PATHS\",\n file: route.file,\n message: \"route dynamic ber-`prerender = true` tanpa `export const paths`\",\n details: \"Prerender butuh daftar param untuk merender tiap path.\",\n suggestions: [\n 'Tambahkan `export const paths = () => [{ id: \"…\" }]`',\n \"Atau hapus `prerender` agar dirender SSR saat request\",\n ],\n });\n }\n\n const raw = await (paths as () => unknown | Promise<unknown>)();\n if (!Array.isArray(raw)) {\n throw prerenderError(route, \"`paths()` harus mengembalikan array\");\n }\n\n const expected = new Set(route.params);\n const result: string[] = [];\n for (const item of raw as unknown[]) {\n if (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n throw prerenderError(route, \"item `paths()` harus objek param string\");\n }\n const record = item as Record<string, unknown>;\n const keys = Object.keys(record);\n for (const name of expected) {\n const value = record[name];\n if (typeof value !== \"string\" || value.length === 0) {\n throw prerenderError(route, `param \\`${name}\\` wajib string non-kosong`);\n }\n }\n for (const key of keys) {\n if (!expected.has(key)) {\n throw prerenderError(route, `param \\`${key}\\` tidak ada di pola route`);\n }\n }\n result.push(buildPathname(route, record as Record<string, string>));\n }\n return result;\n}\n\nfunction buildPathname(route: RouteDefinition, params: Record<string, string>): string {\n const segments = route.path.split(\"/\").filter((segment) => segment.length > 0);\n const out: string[] = [];\n let catchallName: string | null = null;\n for (const segment of segments) {\n if (segment === \"*\") {\n catchallName = route.params[route.params.length - 1] ?? null;\n const value = catchallName === null ? \"\" : (params[catchallName] ?? \"\");\n for (const part of value.split(\"/\")) {\n if (part.length === 0) {\n continue;\n }\n out.push(encodeSegment(route, part));\n }\n continue;\n }\n if (segment.startsWith(\":\")) {\n out.push(encodeSegment(route, params[segment.slice(1)] ?? \"\"));\n continue;\n }\n out.push(segment);\n }\n return `/${out.join(\"/\")}`;\n}\n\nfunction encodeSegment(route: RouteDefinition, value: string): string {\n if (value.length === 0 || /^\\.+$/.test(value)) {\n throw prerenderError(route, `nilai param \\`${value}\\` tidak valid untuk path file`);\n }\n return encodeURIComponent(value);\n}\n\nfunction outputFile(clientDir: string, pathname: string): string {\n const parts = pathname.split(\"/\").filter((part) => part.length > 0);\n const file = resolve(join(clientDir, ...parts, \"index.html\"));\n const base = resolve(clientDir);\n if (file !== base && !file.startsWith(base + sep)) {\n throw new MoonsError({\n code: \"E_PRERENDER_INVALID\",\n message: `path prerender keluar dari direktori client (\\`${pathname}\\`)`,\n details: \"Nama file harus berada di dalam `dist/client`.\",\n suggestions: [\"Periksa nilai param `paths` — jangan memakai `..`\"],\n });\n }\n return file;\n}\n\nfunction prerenderError(route: RouteDefinition, message: string): MoonsError {\n return new MoonsError({\n code: \"E_PRERENDER_INVALID\",\n file: route.file,\n message,\n details: \"Kontrak prerender mengikuti.\",\n suggestions: [\n \"Perbaiki bentuk `paths`/param agar cocok dengan pola route\",\n \"Jangan memakai `redirect()` pada route yang di-prerender\",\n ],\n });\n}\n"
|
|
11
|
+
"import type { Server } from \"node:http\";\n\nexport interface ShutdownOptions {\n /** Batas drain sebelum keluar paksa (default 10_000 ms). */\n timeoutMs?: number;\n log?: (message: string) => void;\n /** Injectable untuk test; default `process.exit`. */\n exit?: (code: number) => void;\n /**\n * Dipanggil setelah drain penuh, sebelum exit (Addendum B.4: onShutdown\n * plugin). Berbagi batas waktu dengan drain; error dilaporkan, tidak\n * menggagalkan shutdown.\n */\n onShutdown?: () => void | Promise<void>;\n}\n\n/**\n * Graceful shutdown (PRD §19.5): SIGTERM/SIGINT → stop menerima koneksi baru →\n * drain request berjalan → exit 0. Melewati timeout → keluar paksa exit 1.\n *\n * Handler dipasang `once` oleh pemanggil, sehingga sinyal kedua memakai\n * perilaku default (proses langsung berhenti).\n */\nexport function installGracefulShutdown(\n server: Server,\n options: ShutdownOptions = {},\n): (signal: NodeJS.Signals) => void {\n const timeoutMs = options.timeoutMs ?? 10_000;\n const log = options.log ?? ((message: string) => console.log(message));\n const exit = options.exit ?? ((code: number) => process.exit(code));\n\n let shuttingDown = false;\n\n return (signal: NodeJS.Signals): void => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n log(`[moons] received ${signal} — no longer accepting connections, draining...`);\n\n const timer = setTimeout(() => {\n log(`[moons] drain exceeded ${timeoutMs}ms — forcing exit`);\n const closeAll = (server as { closeAllConnections?: () => void }).closeAllConnections;\n try {\n closeAll?.call(server);\n } catch {\n // abaikan: keluar paksa tetap jalan\n }\n exit(1);\n }, timeoutMs);\n timer.unref?.();\n\n try {\n (server as { closeIdleConnections?: () => void }).closeIdleConnections?.();\n } catch {\n // abaikan: fallback timeout tetap ada\n }\n\n server.close(async (error?: Error) => {\n if (error !== undefined) {\n clearTimeout(timer);\n log(`[moons] server close failed: ${error.message}`);\n exit(1);\n return;\n }\n if (options.onShutdown !== undefined) {\n // Tetap berbagi batas waktu dengan drain: timer di-ref kembali agar\n // proses tidak keluar sebelum hook selesai.\n (timer as { ref?: () => void }).ref?.();\n try {\n await options.onShutdown();\n } catch (hookError) {\n log(`[moons] onShutdown failed: ${String(hookError)}`);\n }\n }\n clearTimeout(timer);\n log(\"[moons] shutdown complete (full drain)\");\n exit(0);\n });\n };\n}\n",
|
|
12
|
+
"import type { MoonsConfig, RouteDefinition, RouteModule } from \"@moonsjs/core\";\nimport { createRequestHandler, type RequestHandlerOptions } from \"./handler\";\nimport { DEFAULT_TEMPLATE, injectShell, type Shell } from \"./shell\";\n\nexport interface TestServerOptions {\n routes: RouteDefinition[];\n config: MoonsConfig;\n routesDir: string;\n loadRoute: Record<string, () => Promise<RouteModule>>;\n /** Endpoint `src/api` (Addendum O) — hasil scan app. */\n apiRoutes?: RequestHandlerOptions[\"apiRoutes\"];\n loadApi?: RequestHandlerOptions[\"loadApi\"];\n apiMiddlewares?: RequestHandlerOptions[\"apiMiddlewares\"];\n loadApiMiddleware?: RequestHandlerOptions[\"loadApiMiddleware\"];\n /** Default: shell in-memory dari `DEFAULT_TEMPLATE` (tanpa file). */\n shell?: Shell;\n}\n\nexport interface TestServer {\n handler: (request: Request) => Promise<Response>;\n /** Dispatch request langsung ke handler — tanpa port/jaringan (§19.5). */\n fetch(input: string, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Utility test in-process (PRD §19.5): jalankan handler tanpa listen port.\n * Dipakai test aplikasi user maupun test internal framework.\n */\nexport function createTestServer(\n options: TestServerOptions,\n baseUrl = \"http://localhost\",\n): TestServer {\n const shell: Shell =\n options.shell ??\n ((markup, payload, _url, meta) => injectShell(DEFAULT_TEMPLATE, markup, payload, meta));\n\n const handler = createRequestHandler({\n routes: options.routes,\n config: options.config,\n routesDir: options.routesDir,\n loadRoute: options.loadRoute,\n ...(options.apiRoutes === undefined ? {} : { apiRoutes: options.apiRoutes }),\n ...(options.loadApi === undefined ? {} : { loadApi: options.loadApi }),\n ...(options.apiMiddlewares === undefined ? {} : { apiMiddlewares: options.apiMiddlewares }),\n ...(options.loadApiMiddleware === undefined\n ? {}\n : { loadApiMiddleware: options.loadApiMiddleware }),\n shell,\n });\n\n return {\n handler,\n fetch: (input: string, init?: RequestInit) =>\n handler(new Request(new URL(input, baseUrl), init)),\n };\n}\n",
|
|
13
|
+
"import { MOONS_VERSION, type App, type Middleware, type MoonsConfig, type RouteDefinition } from \"@moonsjs/core\";\n\n/**\n * Eksekusi lifecycle plugin (PRD §14.4 / Addendum B.4).\n * Urutan: registrasi (addRoute per route → addMiddleware per middleware →\n * extendContext(register)) → onStart → ready/onReady → shutdown/onShutdown.\n */\nexport interface PluginRuntime {\n readonly app: App;\n /** Registrasi + `onStart` (sebelum server siap). */\n start(): Promise<void>;\n /** Tandai `app.ready = true` lalu panggil `onReady` (server siap). */\n ready(): Promise<void>;\n /** Panggil `onShutdown` (selama drain; error dilaporkan, tidak menggagalkan). */\n shutdown(): Promise<void>;\n /** Terapkan extender `extendContext` ke ctx request (dipanggil handler). */\n applyExtensions(ctx: unknown): void;\n}\n\nexport interface PluginRuntimeOptions {\n config: MoonsConfig;\n routes: RouteDefinition[];\n /** Rantai middleware final (config.middleware). */\n middlewares: Middleware[];\n log?: (message: string) => void;\n}\n\nexport function createPluginRuntime(options: PluginRuntimeOptions): PluginRuntime {\n const log = options.log ?? ((message: string) => console.warn(message));\n const plugins = options.config.plugins ?? [];\n const state = { ready: false, version: MOONS_VERSION };\n const app = state as App;\n const extensions: Array<(ctx: unknown) => unknown> = [];\n const register = (fn: (ctx: unknown) => unknown): void => {\n extensions.push(fn);\n };\n\n // Fase registrasi (sinkron): addRoute → addMiddleware → extendContext.\n for (const plugin of plugins) {\n for (const route of options.routes) {\n // Objek beku: hook bersifat observasi di v1 (lihat docs/decisions/0022).\n const frozen = Object.freeze({\n ...route,\n params: [...route.params],\n }) as RouteDefinition;\n plugin.addRoute?.(frozen);\n }\n for (const middleware of options.middlewares) {\n plugin.addMiddleware?.(middleware);\n }\n plugin.extendContext?.(register as never);\n }\n\n return {\n app,\n async start(): Promise<void> {\n for (const plugin of plugins) {\n await plugin.onStart?.(app);\n }\n },\n async ready(): Promise<void> {\n state.ready = true;\n for (const plugin of plugins) {\n await plugin.onReady?.(app);\n }\n },\n async shutdown(): Promise<void> {\n for (const plugin of plugins) {\n try {\n await plugin.onShutdown?.(app);\n } catch (error) {\n log(`[moons] plugin \\`${plugin.name}\\` failed during onShutdown: ${String(error)}`);\n }\n }\n },\n applyExtensions(ctx: unknown): void {\n for (const extend of extensions) {\n const result = extend(ctx);\n if (result !== null && typeof result === \"object\" && !Array.isArray(result)) {\n Object.assign(ctx as Record<string, unknown>, result);\n }\n }\n },\n };\n}\n",
|
|
14
|
+
"import { MoonsError, type RouteDefinition, type RouteModule } from \"@moonsjs/core\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { scanPayloadForSecrets } from \"../payload-scan\";\n\n/**\n * Prerender statis (PRD Addendum D.5): render route ber-`prerender = true`\n * saat build → `dist/client/<path>/index.html` (guard: payload scan fail-mode).\n */\n/** Addendum H: config statis yang ditulis saat prerender (deploy kit). */\nexport interface PrerenderStaticConfig {\n headers?: Record<string, string>;\n redirects?: Array<{ from: string; to: string; status?: number }>;\n sitemap?: { site: string; exclude?: string[] };\n robots?: { sitemap?: boolean; disallow?: string[] };\n}\n\nexport interface PrerenderOptions {\n routes: RouteDefinition[];\n routesDir: string;\n loadRoute: Record<string, () => Promise<RouteModule>>;\n /** Handler SSR yang sudah dibuat runtime (createRequestHandler). */\n handler: (request: Request) => Promise<Response>;\n /** Tujuan file statis (biasanya `<root>/dist/client`). */\n clientDir: string;\n canary?: string;\n env?: Record<string, string | undefined>;\n log?: (message: string) => void;\n /** Addendum H: `headers`/`redirects`/`sitemap`/`robots` dari config. */\n staticConfig?: PrerenderStaticConfig;\n}\n\nexport interface PrerenderResult {\n written: number;\n skipped: number;\n}\n\n/**\n * Manifest path yang benar-benar di-prerender (dibaca static server agar hanya\n * file hasil prerender yang \"menang\" atas SSR — bukan shell index.html biasa).\n */\nexport const PRERENDER_MANIFEST_FILE = \"_moons_prerender.json\";\n\n/**\n * Addendum G: sentinel internal untuk merender halaman 404 statis. Path ini\n * tidak pernah menjadi route publik; handler merendernya seperti request tak\n * dikenal (route `_404` atau 404 bawaan).\n */\nexport const NOT_FOUND_SENTINEL = \"/_moons/404\";\n\n/** Addendum G: nama file 404 untuk static host (konvensi Cloudflare Pages/Netlify). */\nexport const NOT_FOUND_FILE = \"404.html\";\n\nexport async function runPrerender(options: PrerenderOptions): Promise<PrerenderResult> {\n const log = options.log ?? ((message: string) => console.log(message));\n const env = options.env ?? process.env;\n let written = 0;\n let skipped = 0;\n const entries: Array<{ path: string; revalidate?: number }> = [];\n\n const pages = options.routes.filter((route) => route.kind === \"page\");\n for (const route of pages) {\n const key = routeKeyOf(options.routesDir, route.file);\n const load = options.loadRoute[key];\n if (load === undefined) {\n continue;\n }\n const module = (await load()) as RouteModule;\n const prerender = module.prerender;\n const revalidate = module.revalidate;\n\n // Addendum E.1: `revalidate` hanya sah bersama `prerender`.\n if (revalidate !== undefined) {\n if (\n typeof revalidate !== \"number\" ||\n !Number.isFinite(revalidate) ||\n revalidate < 0 ||\n prerender !== true\n ) {\n throw new MoonsError({\n code: \"E_ISR_INVALID\",\n file: route.file,\n message: \"`revalidate` is invalid or used without `prerender = true`\",\n details: \"File-based ISR: `revalidate` (seconds, number >= 0) + `prerender`.\",\n suggestions: [\n \"Use a number of seconds, e.g. `export const revalidate = 60`\",\n \"Add `export const prerender = true` to the same page\",\n ],\n });\n }\n }\n\n if (prerender !== true) {\n if (prerender !== undefined && prerender !== false) {\n throw prerenderError(route, \"`prerender` must be a boolean (`true`/`false`)\");\n }\n continue;\n }\n\n const pathnames = await resolvePathnames(route, module);\n for (const pathname of pathnames) {\n const response = await options.handler(\n new Request(`http://localhost${pathname}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n\n if (response.status === 404) {\n log(`[moons] prerender: skipped ${pathname} (notFound)`);\n skipped += 1;\n continue;\n }\n if (response.status >= 300 && response.status < 400) {\n throw prerenderError(route, `\\`redirect()\\` is not supported during prerender (${pathname})`);\n }\n if (response.status !== 200) {\n throw prerenderError(route, `status ${response.status} while rendering ${pathname}`);\n }\n\n const html = await response.text();\n assertNoLeak(html, pathname, route.file, options, env);\n\n const file = outputFile(options.clientDir, pathname);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, html);\n entries.push(\n typeof revalidate === \"number\" && revalidate >= 0\n ? { path: pathname, revalidate }\n : { path: pathname },\n );\n written += 1;\n }\n }\n\n // Addendum G: `404.html` untuk static host, bila app punya route `_404`.\n const notFound = await renderStaticNotFound(options, env, log);\n let wrote404 = false;\n if (notFound !== null) {\n writeFileSync(join(options.clientDir, NOT_FOUND_FILE), notFound);\n wrote404 = true;\n }\n\n // Manifest v2 (Addendum E.1): entries + revalidate; reader tetap menerima v1.\n writeFileSync(\n join(options.clientDir, PRERENDER_MANIFEST_FILE),\n `${JSON.stringify({ version: 2, entries }, null, 2)}\\n`,\n );\n\n // Addendum H: deploy kit statis (headers/redirects/sitemap/robots).\n const emitted = emitStaticFiles(options.clientDir, options.staticConfig, entries);\n\n const extras = [...(wrote404 ? [NOT_FOUND_FILE] : []), ...emitted];\n log(\n `[moons] prerender done: ${written} file${extras.length > 0 ? ` + ${extras.join(\" + \")}` : \"\"} (${skipped} skipped)`,\n );\n return { written, skipped };\n}\n\n/** Tulis file deploy statis dari config; mengembalikan nama file yang ditulis. */\nfunction emitStaticFiles(\n clientDir: string,\n staticConfig: PrerenderStaticConfig | undefined,\n entries: Array<{ path: string }>,\n): string[] {\n if (staticConfig === undefined) {\n return [];\n }\n const emitted: string[] = [];\n\n const headers = Object.entries(staticConfig.headers ?? {});\n if (headers.length > 0) {\n const lines = [\"/*\", ...headers.map(([name, value]) => ` ${name}: ${value}`)];\n writeFileSync(join(clientDir, \"_headers\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"_headers\");\n }\n\n const redirects = staticConfig.redirects ?? [];\n if (redirects.length > 0) {\n const lines = redirects.map((entry) => `${entry.from} ${entry.to} ${entry.status ?? 301}`);\n writeFileSync(join(clientDir, \"_redirects\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"_redirects\");\n }\n\n const sitemap = staticConfig.sitemap;\n if (sitemap !== undefined) {\n const site = sitemap.site.replace(/\\/$/, \"\");\n const exclude = sitemap.exclude ?? [];\n const paths = [...new Set(entries.map((entry) => entry.path))]\n .filter((path) => !exclude.some((prefix) => path.startsWith(prefix)))\n .sort();\n const xml = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">',\n ...paths.map((path) => ` <url><loc>${site}${path === \"/\" ? \"/\" : path}</loc></url>`),\n \"</urlset>\",\n \"\",\n ].join(\"\\n\");\n writeFileSync(join(clientDir, \"sitemap.xml\"), xml);\n emitted.push(\"sitemap.xml\");\n }\n\n const robots = staticConfig.robots;\n if (robots !== undefined) {\n const lines = [\"User-agent: *\"];\n for (const path of robots.disallow ?? []) {\n lines.push(`Disallow: ${path}`);\n }\n if ((robots.sitemap ?? true) && sitemap !== undefined) {\n lines.push(\"\", `Sitemap: ${sitemap.site.replace(/\\/$/, \"\")}/sitemap.xml`);\n }\n writeFileSync(join(clientDir, \"robots.txt\"), `${lines.join(\"\\n\")}\\n`);\n emitted.push(\"robots.txt\");\n }\n\n return emitted;\n}\n\n/**\n * Addendum G: render halaman 404 ke `dist/client/404.html` (static export).\n * Ditulis hanya bila app memiliki route `_404` dan sentinel menghasilkan 404;\n * hasilnya tetap melewati guard kebocoran (fail-mode).\n */\nasync function renderStaticNotFound(\n options: PrerenderOptions,\n env: Record<string, string | undefined>,\n log: (message: string) => void,\n): Promise<string | null> {\n if (!options.routes.some((route) => route.kind === \"404\")) {\n return null;\n }\n const response = await options.handler(\n new Request(`http://localhost${NOT_FOUND_SENTINEL}`, {\n method: \"GET\",\n headers: { \"x-moons-prerender\": \"1\" },\n }),\n );\n if (response.status !== 404) {\n log(\n `[moons] prerender: ${NOT_FOUND_FILE} skipped (sentinel \\`${NOT_FOUND_SENTINEL}\\` → ${response.status})`,\n );\n return null;\n }\n const html = await response.text();\n assertNoLeak(html, NOT_FOUND_SENTINEL, NOT_FOUND_FILE, options, env);\n return html;\n}\n\n/** Guard kebocoran fail-mode (Addendum D.5) — dipakai halaman & 404 statis. */\nfunction assertNoLeak(\n html: string,\n pathname: string,\n file: string,\n options: PrerenderOptions,\n env: Record<string, string | undefined>,\n): void {\n const findings = scanPayloadForSecrets(html, {\n ...(options.canary === undefined ? {} : { canary: options.canary }),\n env,\n });\n if (findings.length === 0) {\n return;\n }\n const labels = findings\n .map((finding) => (finding.kind === \"canary\" ? \"canary\" : `env(${finding.label})`))\n .join(\", \");\n throw new MoonsError({\n code: \"E_PRERENDER_LEAK\",\n file,\n message: `prerender output \\`${pathname}\\` contains ${labels}`,\n details: \"Static HTML is permanent — a prerendered secret cannot be retracted.\",\n suggestions: [\n \"Do not return secret env values from a loader that runs at prerender time\",\n \"Turn off `prerender` for this route or move the data to a request-time serverFn\",\n ],\n });\n}\n\nfunction routeKeyOf(routesDir: string, file: string): string {\n const relative = file.startsWith(routesDir) ? file.slice(routesDir.length + 1) : file;\n return relative.split(\"\\\\\").join(\"/\").replace(/\\.(tsx|ts)$/, \"\");\n}\n\nasync function resolvePathnames(route: RouteDefinition, module: RouteModule): Promise<string[]> {\n const isDynamic = route.params.length > 0;\n if (!isDynamic) {\n return [route.path];\n }\n const paths = module.paths;\n if (typeof paths !== \"function\") {\n throw new MoonsError({\n code: \"E_PRERENDER_NO_PATHS\",\n file: route.file,\n message: \"dynamic route with `prerender = true` without `export const paths`\",\n details: \"Prerendering needs a param list to render each path.\",\n suggestions: [\n 'Add `export const paths = () => [{ id: \"…\" }]`',\n \"Or remove `prerender` so the route renders at request time (SSR)\",\n ],\n });\n }\n\n const raw = await (paths as () => unknown | Promise<unknown>)();\n if (!Array.isArray(raw)) {\n throw prerenderError(route, \"`paths()` must return an array\");\n }\n\n const expected = new Set(route.params);\n const result: string[] = [];\n for (const item of raw as unknown[]) {\n if (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n throw prerenderError(route, \"`paths()` items must be objects with string params\");\n }\n const record = item as Record<string, unknown>;\n const keys = Object.keys(record);\n for (const name of expected) {\n const value = record[name];\n if (typeof value !== \"string\" || value.length === 0) {\n throw prerenderError(route, `param \\`${name}\\` must be a non-empty string`);\n }\n }\n for (const key of keys) {\n if (!expected.has(key)) {\n throw prerenderError(route, `param \\`${key}\\` is not in the route pattern`);\n }\n }\n result.push(buildPathname(route, record as Record<string, string>));\n }\n return result;\n}\n\nfunction buildPathname(route: RouteDefinition, params: Record<string, string>): string {\n const segments = route.path.split(\"/\").filter((segment) => segment.length > 0);\n const out: string[] = [];\n let catchallName: string | null = null;\n for (const segment of segments) {\n if (segment === \"*\") {\n catchallName = route.params[route.params.length - 1] ?? null;\n const value = catchallName === null ? \"\" : (params[catchallName] ?? \"\");\n for (const part of value.split(\"/\")) {\n if (part.length === 0) {\n continue;\n }\n out.push(encodeSegment(route, part));\n }\n continue;\n }\n if (segment.startsWith(\":\")) {\n out.push(encodeSegment(route, params[segment.slice(1)] ?? \"\"));\n continue;\n }\n out.push(segment);\n }\n return `/${out.join(\"/\")}`;\n}\n\nfunction encodeSegment(route: RouteDefinition, value: string): string {\n if (value.length === 0 || /^\\.+$/.test(value)) {\n throw prerenderError(route, `param value \\`${value}\\` is not valid for a file path`);\n }\n return encodeURIComponent(value);\n}\n\nfunction outputFile(clientDir: string, pathname: string): string {\n const parts = pathname.split(\"/\").filter((part) => part.length > 0);\n const file = resolve(join(clientDir, ...parts, \"index.html\"));\n const base = resolve(clientDir);\n if (file !== base && !file.startsWith(base + sep)) {\n throw new MoonsError({\n code: \"E_PRERENDER_INVALID\",\n message: `prerender path escapes the client directory (\\`${pathname}\\`)`,\n details: \"The file name must stay inside `dist/client`.\",\n suggestions: [\"Check the `paths` param values — do not use `..`\"],\n });\n }\n return file;\n}\n\nfunction prerenderError(route: RouteDefinition, message: string): MoonsError {\n return new MoonsError({\n code: \"E_PRERENDER_INVALID\",\n file: route.file,\n message,\n details: \"The prerender contract is enforced.\",\n suggestions: [\n \"Fix the `paths`/params shape so it matches the route pattern\",\n \"Do not use `redirect()` on a prerendered route\",\n ],\n });\n}\n"
|
|
15
15
|
],
|
|
16
|
-
"mappings": "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",
|
|
17
|
-
"debugId": "
|
|
16
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA;AACA;AACA;AAEA;;;ACFA,IAAM,qBACJ;AAEF,IAAM,oBAAoB;AAEnB,SAAS,qBAAqB,CACnC,SACA,UAA8B,CAAC,GACT;AAAA,EACtB,MAAM,WAAiC,CAAC;AAAA,EAExC,MAAM,SAAS,QAAQ;AAAA,EACvB,IAAI,WAAW,aAAa,OAAO,SAAS,KAAK,QAAQ,SAAS,MAAM,GAAG;AAAA,IACzE,SAAS,KAAK,EAAE,MAAM,UAAU,OAAO,SAAS,CAAC;AAAA,EACnD;AAAA,EAEA,YAAY,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,CAAC,CAAC,GAAG;AAAA,IAC5D,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,mBAAmB;AAAA,MACjE;AAAA,IACF;AAAA,IACA,IAAI,CAAC,mBAAmB,KAAK,GAAG,KAAK,UAAU,KAAK,GAAG,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,SAAS,KAAK,GAAG;AAAA,MAC3B,SAAS,KAAK,EAAE,MAAM,OAAO,OAAO,IAAI,CAAC;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;;;ADrBT,IAAM,aAAa;AACnB,IAAM,cAAc;AAoCb,SAAS,oBAAoB,CAClC,SACyC;AAAA,EAAG,QAAQ,QAAQ,QAAQ,WAAW,WAAW,UAAU;AAAA,EACpG,MAAM,MAAM,iBACV,OAAO,aAAa,YAAY,CAAC,IAAI,EAAE,UAAU,OAAO,SAAS,CACnE;AAAA,EACA,MAAM,gBAAgB,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,KAAK;AAAA,EACjE,MAAM,aAAa,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,OAAO;AAAA,EAEhE,MAAM,sBAAsB,IAAI;AAAA,EAEhC,eAAe,WAAW,CACxB,UACA,SACA,KACmB;AAAA,IACnB,MAAM,UAAU,CAAC,GAAG,SAAS,SAAS,SAAS,KAAK;AAAA,IACpD,MAAM,OAAO,QAAQ,IAAI,CAAC,UAAU,iBAAiB,WAAW,MAAM,IAAI,CAAC;AAAA,IAC3E,MAAM,UAAU,MAAM,YAAY,MAAM,SAAS;AAAA,IAEjD,MAAM,OAAO,MAAM,WACjB,QAAQ,IAAI,CAAC,OAAO,WAAW,EAAE,MAAM,KAAK,QAAkB,QAAQ,QAAQ,OAAsB,EAAE,GACtG,EAAE,QAAQ,SAAS,QAAQ,KAAK,KAAK,QAAQ,CAC/C;AAAA,IAEA,MAAM,UAAU,iBAAiB,WAAW,SAAS,MAAM,IAAI;AAAA,IAC/D,MAAM,aAAa,QAAQ,QAAQ,SAAS;AAAA,IAC5C,MAAM,QAA0B,EAAE,MAAM,SAAS,SAAS,KAAK,MAAM,GAAG,EAAE,EAAE;AAAA,IAE5E,MAAM,eAAe,OAAO,YAAY,IAAI,IAAI,QAAQ,GAAG,EAAE,YAAY;AAAA,IAEzE,MAAM,OAAO,MAAM,aAAa,YAAY,KAAK,UAAU,SAAS,MAAM,IAAI;AAAA,IAE9E,MAAM,SAAS,eACb,OACA,EAAE,MAAM,YAAgC,SAAS,QAAQ,MAAM,GAAG,EAAE,EAAwB,GAC5F,SAAS,QACT,MACA,cACA,WACA,OAAO,aACT;AAAA,IACA,MAAM,UAAU,iBAAiB;AAAA,MAC/B,KAAK;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB;AAAA,MACA;AAAA,SACI,SAAS,YAAY,CAAC,IAAI,EAAE,KAAK;AAAA,IACvC,CAAC;AAAA,IAGD,oBAAoB,SAAS,QAAQ,aAAa,mBAAmB;AAAA,IAErE,OAAO,aACL,sBAAsB,MAAM,MAAM,QAAQ,SAAS,QAAQ,KAAK,IAAI,GAAG,OAAO,aAAa,GAC3F,GACF;AAAA;AAAA,EAIF,eAAe,gBAAgB,CAC7B,OACA,QACA,SACA,KACmB;AAAA,IACnB,MAAM,OAAO,QAAQ,UAAU,MAAM;AAAA,IACrC,IAAI,SAAS,WAAW;AAAA,MACtB,OAAO,iBACL,IAAI,WAAW;AAAA,QACb,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,SAAS,gBAAgB,MAAM;AAAA,QAC/B,SAAS;AAAA,QACT,aAAa,CAAC,kCAAkC;AAAA,MAClD,CAAC,GACD,KACF;AAAA,IACF;AAAA,IAEA,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,MAAM,MAAM,KAAK;AAAA,MACjB,OAAO,OAAO;AAAA,MACd,OAAO,iBAAiB,OAAO,KAAK;AAAA;AAAA,IAEtC,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAAA,MAC3C,OAAO,iBACL,IAAI,WAAW;AAAA,QACb,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT,SAAS,YAAY,MAAM;AAAA,QAC3B,aAAa,CAAC,yDAAyD;AAAA,MACzE,CAAC,GACD,KACF;AAAA,IACF;AAAA,IAEA,MAAM,SAAS;AAAA,IACf,MAAM,UAAuB,YAAY,OACvC,CAAC,WAAW,OAAO,OAAO,YAAY,UACxC;AAAA,IACA,MAAM,gBAAgB,QAAQ,OAAO,YAAY;AAAA,IAMjD,IAAI,UAAU,OAAO;AAAA,IACrB,IAAI,YAAY;AAAA,IAGhB,IAAI,OAAO,YAAY,cAAc,kBAAkB,UAAU,OAAO,OAAO,WAAW,YAAY;AAAA,MACpG,UAAU,OAAO;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,IACA,IAAI,OAAO,YAAY,YAAY;AAAA,MACjC,IAAI,kBAAkB,WAAW;AAAA,QAC/B,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,IAAI,EAAE,EAAE,CAAC;AAAA,MACnF;AAAA,MACA,OAAO,IAAI,SAAS,sBAAsB;AAAA,QACxC,QAAQ;AAAA,QACR,SAAS,EAAE,OAAO,QAAQ,KAAK,IAAI,EAAE;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,SAAS,MAAM,QAAQ,EAAE,KAAK,SAAS,QAAQ,IAAI,CAAC;AAAA,MAC1D,IAAI,EAAE,kBAAkB,WAAW;AAAA,QACjC,OAAO,iBACL,IAAI,WAAW;AAAA,UACb,MAAM;AAAA,UACN,MAAM,MAAM;AAAA,UACZ,SAAS,aAAa;AAAA,UACtB,SAAS;AAAA,UACT,aAAa,CAAC,kDAAkD;AAAA,QAClE,CAAC,GACD,KACF;AAAA,MACF;AAAA,MACA,IAAI,WAAW;AAAA,QACb,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,OAAO,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,MAC9E;AAAA,MACA,OAAO;AAAA,MACP,OAAO,OAAO;AAAA,MACd,OAAO,iBAAiB,OAAO,KAAK;AAAA;AAAA;AAAA,EAKxC,eAAe,gBAAgB,CAAC,SAAqC;AAAA,IACnE,IAAI,kBAAkB,WAAW;AAAA,MAC/B,IAAI;AAAA,QACF,MAAM,MAAM,iBAAiB,WAAW,cAAc,IAAI;AAAA,QAC1D,OAAO,UAAU,MAAM,YAAY,CAAC,GAAG,GAAG,SAAS;AAAA,QACnD,MAAM,UAAU,iBAAiB,EAAE,KAAK,qBAAqB,QAAQ,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;AAAA,QACnF,MAAM,SAAS,eACb,EAAE,MAAM,KAAK,SAAS,CAAC,EAAE,GACzB,EAAE,MAAM,QAA4B,SAAS,CAAC,EAAE,GAChD,CAAC,GACD,CAAC,GACD,CAAC,GACD,WACA,OAAO,aACT;AAAA,QACA,OAAO,aACL,sBAAsB,MAAM,MAAM,QAAQ,SAAS,QAAQ,GAAG,GAAG,OAAO,aAAa,GACrF,GACF;AAAA,QACA,OAAO,OAAO;AAAA,QACd,QAAQ,MAAM,yCAAyC,KAAK;AAAA;AAAA,IAEhE;AAAA,IAEA,MAAM,UAAU,iBAAiB,EAAE,KAAK,IAAI,QAAQ,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;AAAA,IAClE,MAAM,OAAO,MAAM,MAAM,sCAAsC,SAAS,QAAQ,GAAG;AAAA,IACnF,OAAO,aAAa,sBAAsB,MAAM,OAAO,aAAa,GAAG,GAAG;AAAA;AAAA,EAO5E,eAAe,kBAAkB,CAC/B,OACA,SACA,UACmB;AAAA,IACnB,QAAQ,MAAM,wBAAwB,KAAK;AAAA,IAE3C,MAAM,YACH,aAAa,YAAY,OAAO,kBAAkB,SAAS,OAAO,MAAM,MACzE,cACA;AAAA,IACF,IAAI,aAAa,MAAM;AAAA,MACrB,IAAI;AAAA,QACF,MAAM,MAAM,iBAAiB,WAAW,SAAS,IAAI;AAAA,QACrD,OAAO,UAAU,MAAM,YAAY,CAAC,GAAG,GAAG,SAAS;AAAA,QACnD,MAAM,eAAe,QAAQ,IAAI,gBAAgB;AAAA,QACjD,MAAM,aAAa,eAAe,YAAY,eAAe,KAAK;AAAA,QAClE,MAAM,UAAU,iBAAiB;AAAA,UAC/B;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,MAAM,CAAC;AAAA,aACH,eAAe,YAAY,CAAC,IAAI,EAAE,OAAO,WAAW;AAAA,QAC1D,CAAC;AAAA,QACD,MAAM,SAAS,eACb,EAAE,MAAM,KAAK,SAAS,CAAC,EAAE,GACzB,EAAE,MAAM,QAA4B,SAAS,CAAC,EAAE,GAChD,CAAC,GACD,CAAC,GACD,CAAC,GACD,eAAe,YAAY,YAAY,YAAY,UAAU,GAC7D,OAAO,aACT;AAAA,QACA,OAAO,aACL,sBAAsB,MAAM,MAAM,QAAQ,SAAS,QAAQ,GAAG,GAAG,OAAO,aAAa,GACrF,GACF;AAAA,QACA,OAAO,aAAa;AAAA,QACpB,QAAQ,MAAM,2CAA2C,WAAW;AAAA;AAAA,IAExE;AAAA,IAEA,OAAO,sBAAsB,OAAO,EAAE,KAAK,MAAM,CAAC;AAAA;AAAA,EAIpD,eAAe,kBAAkB,CAAC,OAA8D;AAAA,IAC9F,MAAM,SAAuB,CAAC;AAAA,IAC9B,WAAW,cAAc,OAAO;AAAA,MAC9B,MAAM,MAAM,iBAAiB,WAAW,WAAW,IAAI;AAAA,MACvD,MAAM,OAAO,QAAQ,YAAY;AAAA,MACjC,IAAI,SAAS,WAAW;AAAA,QACtB,MAAM,IAAI,WAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM,WAAW;AAAA,UACjB,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa,CAAC,kCAAkC;AAAA,QAClD,CAAC;AAAA,MACH;AAAA,MACA,MAAM,SAAU,MAAM,KAAK;AAAA,MAC3B,MAAM,UAAU,OAAO;AAAA,MACvB,IAAI,OAAO,YAAY,YAAY;AAAA,QACjC,MAAM,IAAI,WAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM,WAAW;AAAA,UACjB,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa,CAAC,6DAA6D;AAAA,QAC7E,CAAC;AAAA,MACH;AAAA,MACA,OAAO,KAAK,OAAqB;AAAA,IACnC;AAAA,IACA,OAAO;AAAA;AAAA,EAIT,eAAe,qBAAqB,CAClC,OACuB;AAAA,IACvB,MAAM,SAAuB,CAAC;AAAA,IAC9B,WAAW,cAAc,OAAO;AAAA,MAC9B,MAAM,OAAO,QAAQ,oBAAoB,WAAW;AAAA,MACpD,IAAI,SAAS,WAAW;AAAA,QACtB,MAAM,IAAI,WAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM,WAAW;AAAA,UACjB,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa,CAAC,kCAAkC;AAAA,QAClD,CAAC;AAAA,MACH;AAAA,MACA,MAAM,SAAU,MAAM,KAAK;AAAA,MAC3B,IAAI,OAAO,OAAO,YAAY,YAAY;AAAA,QACxC,MAAM,IAAI,WAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM,WAAW;AAAA,UACjB,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa,CAAC,6DAA6D;AAAA,QAC7E,CAAC;AAAA,MACH;AAAA,MACA,OAAO,KAAK,OAAO,OAAqB;AAAA,IAC1C;AAAA,IACA,OAAO;AAAA;AAAA,EAGT,MAAM,aAAa,eAAe,OAAO,CAAC,SAAqC;AAAA,IAC7E,IAAI;AAAA,MACF,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,MAG/B,IAAI,IAAI,aAAa,aAAa;AAAA,QAChC,OAAO,eAAe,QAAQ,MAAM;AAAA,MACtC;AAAA,MAMA,MAAM,MAAO,MAAM,OAAO,QAAQ,OAAO;AAAA,MACzC,QAAQ,YAAY,GAAG;AAAA,MAEvB,IAAI,QAAQ,QAAQ,IAAI,mBAAmB,MAAM,KAAK;AAAA,QACnD,IAAgC,iBAAiB;AAAA,MACpD;AAAA,MAEA,MAAM,UAAU,kBAAkB,OAAO,cAAc,CAAC,GAAG,KAAK,YAAY;AAAA,QAC1E,IAAI,IAAI,SAAS,WAAW,UAAU,GAAG;AAAA,UACvC,OAAO,MAAM,IAAI,SAAS,IAAI,SAAS,MAAM,WAAW,MAAM,GAAG,GAAG;AAAA,QACtE;AAAA,QAEA,IAAI,QAAQ,cAAc,aAAa,QAAQ,UAAU,SAAS,GAAG;AAAA,UACnE,MAAM,WAAW,gBAAgB,IAAI,UAAU,QAAQ,SAAS;AAAA,UAChE,IAAI,aAAa,MAAM;AAAA,YAErB,MAAM,WAAW,sBACf,SAAS,MAAM,MACf,QAAQ,kBAAkB,CAAC,CAC7B;AAAA,YACA,IAAI,SAAS,WAAW,GAAG;AAAA,cACzB,OAAO,MAAM,iBAAiB,SAAS,OAAO,SAAS,QAAQ,SAAS,GAAG;AAAA,YAC7E;AAAA,YACA,MAAM,cAAc,MAAM,sBAAsB,QAAQ;AAAA,YACxD,OAAO,MAAM,kBACX,aACA,KACA,MAAM,iBAAiB,SAAS,OAAO,SAAS,QAAQ,SAAS,GAAG,GACpE,EAAE,MAAM,wBAAwB,OAAO,iBAAiB,CAC1D,EAAE,OAAO;AAAA,UACX;AAAA,QACF;AAAA,QACA,MAAM,WAAW,aAAa,IAAI,UAAU,MAAM;AAAA,QAClD,IAAI,aAAa,MAAM;AAAA,UACrB,OAAO,MAAM,iBAAiB,OAAO;AAAA,QACvC;AAAA,QACA,IAAI;AAAA,UAEF,MAAM,WAAW,mBAAmB,SAAS,OAAO,MAAM;AAAA,UAC1D,IAAI,SAAS,WAAW,GAAG;AAAA,YACzB,OAAO,MAAM,YAAY,UAAU,SAAS,GAAG;AAAA,UACjD;AAAA,UACA,MAAM,cAAc,MAAM,mBAAmB,QAAQ;AAAA,UACrD,OAAO,MAAM,kBACX,aACA,KACA,MAAM,YAAY,UAAU,SAAS,GAAG,GACxC,EAAE,MAAM,wBAAwB,OAAO,uBAAuB,CAChE,EAAE,OAAO;AAAA,UACT,OAAO,OAAO;AAAA,UAEd,IAAI,iBAAiB,KAAK,GAAG;AAAA,YAC3B,OAAO,IAAI,SAAS,MAAM;AAAA,cACxB,QAAQ,MAAM;AAAA,cACd,SAAS,EAAE,UAAU,IAAI,IAAI,MAAM,IAAI,QAAQ,GAAG,EAAE,SAAS,EAAE;AAAA,YACjE,CAAC;AAAA,UACH;AAAA,UACA,IAAI,iBAAiB,KAAK,GAAG;AAAA,YAC3B,OAAO,MAAM,iBAAiB,OAAO;AAAA,UACvC;AAAA,UACA,OAAO,MAAM,mBAAmB,OAAO,SAAS,QAAQ;AAAA;AAAA,OAE3D;AAAA,MAKD,OAAO,MAAM,yBAAyB,YAAY;AAAA,QAChD,IAAI;AAAA,QACJ,IAAI;AAAA,UACF,WAAW,MAAM,oBAAoB,MAAM,eAAe,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC;AAAA,UACtF,OAAO,OAAO;AAAA,UACd,WAAW,sBAAsB,KAAK;AAAA;AAAA,QAExC,OAAO,uBAAuB,QAAQ;AAAA,OACvC;AAAA,MACD,OAAO,OAAO;AAAA,MACd,OAAO,sBAAsB,KAAK;AAAA;AAAA;AAAA,EAKtC,MAAM,gBAAgB,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC;AAAA,EACzD,MAAM,aAAa,OAAO,aAAa,CAAC,GAAG,IAAI,CAAC,WAAW;AAAA,OACtD;AAAA,IACH,QAAQ,MAAM,UAAU;AAAA,EAC1B,EAAE;AAAA,EAEF,OAAO,eAAe,OAAO,CAAC,SAAqC;AAAA,IACjE,MAAM,cAAc,QAAQ,QAAQ,IAAI,mBAAmB,MAAM;AAAA,IACjE,MAAM,eAAe,CAAC,aAAiC;AAAA,MACrD,YAAY,MAAM,UAAU,eAAe;AAAA,QACzC,IAAI,CAAC,SAAS,QAAQ,IAAI,IAAI,GAAG;AAAA,UAC/B,SAAS,QAAQ,IAAI,MAAM,KAAK;AAAA,QAClC;AAAA,MACF;AAAA,MACA,OAAO;AAAA;AAAA,IAGT,IAAI;AAAA,MAGF,IAAI,CAAC,eAAe,OAAO,kBAAkB,WAAW;AAAA,QACtD,MAAM,YAAY,IAAI,IAAI,QAAQ,GAAG;AAAA,QACrC,MAAM,YAAY,sBAAsB,UAAU,UAAU,OAAO,aAAa;AAAA,QAChF,IAAI,cAAc,MAAM;AAAA,UACtB,UAAU,WAAW;AAAA,UACrB,OAAO,aACL,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,SAAS,EAAE,UAAU,UAAU,SAAS,EAAE,EAAE,CAAC,CACjF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,IAAI,CAAC,eAAe,UAAU,SAAS,GAAG;AAAA,QACxC,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,QAC/B,MAAM,OAAO,IAAI,SAAS,QAAQ,OAAO,EAAE;AAAA,QAC3C,WAAW,SAAS,WAAW;AAAA,UAC7B,IAAI,SAAS,MAAM,KAAK,QAAQ,OAAO,EAAE,GAAG;AAAA,YAC1C,MAAM,WAAW,MAAM,GAAG,WAAW,MAAM,IACvC,MAAM,KACN,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,EAAE,SAAS;AAAA,YAC3C,OAAO,aACL,IAAI,SAAS,MAAM,EAAE,QAAQ,MAAM,QAAQ,SAAS,EAAE,SAAS,EAAE,CAAC,CACpE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,OAAO,YAAY,OAAO;AAAA,MACvC,IAAI,WAAW,MAAM,WAAW,OAAO;AAAA,MACvC,MAAM,WAAW,MAAM,OAAO,OAAO,aAAa,UAAU,OAAO;AAAA,MACnE,IAAI,oBAAoB,UAAU;AAAA,QAChC,WAAW;AAAA,MACb;AAAA,MACA,OAAO,aAAa,QAAQ;AAAA,MAC5B,OAAO,OAAO;AAAA,MACd,IAAI;AAAA,QACF,MAAM,OAAO,OAAO,UAAU,OAAO,OAAO;AAAA,QAC5C,MAAM;AAAA,MAGR,OAAO,sBAAsB,KAAK;AAAA;AAAA;AAAA;AAMxC,SAAS,sBAAsB,CAAC,UAA8B;AAAA,EAC5D,MAAM,YAAY,sBAAsB;AAAA,EACxC,IAAI,UAAU,WAAW,GAAG;AAAA,IAC1B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,UAAU,IAAI,QAAQ,SAAS,OAAO;AAAA,EAC5C,WAAW,YAAY,WAAW;AAAA,IAChC,IAAI,SAAS,SAAS,UAAU;AAAA,MAC9B,IAAI,SAAS,QAAQ;AAAA,QACnB,QAAQ,OAAO,SAAS,MAAM,SAAS,KAAK;AAAA,MAC9C,EAAO;AAAA,QACL,QAAQ,IAAI,SAAS,MAAM,SAAS,KAAK;AAAA;AAAA,IAE7C,EAAO;AAAA,MACL,QAAQ,OAAO,cAAc,SAAS,KAAK;AAAA;AAAA,EAE/C;AAAA,EACA,OAAO,IAAI,SAAS,SAAS,MAAM;AAAA,IACjC,QAAQ,SAAS;AAAA,IACjB,YAAY,SAAS;AAAA,IACrB;AAAA,EACF,CAAC;AAAA;AAGH,eAAe,WAAW,CACxB,MACA,WACwB;AAAA,EACxB,OAAO,MAAM,QAAQ,IACnB,KAAK,IAAI,OAAO,QAAQ;AAAA,IACtB,MAAM,OAAO,UAAU;AAAA,IACvB,IAAI,SAAS,WAAW;AAAA,MACtB,MAAM,IAAI,WAAW;AAAA,QACnB,MAAM;AAAA,QACN,SAAS,kBAAkB;AAAA,QAC3B,SAAS;AAAA,QACT,aAAa,CAAC,sDAAsD;AAAA,MACtE,CAAC;AAAA,IACH;AAAA,IACA,OAAO,MAAM,KAAK;AAAA,GACnB,CACH;AAAA;AAGF,eAAe,YAAY,CACzB,YACA,UACA,MAC8C;AAAA,EAC9C,MAAM,OAAQ,WAAkC;AAAA,EAChD,IAAI,SAAS,WAAW;AAAA,IACtB;AAAA,EACF;AAAA,EACA,IAAI,OAAO,SAAS,YAAY;AAAA,IAC9B,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,EACA,MAAM,SAAS,MAAO,KAA8C,EAAE,MAAM,SAAS,CAAC;AAAA,EACtF,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAAA,IAC1E,MAAM,IAAI,WAAW;AAAA,MACnB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT,aAAa,CAAC,8CAAgD;AAAA,IAChE,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAMT,SAAS,gBAAgB,CAAC,OAAgB,OAAqC;AAAA,EAC7E,MAAM,eAAe,QAAQ,IAAI,gBAAgB;AAAA,EACjD,IAAI,iBAAiB,YAAY;AAAA,IAC/B,QAAQ,MAAM,eAAe,MAAM,SAAS,MAAM,OAAO,GAAG;AAAA,IAC5D,OAAO,IAAI,SAAS,eAAe,2BAA2B,MAAM,OAAO,GAAG;AAAA,MAC5E,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,IACzD,CAAC;AAAA,EACH;AAAA,EACA,QAAQ,MAAM,eAAe,MAAM,SAAS,KAAK;AAAA,EACjD,OAAO,IAAI,SAAS,eAAe,2BAA2B,OAAO,KAAK,GAAG;AAAA,IAC3E,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,4BAA4B;AAAA,EACzD,CAAC;AAAA;AAGH,SAAS,qBAAqB,CAAC,OAAgB,UAA6B,CAAC,GAAa;AAAA,EACxF,IAAI,QAAQ,QAAQ,OAAO;AAAA,IACzB,QAAQ,MAAM,0BAA0B,KAAK;AAAA,EAC/C;AAAA,EAEA,MAAM,SACJ,QAAQ,IAAI,gBAAgB,gBAAgB,iBAAiB,aACzD,QAAQ,WAAW,MAAM,OAAO,CAAC,YACjC;AAAA,EAEN,OAAO,aACL,yGAAyG,wBACzG,GACF;AAAA;AAIF,SAAS,qBAAqB,CAAC,MAAc,QAAqC;AAAA,EAChF,IAAI,WAAW,WAAW;AAAA,IACxB,OAAO;AAAA,EACT;AAAA,EACA,OAAO,KAAK,QACV,WACA,gDAAgD;AAAA,QAClD;AAAA;AAGF,SAAS,YAAY,CAAC,MAAc,QAA0B;AAAA,EAC5D,OAAO,IAAI,SAAS,MAAM;AAAA,IACxB;AAAA,IACA,SAAS,EAAE,gBAAgB,2BAA2B;AAAA,EACxD,CAAC;AAAA;AAIH,SAAS,cAAc,CAAC,QAA0B;AAAA,EAChD,MAAM,UAAU,EAAE,gBAAgB,kCAAkC;AAAA,EACpE,IAAI,WAAW,SAAS,WAAW,QAAQ;AAAA,IACzC,OAAO,IAAI,SAAS,WAAW,SAAS,OAAO,KAAK,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG;AAAA,MAC3E,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EACA,OAAO,IAAI,SAAS,sBAAsB;AAAA,IACxC,QAAQ;AAAA,IACR,SAAS,EAAE,OAAO,YAAY;AAAA,EAChC,CAAC;AAAA;AAGH,SAAS,UAAU,CAAC,MAAsB;AAAA,EACxC,OAAO,KACJ,WAAW,KAAK,OAAO,EACvB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,QAAQ;AAAA;AAQ7B,SAAS,mBAAmB,CAC1B,SACA,MACA,QACM;AAAA,EACN,IAAI,SAAS,WAAW;AAAA,IACtB;AAAA,EACF;AAAA,EACA,WAAW,WAAW,sBAAsB,SAAS,IAAI,GAAG;AAAA,IAC1D,MAAM,QAAQ,QAAQ,SAAS,WAAW,WAAW,OAAO,QAAQ;AAAA,IACpE,IAAI,OAAO,IAAI,KAAK,GAAG;AAAA,MACrB;AAAA,IACF;AAAA,IACA,OAAO,IAAI,KAAK;AAAA,IAChB,QAAQ,KACN,6CAA6C,6CAC/C;AAAA,EACF;AAAA;;AErrBF,qCAAqB,2BAAc;AACnC;AACA;AACA,oBAAS;AACT;AAAA;AAAA,gBAEE;AAAA,2BACA;AAAA;;;ACPF;AASO,SAAS,gBAAgB,CAAC,OAIrB;AAAA,EACV,MAAM,MAAM,MAAM,OAAO,KAAK,IAAI;AAAA,EAClC,OAAO,MAAM,MAAM,WAAW,MAAM,oBAAoB;AAAA;AAmB1D,IAAM,WAAW,IAAI;AAGd,SAAS,qBAAqB,CAAC,SAA2C;AAAA,EAC/E,MAAM,WAAW,SAAS,IAAI,QAAQ,QAAQ;AAAA,EAC9C,IAAI,aAAa,WAAW;AAAA,IAC1B,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,cAAc,OAAO,EAAE,QAAQ,MAAM;AAAA,IAChD,SAAS,OAAO,QAAQ,QAAQ;AAAA,GACjC;AAAA,EACD,SAAS,IAAI,QAAQ,UAAU,IAAI;AAAA,EACnC,OAAO;AAAA;AAGT,eAAe,aAAa,CAAC,SAA2C;AAAA,EACtE,MAAM,MAAM,QAAQ,QAAQ,CAAC,YAAoB,QAAQ,IAAI,OAAO;AAAA,EACpE,IAAI;AAAA,IACF,MAAM,WAAW,MAAM,QAAQ,QAC7B,IAAI,QAAQ,mBAAmB,QAAQ,YAAY;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,qBAAqB,IAAI;AAAA,IACtC,CAAC,CACH;AAAA,IACA,IAAI,SAAS,WAAW,KAAK;AAAA,MAC3B,IAAI,wBAAwB,QAAQ,oBAAoB,SAAS,SAAS;AAAA,MAC1E;AAAA,IACF;AAAA,IACA,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,IACjC,MAAM,WAAW,sBAAsB,MAAM;AAAA,SACvC,QAAQ,WAAW,YAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,MACjE,KAAK,QAAQ,OAAO,QAAQ;AAAA,IAC9B,CAAC;AAAA,IACD,IAAI,SAAS,SAAS,GAAG;AAAA,MACvB,MAAM,SAAS,SACZ,IAAI,CAAC,YAAa,QAAQ,SAAS,WAAW,WAAW,OAAO,QAAQ,QAAS,EACjF,KAAK,IAAI;AAAA,MAEZ,IAAI,4BAA4B,QAAQ,uBAAuB,QAAQ;AAAA,MACvE;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,YAAY,WAAW;AAAA,MACjC,MAAM,QAAQ,QAAQ,MAAM,QAAQ,UAAU,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAAA,MAC5E;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,SAAS,WAAW;AAAA,MAC9B,IAAI,wBAAwB,QAAQ,wCAAwC;AAAA,MAC5E;AAAA,IACF;AAAA,IACA,MAAM,MAAM,GAAG,QAAQ,YAAY,QAAQ;AAAA,IAC3C,cAAc,KAAK,IAAI;AAAA,IACvB,WAAW,KAAK,QAAQ,IAAI;AAAA,IAC5B,OAAO,OAAO;AAAA,IACd,IAAI,qCAAqC,QAAQ,aAAa,OAAO,KAAK,GAAG;AAAA;AAAA;;;ACvFjF,gDAAkC,wCAAsB;AACxD;AASO,SAAS,iBAAiB,CAAC,WAAqC;AAAA,EACrE,OAAO;AAAA,SACC,KAAI,CAAC,UAAyD;AAAA,MAClE,MAAM,OAAO,kBAAkB,WAAW,QAAQ;AAAA,MAClD,IAAI,SAAS,MAAM;AAAA,QACjB,OAAO;AAAA,MACT;AAAA,MACA,MAAM,OAAO,SAAS,IAAI;AAAA,MAC1B,OAAO,EAAE,MAAM,aAAa,IAAI,GAAG,SAAS,KAAK,QAAQ;AAAA;AAAA,SAErD,MAAK,CAAC,UAAkB,MAAiC;AAAA,MAC7D,MAAM,SAAS,iBAAiB,WAAW,QAAQ;AAAA,MACnD,IAAI,WAAW,MAAM;AAAA,QACnB,MAAM,IAAI,MAAM,uCAAuC,UAAU;AAAA,MACnE;AAAA,MACA,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,MAC9C,MAAM,MAAM,GAAG,cAAc,QAAQ;AAAA,MACrC,eAAc,KAAK,IAAI;AAAA,MACvB,YAAW,KAAK,MAAM;AAAA;AAAA,EAE1B;AAAA;AAIK,SAAS,sBAAsB,CAAC,UAA0B;AAAA,EAC/D,MAAM,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,MAAM,EAAE,EAAE,YAAY;AAAA,EAC9D,OAAO,KAAK,QAAQ,KAAK,YAAY;AAAA;AAGvC,IAAM,OAA+B;AAAA,EACnC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AACZ;;;AC3BO,SAAS,UAAU,CAAC,MAAc,QAAmC;AAAA,EAC1E,IAAI,OAAO,WAAW,KAAK,CAAC,KAAK,SAAS,GAAG,GAAG;AAAA,IAC9C,OAAO;AAAA,EACT;AAAA,EACA,MAAM,QAAQ,KAAK,QAAQ,GAAG;AAAA,EAC9B,MAAM,WAAW,KAAK,MAAM,GAAG,KAAK;AAAA,EACpC,MAAM,SAAS,IAAI,gBAAgB,KAAK,MAAM,QAAQ,CAAC,CAAC;AAAA,EACxD,IAAI,UAAU;AAAA,EACd,WAAW,QAAQ,QAAQ;AAAA,IACzB,IAAI,OAAO,IAAI,IAAI,GAAG;AAAA,MACpB,OAAO,IAAI,MAAM,YAAY;AAAA,MAC7B,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,OAAO,UAAU,GAAG,YAAY,OAAO,SAAS,MAAM;AAAA;AAGjD,SAAS,YAAY,CAAC,UAAyB,CAAC,GAAW;AAAA,EAChE,MAAM,OAAO,QAAQ,SAAS;AAAA,EAC9B,MAAM,SAAS,QAAQ,UAAU,CAAC;AAAA,EAClC,MAAM,QAAQ,QAAQ,UAAU,CAAC,SAAuB,QAAQ,IAAI,IAAI;AAAA,EAExE,OAAO,CAAC,UAAU;AAAA,IAChB,MAAM,SAAkC,EAAE,OAAO,WAAW,MAAM;AAAA,IAClE,IAAI,OAAO,OAAO,YAAY,UAAU;AAAA,MACtC,OAAO,UAAU,WAAW,OAAO,SAAS,MAAM;AAAA,IACpD;AAAA,IACA,IAAI,MAAM;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,IAAI,KAAK,EAAE,YAAY,MAAM,OAAO,CAAC,CAAC;AAAA,MACnE;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,CAAC,WAAW,OAAO,OAAO,QAAQ,EAAE,YAAY,GAAG,OAAO,OAAO,MAAM,CAAC;AAAA,IACtF,IAAI,OAAO,YAAY,WAAW;AAAA,MAChC,MAAM,KAAK,OAAO,OAAO,OAAO,CAAC;AAAA,IACnC;AAAA,IACA,IAAI,OAAO,cAAc,WAAW;AAAA,MAClC,MAAM,KAAK,OAAO,OAAO,SAAS,CAAC;AAAA,IACrC;AAAA,IACA,IAAI,OAAO,kBAAkB,WAAW;AAAA,MACtC,MAAM,KAAK,GAAG,OAAO,OAAO,aAAa,KAAK;AAAA,IAChD;AAAA,IACA,MAAM,MAAM,KAAK,GAAG,CAAC;AAAA;AAAA;;;AC3ClB,SAAS,uBAAuB,CACrC,QACA,UAA2B,CAAC,GACM;AAAA,EAClC,MAAM,YAAY,QAAQ,aAAa;AAAA,EACvC,MAAM,MAAM,QAAQ,QAAQ,CAAC,YAAoB,QAAQ,IAAI,OAAO;AAAA,EACpE,MAAM,OAAO,QAAQ,SAAS,CAAC,SAAiB,QAAQ,KAAK,IAAI;AAAA,EAEjE,IAAI,eAAe;AAAA,EAEnB,OAAO,CAAC,WAAiC;AAAA,IACvC,IAAI,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,eAAe;AAAA,IACf,IAAI,oBAAoB,uDAAuD;AAAA,IAE/E,MAAM,QAAQ,WAAW,MAAM;AAAA,MAC7B,IAAI,0BAA0B,4BAA4B;AAAA,MAC1D,MAAM,WAAY,OAAgD;AAAA,MAClE,IAAI;AAAA,QACF,UAAU,KAAK,MAAM;AAAA,QACrB,MAAM;AAAA,MAGR,KAAK,CAAC;AAAA,OACL,SAAS;AAAA,IACZ,MAAM,QAAQ;AAAA,IAEd,IAAI;AAAA,MACD,OAAiD,uBAAuB;AAAA,MACzE,MAAM;AAAA,IAIR,OAAO,MAAM,OAAO,UAAkB;AAAA,MACpC,IAAI,UAAU,WAAW;AAAA,QACvB,aAAa,KAAK;AAAA,QAClB,IAAI,gCAAgC,MAAM,SAAS;AAAA,QACnD,KAAK,CAAC;AAAA,QACN;AAAA,MACF;AAAA,MACA,IAAI,QAAQ,eAAe,WAAW;AAAA,QAGnC,MAA+B,MAAM;AAAA,QACtC,IAAI;AAAA,UACF,MAAM,QAAQ,WAAW;AAAA,UACzB,OAAO,WAAW;AAAA,UAClB,IAAI,8BAA8B,OAAO,SAAS,GAAG;AAAA;AAAA,MAEzD;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,IAAI,wCAAwC;AAAA,MAC5C,KAAK,CAAC;AAAA,KACP;AAAA;AAAA;;;AJrDL,IAAM,aAAqC;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;AAsCO,SAAS,eAAe,CAC7B,SACA,UAA6B,CAAC,GACtB;AAAA,EACR,MAAM,YAAY,QAAQ,QAAQ,aAAa,KAAK,QAAQ,IAAI,GAAG,aAAa,CAAC;AAAA,EACjF,MAAM,OAAO,QAAQ,QAAQ,OAAO,QAAQ,IAAI,WAAW,IAAI;AAAA,EAE/D,MAAM,eACJ,QAAQ,SAAS,cAAc,OAC3B,aAAa;AAAA,IACX,MAAM,QAAQ,QAAQ,SAAS;AAAA,IAC/B,QAAQ,QAAQ,QAAQ,UAAU,CAAC;AAAA,EACrC,CAAC,IACD;AAAA,EAEN,MAAM,SAAS,aAAa,CAAC,KAAK,QAAQ;AAAA,IACxC,MAAM,mBAAmB,YAAY,IAAI;AAAA,IACzC,IAAI,iBAAiB,MAAM;AAAA,MACzB,IAAI,KAAK,UAAU,MAAM;AAAA,QACvB,MAAM,KAAK,gBAAgB,KAAK,QAAQ,eAAe,IAAI;AAAA,QAC3D,aAAa;AAAA,UACX,KAAK;AAAA,UACL,QAAQ,IAAI,UAAU;AAAA,UACtB,MAAM,IAAI,OAAO;AAAA,UACjB,QAAQ,IAAI;AAAA,UACZ,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,gBAAgB;AAAA,aACvD,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG;AAAA,QAC9B,CAAC;AAAA,OACF;AAAA,IACH;AAAA,KACM,YAAY;AAAA,MAChB,IAAI;AAAA,MACJ,IAAI;AAAA,QAGF,MAAM,kBAAkB,KAAK,EAAE,YAAY,QAAQ,eAAe,KAAK,CAAC;AAAA,QACxE,OAAO,OAAO;AAAA,QACd,IAAI,iBAAiB,qBAAqB;AAAA,UACxC,QAAQ,KAAK,WAAW,MAAM,eAAe;AAAA,UAC7C,kBAAkB,GAAG;AAAA,UACrB;AAAA,QACF;AAAA,QACA,MAAM;AAAA;AAAA,MAGR,IAAI;AAAA,QAGF,IAAI,QAAQ,kBAAkB,WAAW;AAAA,UACvC,MAAM,YAAY,uBAAsB,IAAI,UAAU,QAAQ,aAAa;AAAA,UAC3E,IAAI,cAAc,MAAM;AAAA,YACtB,IAAI,WAAW;AAAA,YACf,IAAI,aAAa;AAAA,YACjB,IAAI,UAAU,YAAY,IAAI,SAAS,CAAC;AAAA,YACxC,IAAI,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,QAEA,IAAI,IAAI,WAAW,SAAS,IAAI,WAAW,QAAQ;AAAA,UAEjD,IAAI,QAAQ,YAAY,WAAW;AAAA,YACjC,MAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ;AAAA,YACrD,IAAI,UAAU,MAAM;AAAA,cAClB,qBAAqB;AAAA,gBACnB,UAAU,IAAI;AAAA,gBACd,SAAS,MAAM;AAAA,gBACf,SAAS,QAAQ;AAAA,gBACjB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QAAQ;AAAA,cACV,CAAC;AAAA,cACD,IAAI,aAAa;AAAA,cACjB,IAAI,UAAU,gBAAgB,uBAAuB,IAAI,QAAQ,CAAC;AAAA,cAClE,mBAAmB,KAAK,IAAI,UAAU,QAAQ,OAAO;AAAA,cACrD,IAAI,IAAI,IAAI,WAAW,SAAS,YAAY,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,cACnE;AAAA,YACF;AAAA,UAGF;AAAA,UACA;AAAA,YACE,MAAM,aAAa,kBAAkB,WAAW,IAAI,QAAQ;AAAA,YAC5D,IAAI,eAAe,MAAM;AAAA,cACvB,qBAAqB;AAAA,gBACnB,UAAU,IAAI;AAAA,gBACd,SAAS,UAAS,UAAU,EAAE;AAAA,gBAC9B,MAAM;AAAA,mBAGF,QAAQ,YAAY,YAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;AAAA,gBACpE;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QAAQ;AAAA,cACV,CAAC;AAAA,cACD,MAAM,OAAO,cAAa,UAAU;AAAA,cACpC,MAAM,OAAO,UAAS,UAAU;AAAA,cAChC,IAAI,aAAa;AAAA,cACjB,IAAI,UAAU,gBAAgB,WAAW,SAAQ,UAAU,EAAE,YAAY,MAAM,0BAA0B;AAAA,cACzG,mBAAmB,KAAK,IAAI,UAAU,QAAQ,OAAO;AAAA,cAGrD,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK,MAAM,KAAK,OAAO;AAAA,cACvD,IAAI,UAAU,QAAQ,IAAI;AAAA,cAC1B,MAAM,cAAc,IAAI,QAAQ;AAAA,cAChC,IACE,OAAO,gBAAgB,YACvB,YAAY,MAAM,GAAG,EAAE,KAAK,CAAC,UAAU,MAAM,KAAK,MAAM,IAAI,GAC5D;AAAA,gBACA,IAAI,aAAa;AAAA,gBACjB,IAAI,IAAI;AAAA,gBACR;AAAA,cACF;AAAA,cAGA,IAAI,UAAkB;AAAA,cACtB,IACE,IAAI,WAAW,SACf,kBAAkB,KAAK,UAAU,KACjC,KAAK,cAAc,kBACnB,YAAY,GAAG,GACf;AAAA,gBACA,UAAU,WAAW,YAAY,KAAK,SAAS,IAAI;AAAA,gBACnD,IAAI,UAAU,oBAAoB,MAAM;AAAA,gBACxC,WAAW,KAAK,iBAAiB;AAAA,cACnC;AAAA,cACA,IAAI,IAAI,IAAI,WAAW,SAAS,YAAY,OAAO;AAAA,cACnD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QAIA,MAAM,QAAQ,IAAI,SAAS,WAAW,aAAa;AAAA,QACnD,MAAM,WAAW,QAAQ,kBAAkB;AAAA,QAC3C,IAAI,OAAO;AAAA,UACT,MAAM,gBAAgB,OAAO,IAAI,QAAQ,qBAAqB,GAAG;AAAA,UACjE,IAAI,OAAO,SAAS,aAAa,KAAK,gBAAgB,UAAU;AAAA,YAC9D,IAAI,aAAa;AAAA,YACjB,IAAI,UAAU,gBAAgB,2BAA2B;AAAA,YACzD,IAAI,IAAI,oBAAoB,UAAU,aAAa,CAAC;AAAA,YACpD,IAAI,KAAK,UAAU,MAAM,IAAI,QAAQ,CAAC;AAAA,YACtC;AAAA,UACF;AAAA,QACF;AAAA,QAEA,MAAM,UAAU,MAAM,cAAa,KAAK;AAAA,UACtC,YAAY,QAAQ,eAAe;AAAA,aAC/B,QAAQ,EAAE,cAAc,SAAS,IAAI,CAAC;AAAA,QAC5C,CAAC;AAAA,QACD,MAAM,WAAW,MAAM,QAAQ,OAAO;AAAA,QACtC,MAAM,kBAAiB,KAAK,QAAQ;AAAA,QACpC,OAAO,OAAO;AAAA,QACd,IAAI,iBAAiB,gBAAgB;AAAA,UACnC,MAAM,QAAQ,IAAI,SAAS,WAAW,aAAa;AAAA,UACnD,IAAI,aAAa;AAAA,UACjB,IAAI,UAAU,gBAAgB,2BAA2B;AAAA,UACzD,IAAI,IAAI,QAAQ,oBAAoB,MAAM,OAAO,IAAI,IAAI,mBAAmB;AAAA,UAE5E,IAAI,KAAK,UAAU,MAAM,IAAI,QAAQ,CAAC;AAAA,UACtC;AAAA,QACF;AAAA,QACA,QAAQ,MAAM,yBAAyB,KAAK;AAAA,QAC5C,IAAI,aAAa;AAAA,QACjB,IAAI,UAAU,gBAAgB,2BAA2B;AAAA,QACzD,IAAI,IAAI,uBAAuB;AAAA;AAAA,OAEhC;AAAA,GACJ;AAAA,EAGD,MAAM,mBAAmB,MAAY;AAAA,IACnC,OAAO,OAAO,MAAM,MAAM;AAAA,MACxB,MAAM,UAAU,OAAO,QAAQ;AAAA,MAC/B,MAAM,YAAY,OAAO,YAAY,YAAY,YAAY,OAAO,QAAQ,OAAO;AAAA,MACnF,QAAQ,IAAI,gDAAgD,WAAW;AAAA,MAClE,QAAQ,SAAS,MAAM;AAAA,KAC7B;AAAA;AAAA,EAEH,IAAI,QAAQ,YAAY,WAAW;AAAA,IAC5B,QAAQ,QAAQ,MAAM,EAAE,KAAK,gBAAgB;AAAA,EACpD,EAAO;AAAA,IACL,iBAAiB;AAAA;AAAA,EAGnB,IAAI,QAAQ,kBAAkB,OAAO;AAAA,IACnC,MAAM,WAAW,wBAAwB,QAAQ;AAAA,SAC3C,QAAQ,sBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,kBAAkB;AAAA,SACtF,QAAQ,YAAY,YACpB,CAAC,IACD,EAAE,YAAY,MAAM,QAAQ,SAAS,SAAS,EAAE;AAAA,IACtD,CAAC;AAAA,IAED,QAAQ,KAAK,WAAW,MAAM,SAAS,SAAS,CAAC;AAAA,IACjD,QAAQ,KAAK,UAAU,MAAM,SAAS,QAAQ,CAAC;AAAA,EACjD;AAAA,EAEA,OAAO;AAAA;AAOT,SAAS,kBAAkB,CACzB,KACA,UACA,YACM;AAAA,EACN,YAAY,MAAM,UAAU,OAAO,QAAQ,cAAc,CAAC,CAAC,GAAG;AAAA,IAC5D,IAAI,CAAC,IAAI,UAAU,IAAI,GAAG;AAAA,MACxB,IAAI,UAAU,MAAM,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,YAAY,MAAM,UAAU,OAAO,QAAQ,wBAAwB,GAAG;AAAA,IACpE,IAAI,CAAC,IAAI,UAAU,IAAI,GAAG;AAAA,MACxB,IAAI,UAAU,MAAM,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EACA,IAAI,SAAS,WAAW,UAAU,KAAK,CAAC,IAAI,UAAU,eAAe,GAAG;AAAA,IACtE,IAAI,UAAU,iBAAiB,qCAAqC;AAAA,EACtE;AAAA;AAGF,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,YAAY,IAAI;AAEtB,SAAS,WAAW,CAAC,KAAmD;AAAA,EACtE,MAAM,SAAS,IAAI,QAAQ;AAAA,EAC3B,IAAI,OAAO,WAAW,UAAU;AAAA,IAC9B,OAAO;AAAA,EACT;AAAA,EACA,OAAO,OACJ,YAAY,EACZ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,KAAK,CAAC,SAAS,SAAS,UAAU,SAAS,OAAO,KAAK,WAAW,OAAO,CAAC;AAAA;AAI/E,SAAS,UAAU,CAAC,MAAc,SAAiB,MAAsB;AAAA,EACvE,MAAM,SAAS,UAAU,IAAI,IAAI;AAAA,EACjC,IAAI,WAAW,aAAa,OAAO,YAAY,SAAS;AAAA,IACtD,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,MAAM,OAAO,SAAS,IAAI;AAAA,EAC1B,IAAI,UAAU,QAAQ,gBAAgB;AAAA,IACpC,MAAM,SAAS,UAAU,KAAK,EAAE,KAAK,EAAE;AAAA,IACvC,IAAI,WAAW,WAAW;AAAA,MACxB,UAAU,OAAO,MAAM;AAAA,IACzB;AAAA,EACF;AAAA,EACA,UAAU,IAAI,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,EACrC,OAAO;AAAA;AAGT,SAAS,UAAU,CAAC,KAAyC,OAAqB;AAAA,EAChF,MAAM,WAAW,IAAI,UAAU,MAAM;AAAA,EACrC,IAAI,OAAO,aAAa,YAAY,SAAS,SAAS,GAAG;AAAA,IACvD,IAAI,CAAC,SAAS,YAAY,EAAE,SAAS,KAAK,GAAG;AAAA,MAC3C,IAAI,UAAU,QAAQ,GAAG,aAAa,OAAO;AAAA,IAC/C;AAAA,IACA;AAAA,EACF;AAAA,EACA,IAAI,UAAU,QAAQ,KAAK;AAAA;AAG7B,SAAS,iBAAiB,CAAC,KAA+C;AAAA,EACxE,IAAI,aAAa;AAAA,EACjB,IAAI,UAAU,gBAAgB,2BAA2B;AAAA,EACzD,IAAI,IAAI,aAAa;AAAA;AAIvB,SAAS,mBAAmB,CAAC,OAAe,MAA6B;AAAA,EACvE,MAAM,YAAY,CAAC,WAA2B,QAAQ,KAAW,QAAQ,CAAC;AAAA,EAC1E,OAAO,IAAI,YAAW;AAAA,IACpB,MAAM;AAAA,IACN,SACE,SAAS,OACL,oBAAoB,UAAU,KAAK,eACnC,QAAQ,UAAU,IAAI,oBAAoB,UAAU,KAAK;AAAA,IAC/D,SACE;AAAA,IACF,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC,EAAE,OAAO;AAAA;AAIL,SAAS,iBAAiB,CAAC,WAAmB,UAAiC;AAAA,EACpF,MAAM,SAAS,iBAAiB,WAAW,QAAQ;AAAA,EACnD,OAAO,WAAW,QAAQ,OAAO,MAAM,IAAI,SAAS;AAAA;AAO/C,SAAS,gBAAgB,CAAC,WAAmB,UAAiC;AAAA,EACnF,IAAI;AAAA,EACJ,IAAI;AAAA,IACF,UAAU,mBAAmB,QAAQ;AAAA,IACrC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAIT,MAAM,QAAQ,WAAW,WAAW,IAAI,SAAS;AAAA,EACjD,IAAI,UAAU,QAAQ,OAAO,KAAK,GAAG;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EAIA,MAAM,aAAa,QAAQ,SAAS,IAAI,QAAQ,QAAQ,QAAQ,EAAE,IAAI;AAAA,EACtE,MAAM,WAAW,sBAAsB,SAAS;AAAA,EAChD,IAAI,SAAS,MAAM,IAAI,UAAU,GAAG;AAAA,IAClC,MAAM,SAAS,eAAe,MAAM,eAAe,GAAG,WAAW,MAAM,CAAC;AAAA,IACxE,OAAO,WAAW,WAAW,KAAK,QAAQ;AAAA,EAC5C;AAAA,EAEA,OAAO;AAAA;AAGT,SAAS,UAAU,CAAC,WAAmB,UAAiC;AAAA,EACtE,MAAM,YAAY,QAAQ,WAAW,QAAQ;AAAA,EAC7C,IAAI,cAAc,aAAa,CAAC,UAAU,WAAW,YAAY,GAAG,GAAG;AAAA,IACrE,OAAO;AAAA,EACT;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,MAAM,CAAC,MAAuB;AAAA,EACrC,OAAO,WAAW,IAAI,KAAK,UAAS,IAAI,EAAE,OAAO;AAAA;AAQnD,IAAI,yBAEO;AAEX,SAAS,qBAAqB,CAAC,WAA0C;AAAA,EACvE,MAAM,OAAO,KAAK,WAAW,uBAAuB;AAAA,EACpD,MAAM,QAA+B,EAAE,OAAO,IAAI,KAAO,YAAY,IAAI,IAAM;AAAA,EAC/E,IAAI;AAAA,IACF,MAAM,UAAU,UAAS,IAAI,EAAE;AAAA,IAC/B,IACE,2BAA2B,QAC3B,uBAAuB,SAAS,QAChC,uBAAuB,YAAY,SACnC;AAAA,MACA,OAAO,uBAAuB;AAAA,IAChC;AAAA,IACA,MAAM,OAAO,KAAK,MAAM,cAAa,MAAM,MAAM,CAAC;AAAA,IAKlD,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,aAAa,IAAI;AAAA,IACvB,IAAI,MAAM,QAAQ,KAAK,KAAK,GAAG;AAAA,MAE7B,WAAW,QAAQ,KAAK,OAAO;AAAA,QAC7B,IAAI,OAAO,SAAS,UAAU;AAAA,UAC5B,MAAM,IAAI,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IACA,IAAI,MAAM,QAAQ,KAAK,OAAO,GAAG;AAAA,MAE/B,WAAW,SAAS,KAAK,SAA2C;AAAA,QAClE,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,MAAM,YAAY,UAAU;AAAA,UACpF;AAAA,QACF;AAAA,QACA,MAAM,OAAO,MAAM;AAAA,QACnB,MAAM,IAAI,IAAI;AAAA,QACd,MAAM,UAAU,MAAM;AAAA,QACtB,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,OAAO,KAAK,WAAW,GAAG;AAAA,UAC3E,WAAW,IAAI,MAAM,OAAO;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,EAAE,OAAO,WAAW;AAAA,IACjC,yBAAyB,EAAE,MAAM,SAAS,KAAK;AAAA,IAC/C,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAKX,SAAS,oBAAoB,CAAC,OASrB;AAAA,EACP,MAAM,aAAa,MAAM,SAAS,SAAS,IAAI,MAAM,SAAS,QAAQ,QAAQ,EAAE,IAAI,MAAM;AAAA,EAC1F,MAAM,UAAU,sBAAsB,MAAM,SAAS,EAAE,WAAW,IAAI,UAAU;AAAA,EAChF,IAAI,YAAY,aAAa,UAAU,GAAG;AAAA,IACxC;AAAA,EACF;AAAA,EACA,IAAI,CAAC,iBAAiB,EAAE,SAAS,MAAM,SAAS,mBAAmB,QAAQ,CAAC,GAAG;AAAA,IAC7E;AAAA,EACF;AAAA,EACA,MAAM,gBAAgB,YAAY,IAAI;AAAA,EACtC,MAAM,SAAS,MAAM,UAAU;AAAA,EAC1B,sBAAsB;AAAA,IACzB,UAAU;AAAA,OACN,MAAM,SAAS,YAAY,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK;AAAA,OACnD,MAAM,YAAY,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;AAAA,IAChE,SAAS,MAAM;AAAA,OACX,MAAM,QAAQ,WAAW,YAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,OAAO;AAAA,IAC7E,KAAK,QAAQ;AAAA,EACf,CAAC,EACE,KAAK,MAAM;AAAA,IACV,SAAS;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,MACN,YAAY,KAAK,MAAM,YAAY,IAAI,IAAI,aAAa;AAAA,IAC1D,CAAC;AAAA,GACF,EACA,MAAM,CAAC,UAAmB;AAAA,IACzB,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IACrE,IAAI,WAAW,MAAM;AAAA,MACnB,OAAO,EAAE,KAAK,yBAAyB,OAAO,QAAQ,MAAM,YAAY,OAAO,QAAQ,CAAC;AAAA,IAC1F,EAAO;AAAA,MACL,QAAQ,MAAM,oCAAoC,gBAAgB,SAAS;AAAA;AAAA,GAE9E;AAAA;;AKpfE,SAAS,gBAAgB,CAC9B,SACA,UAAU,oBACE;AAAA,EACZ,MAAM,QACJ,QAAQ,UACP,CAAC,QAAQ,SAAS,MAAM,SAAS,aAAY,mBAAkB,QAAQ,SAAS,IAAI;AAAA,EAEvF,MAAM,UAAU,qBAAqB;AAAA,IACnC,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,WAAW,QAAQ;AAAA,OACf,QAAQ,cAAc,YAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,OACtE,QAAQ,YAAY,YAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;AAAA,OAChE,QAAQ,mBAAmB,YAAY,CAAC,IAAI,EAAE,gBAAgB,QAAQ,eAAe;AAAA,OACrF,QAAQ,sBAAsB,YAC9B,CAAC,IACD,EAAE,mBAAmB,QAAQ,kBAAkB;AAAA,IACnD;AAAA,EACF,CAAC;AAAA,EAED,OAAO;AAAA,IACL;AAAA,IACA,OAAO,CAAC,OAAe,SACrB,QAAQ,IAAI,QAAQ,IAAI,IAAI,OAAO,OAAO,GAAG,IAAI,CAAC;AAAA,EACtD;AAAA;;ACtDF;AA2BO,SAAS,mBAAmB,CAAC,SAA8C;AAAA,EAChF,MAAM,MAAM,QAAQ,QAAQ,CAAC,YAAoB,QAAQ,KAAK,OAAO;AAAA,EACrE,MAAM,UAAU,QAAQ,OAAO,WAAW,CAAC;AAAA,EAC3C,MAAM,QAAQ,EAAE,OAAO,OAAO,SAAS,cAAc;AAAA,EACrD,MAAM,MAAM;AAAA,EACZ,MAAM,aAA+C,CAAC;AAAA,EACtD,MAAM,WAAW,CAAC,OAAwC;AAAA,IACxD,WAAW,KAAK,EAAE;AAAA;AAAA,EAIpB,WAAW,UAAU,SAAS;AAAA,IAC5B,WAAW,SAAS,QAAQ,QAAQ;AAAA,MAElC,MAAM,SAAS,OAAO,OAAO;AAAA,WACxB;AAAA,QACH,QAAQ,CAAC,GAAG,MAAM,MAAM;AAAA,MAC1B,CAAC;AAAA,MACD,OAAO,WAAW,MAAM;AAAA,IAC1B;AAAA,IACA,WAAW,cAAc,QAAQ,aAAa;AAAA,MAC5C,OAAO,gBAAgB,UAAU;AAAA,IACnC;AAAA,IACA,OAAO,gBAAgB,QAAiB;AAAA,EAC1C;AAAA,EAEA,OAAO;AAAA,IACL;AAAA,SACM,MAAK,GAAkB;AAAA,MAC3B,WAAW,UAAU,SAAS;AAAA,QAC5B,MAAM,OAAO,UAAU,GAAG;AAAA,MAC5B;AAAA;AAAA,SAEI,MAAK,GAAkB;AAAA,MAC3B,MAAM,QAAQ;AAAA,MACd,WAAW,UAAU,SAAS;AAAA,QAC5B,MAAM,OAAO,UAAU,GAAG;AAAA,MAC5B;AAAA;AAAA,SAEI,SAAQ,GAAkB;AAAA,MAC9B,WAAW,UAAU,SAAS;AAAA,QAC5B,IAAI;AAAA,UACF,MAAM,OAAO,aAAa,GAAG;AAAA,UAC7B,OAAO,OAAO;AAAA,UACd,IAAI,oBAAoB,OAAO,oCAAoC,OAAO,KAAK,GAAG;AAAA;AAAA,MAEtF;AAAA;AAAA,IAEF,eAAe,CAAC,KAAoB;AAAA,MAClC,WAAW,UAAU,YAAY;AAAA,QAC/B,MAAM,SAAS,OAAO,GAAG;AAAA,QACzB,IAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAAA,UAC3E,OAAO,OAAO,KAAgC,MAAM;AAAA,QACtD;AAAA,MACF;AAAA;AAAA,EAEJ;AAAA;;ACnFF,uBAAS;AACT,sBAAS,6BAAW;AACpB,oBAAS,kBAAS,kBAAM,iBAAS;AAuC1B,IAAM,0BAA0B;AAOhC,IAAM,qBAAqB;AAG3B,IAAM,iBAAiB;AAE9B,eAAsB,YAAY,CAAC,SAAqD;AAAA,EACtF,MAAM,MAAM,QAAQ,QAAQ,CAAC,YAAoB,QAAQ,IAAI,OAAO;AAAA,EACpE,MAAM,MAAM,QAAQ,OAAO,QAAQ;AAAA,EACnC,IAAI,UAAU;AAAA,EACd,IAAI,UAAU;AAAA,EACd,MAAM,UAAwD,CAAC;AAAA,EAE/D,MAAM,QAAQ,QAAQ,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM;AAAA,EACpE,WAAW,SAAS,OAAO;AAAA,IACzB,MAAM,MAAM,WAAW,QAAQ,WAAW,MAAM,IAAI;AAAA,IACpD,MAAM,OAAO,QAAQ,UAAU;AAAA,IAC/B,IAAI,SAAS,WAAW;AAAA,MACtB;AAAA,IACF;AAAA,IACA,MAAM,SAAU,MAAM,KAAK;AAAA,IAC3B,MAAM,YAAY,OAAO;AAAA,IACzB,MAAM,aAAa,OAAO;AAAA,IAG1B,IAAI,eAAe,WAAW;AAAA,MAC5B,IACE,OAAO,eAAe,YACtB,CAAC,OAAO,SAAS,UAAU,KAC3B,aAAa,KACb,cAAc,MACd;AAAA,QACA,MAAM,IAAI,YAAW;AAAA,UACnB,MAAM;AAAA,UACN,MAAM,MAAM;AAAA,UACZ,SAAS;AAAA,UACT,SAAS;AAAA,UACT,aAAa;AAAA,YACX;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,IAAI,cAAc,MAAM;AAAA,MACtB,IAAI,cAAc,aAAa,cAAc,OAAO;AAAA,QAClD,MAAM,eAAe,OAAO,gDAAgD;AAAA,MAC9E;AAAA,MACA;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,MAAM,iBAAiB,OAAO,MAAM;AAAA,IACtD,WAAW,YAAY,WAAW;AAAA,MAChC,MAAM,WAAW,MAAM,QAAQ,QAC7B,IAAI,QAAQ,mBAAmB,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS,EAAE,qBAAqB,IAAI;AAAA,MACtC,CAAC,CACH;AAAA,MAEA,IAAI,SAAS,WAAW,KAAK;AAAA,QAC3B,IAAI,8BAA8B,qBAAqB;AAAA,QACvD,WAAW;AAAA,QACX;AAAA,MACF;AAAA,MACA,IAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AAAA,QACnD,MAAM,eAAe,OAAO,qDAAqD,WAAW;AAAA,MAC9F;AAAA,MACA,IAAI,SAAS,WAAW,KAAK;AAAA,QAC3B,MAAM,eAAe,OAAO,UAAU,SAAS,0BAA0B,UAAU;AAAA,MACrF;AAAA,MAEA,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,MACjC,aAAa,MAAM,UAAU,MAAM,MAAM,SAAS,GAAG;AAAA,MAErD,MAAM,OAAO,WAAW,QAAQ,WAAW,QAAQ;AAAA,MACnD,WAAU,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,MAC5C,eAAc,MAAM,IAAI;AAAA,MACxB,QAAQ,KACN,OAAO,eAAe,YAAY,cAAc,IAC5C,EAAE,MAAM,UAAU,WAAW,IAC7B,EAAE,MAAM,SAAS,CACvB;AAAA,MACA,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EAGA,MAAM,WAAW,MAAM,qBAAqB,SAAS,KAAK,GAAG;AAAA,EAC7D,IAAI,WAAW;AAAA,EACf,IAAI,aAAa,MAAM;AAAA,IACrB,eAAc,MAAK,QAAQ,WAAW,cAAc,GAAG,QAAQ;AAAA,IAC/D,WAAW;AAAA,EACb;AAAA,EAGA,eACE,MAAK,QAAQ,WAAW,uBAAuB,GAC/C,GAAG,KAAK,UAAU,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAAA,CACpD;AAAA,EAGA,MAAM,UAAU,gBAAgB,QAAQ,WAAW,QAAQ,cAAc,OAAO;AAAA,EAEhF,MAAM,SAAS,CAAC,GAAI,WAAW,CAAC,cAAc,IAAI,CAAC,GAAI,GAAG,OAAO;AAAA,EACjE,IACE,2BAA2B,eAAe,OAAO,SAAS,IAAI,MAAM,OAAO,KAAK,KAAK,MAAM,OAAO,kBACpG;AAAA,EACA,OAAO,EAAE,SAAS,QAAQ;AAAA;AAI5B,SAAS,eAAe,CACtB,WACA,cACA,SACU;AAAA,EACV,IAAI,iBAAiB,WAAW;AAAA,IAC9B,OAAO,CAAC;AAAA,EACV;AAAA,EACA,MAAM,UAAoB,CAAC;AAAA,EAE3B,MAAM,UAAU,OAAO,QAAQ,aAAa,WAAW,CAAC,CAAC;AAAA,EACzD,IAAI,QAAQ,SAAS,GAAG;AAAA,IACtB,MAAM,QAAQ,CAAC,MAAM,GAAG,QAAQ,IAAI,EAAE,MAAM,WAAW,KAAK,SAAS,OAAO,CAAC;AAAA,IAC7E,eAAc,MAAK,WAAW,UAAU,GAAG,GAAG,MAAM,KAAK;AAAA,CAAI;AAAA,CAAK;AAAA,IAClE,QAAQ,KAAK,UAAU;AAAA,EACzB;AAAA,EAEA,MAAM,YAAY,aAAa,aAAa,CAAC;AAAA,EAC7C,IAAI,UAAU,SAAS,GAAG;AAAA,IACxB,MAAM,QAAQ,UAAU,IAAI,CAAC,UAAU,GAAG,MAAM,QAAQ,MAAM,MAAM,MAAM,UAAU,KAAK;AAAA,IACzF,eAAc,MAAK,WAAW,YAAY,GAAG,GAAG,MAAM,KAAK;AAAA,CAAI;AAAA,CAAK;AAAA,IACpE,QAAQ,KAAK,YAAY;AAAA,EAC3B;AAAA,EAEA,MAAM,UAAU,aAAa;AAAA,EAC7B,IAAI,YAAY,WAAW;AAAA,IACzB,MAAM,OAAO,QAAQ,KAAK,QAAQ,OAAO,EAAE;AAAA,IAC3C,MAAM,UAAU,QAAQ,WAAW,CAAC;AAAA,IACpC,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC,CAAC,EAC1D,OAAO,CAAC,SAAS,CAAC,QAAQ,KAAK,CAAC,WAAW,KAAK,WAAW,MAAM,CAAC,CAAC,EACnE,KAAK;AAAA,IACR,MAAM,MAAM;AAAA,MACV;AAAA,MACA;AAAA,MACA,GAAG,MAAM,IAAI,CAAC,SAAS,eAAe,OAAO,SAAS,MAAM,MAAM,kBAAkB;AAAA,MACpF;AAAA,MACA;AAAA,IACF,EAAE,KAAK;AAAA,CAAI;AAAA,IACX,eAAc,MAAK,WAAW,aAAa,GAAG,GAAG;AAAA,IACjD,QAAQ,KAAK,aAAa;AAAA,EAC5B;AAAA,EAEA,MAAM,SAAS,aAAa;AAAA,EAC5B,IAAI,WAAW,WAAW;AAAA,IACxB,MAAM,QAAQ,CAAC,eAAe;AAAA,IAC9B,WAAW,QAAQ,OAAO,YAAY,CAAC,GAAG;AAAA,MACxC,MAAM,KAAK,aAAa,MAAM;AAAA,IAChC;AAAA,IACA,KAAK,OAAO,WAAW,SAAS,YAAY,WAAW;AAAA,MACrD,MAAM,KAAK,IAAI,YAAY,QAAQ,KAAK,QAAQ,OAAO,EAAE,eAAe;AAAA,IAC1E;AAAA,IACA,eAAc,MAAK,WAAW,YAAY,GAAG,GAAG,MAAM,KAAK;AAAA,CAAI;AAAA,CAAK;AAAA,IACpE,QAAQ,KAAK,YAAY;AAAA,EAC3B;AAAA,EAEA,OAAO;AAAA;AAQT,eAAe,oBAAoB,CACjC,SACA,KACA,KACwB;AAAA,EACxB,IAAI,CAAC,QAAQ,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,KAAK,GAAG;AAAA,IACzD,OAAO;AAAA,EACT;AAAA,EACA,MAAM,WAAW,MAAM,QAAQ,QAC7B,IAAI,QAAQ,mBAAmB,sBAAsB;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,EAAE,qBAAqB,IAAI;AAAA,EACtC,CAAC,CACH;AAAA,EACA,IAAI,SAAS,WAAW,KAAK;AAAA,IAC3B,IACE,sBAAsB,sCAAsC,0BAA0B,SAAS,SACjG;AAAA,IACA,OAAO;AAAA,EACT;AAAA,EACA,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,EACjC,aAAa,MAAM,oBAAoB,gBAAgB,SAAS,GAAG;AAAA,EACnE,OAAO;AAAA;AAIT,SAAS,YAAY,CACnB,MACA,UACA,MACA,SACA,KACM;AAAA,EACN,MAAM,WAAW,sBAAsB,MAAM;AAAA,OACvC,QAAQ,WAAW,YAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,IACjE;AAAA,EACF,CAAC;AAAA,EACD,IAAI,SAAS,WAAW,GAAG;AAAA,IACzB;AAAA,EACF;AAAA,EACA,MAAM,SAAS,SACZ,IAAI,CAAC,YAAa,QAAQ,SAAS,WAAW,WAAW,OAAO,QAAQ,QAAS,EACjF,KAAK,IAAI;AAAA,EACZ,MAAM,IAAI,YAAW;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA,SAAS,sBAAsB,uBAAuB;AAAA,IACtD,SAAS;AAAA,IACT,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAAA;AAGH,SAAS,UAAU,CAAC,WAAmB,MAAsB;AAAA,EAC3D,MAAM,WAAW,KAAK,WAAW,SAAS,IAAI,KAAK,MAAM,UAAU,SAAS,CAAC,IAAI;AAAA,EACjF,OAAO,SAAS,MAAM,IAAI,EAAE,KAAK,GAAG,EAAE,QAAQ,eAAe,EAAE;AAAA;AAGjE,eAAe,gBAAgB,CAAC,OAAwB,QAAwC;AAAA,EAC9F,MAAM,YAAY,MAAM,OAAO,SAAS;AAAA,EACxC,IAAI,CAAC,WAAW;AAAA,IACd,OAAO,CAAC,MAAM,IAAI;AAAA,EACpB;AAAA,EACA,MAAM,QAAQ,OAAO;AAAA,EACrB,IAAI,OAAO,UAAU,YAAY;AAAA,IAC/B,MAAM,IAAI,YAAW;AAAA,MACnB,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,SAAS;AAAA,MACT,SAAS;AAAA,MACT,aAAa;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,MAAO,MAA2C;AAAA,EAC9D,IAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AAAA,IACvB,MAAM,eAAe,OAAO,gCAAgC;AAAA,EAC9D;AAAA,EAEA,MAAM,WAAW,IAAI,IAAI,MAAM,MAAM;AAAA,EACrC,MAAM,SAAmB,CAAC;AAAA,EAC1B,WAAW,QAAQ,KAAkB;AAAA,IACnC,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AAAA,MACpE,MAAM,eAAe,OAAO,oDAAoD;AAAA,IAClF;AAAA,IACA,MAAM,SAAS;AAAA,IACf,MAAM,OAAO,OAAO,KAAK,MAAM;AAAA,IAC/B,WAAW,QAAQ,UAAU;AAAA,MAC3B,MAAM,QAAQ,OAAO;AAAA,MACrB,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAAG;AAAA,QACnD,MAAM,eAAe,OAAO,WAAW,mCAAmC;AAAA,MAC5E;AAAA,IACF;AAAA,IACA,WAAW,OAAO,MAAM;AAAA,MACtB,IAAI,CAAC,SAAS,IAAI,GAAG,GAAG;AAAA,QACtB,MAAM,eAAe,OAAO,WAAW,mCAAmC;AAAA,MAC5E;AAAA,IACF;AAAA,IACA,OAAO,KAAK,cAAc,OAAO,MAAgC,CAAC;AAAA,EACpE;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,aAAa,CAAC,OAAwB,QAAwC;AAAA,EACrF,MAAM,WAAW,MAAM,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,YAAY,QAAQ,SAAS,CAAC;AAAA,EAC7E,MAAM,MAAgB,CAAC;AAAA,EACvB,IAAI,eAA8B;AAAA,EAClC,WAAW,WAAW,UAAU;AAAA,IAC9B,IAAI,YAAY,KAAK;AAAA,MACnB,eAAe,MAAM,OAAO,MAAM,OAAO,SAAS,MAAM;AAAA,MACxD,MAAM,QAAQ,iBAAiB,OAAO,KAAM,OAAO,iBAAiB;AAAA,MACpE,WAAW,QAAQ,MAAM,MAAM,GAAG,GAAG;AAAA,QACnC,IAAI,KAAK,WAAW,GAAG;AAAA,UACrB;AAAA,QACF;AAAA,QACA,IAAI,KAAK,cAAc,OAAO,IAAI,CAAC;AAAA,MACrC;AAAA,MACA;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,WAAW,GAAG,GAAG;AAAA,MAC3B,IAAI,KAAK,cAAc,OAAO,OAAO,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,IAAI,KAAK,OAAO;AAAA,EAClB;AAAA,EACA,OAAO,IAAI,IAAI,KAAK,GAAG;AAAA;AAGzB,SAAS,aAAa,CAAC,OAAwB,OAAuB;AAAA,EACpE,IAAI,MAAM,WAAW,KAAK,QAAQ,KAAK,KAAK,GAAG;AAAA,IAC7C,MAAM,eAAe,OAAO,iBAAiB,sCAAsC;AAAA,EACrF;AAAA,EACA,OAAO,mBAAmB,KAAK;AAAA;AAGjC,SAAS,UAAU,CAAC,WAAmB,UAA0B;AAAA,EAC/D,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAAA,EAClE,MAAM,OAAO,SAAQ,MAAK,WAAW,GAAG,OAAO,YAAY,CAAC;AAAA,EAC5D,MAAM,OAAO,SAAQ,SAAS;AAAA,EAC9B,IAAI,SAAS,QAAQ,CAAC,KAAK,WAAW,OAAO,IAAG,GAAG;AAAA,IACjD,MAAM,IAAI,YAAW;AAAA,MACnB,MAAM;AAAA,MACN,SAAS,kDAAkD;AAAA,MAC3D,SAAS;AAAA,MACT,aAAa,CAAC,kDAAkD;AAAA,IAClE,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,cAAc,CAAC,OAAwB,SAA6B;AAAA,EAC3E,OAAO,IAAI,YAAW;AAAA,IACpB,MAAM;AAAA,IACN,MAAM,MAAM;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,IACT,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAAA;",
|
|
17
|
+
"debugId": "ACB67C3B410A13D264756E2164756E21",
|
|
18
18
|
"names": []
|
|
19
19
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { MoonsConfig, RouteDefinition, RouteModule } from "@moonsjs/core";
|
|
2
|
+
import { type RequestHandlerOptions } from "./handler";
|
|
2
3
|
import { type Shell } from "./shell";
|
|
3
4
|
export interface TestServerOptions {
|
|
4
5
|
routes: RouteDefinition[];
|
|
5
6
|
config: MoonsConfig;
|
|
6
7
|
routesDir: string;
|
|
7
8
|
loadRoute: Record<string, () => Promise<RouteModule>>;
|
|
9
|
+
/** Endpoint `src/api` (Addendum O) — hasil scan app. */
|
|
10
|
+
apiRoutes?: RequestHandlerOptions["apiRoutes"];
|
|
11
|
+
loadApi?: RequestHandlerOptions["loadApi"];
|
|
12
|
+
apiMiddlewares?: RequestHandlerOptions["apiMiddlewares"];
|
|
13
|
+
loadApiMiddleware?: RequestHandlerOptions["loadApiMiddleware"];
|
|
8
14
|
/** Default: shell in-memory dari `DEFAULT_TEMPLATE` (tanpa file). */
|
|
9
15
|
shell?: Shell;
|
|
10
16
|
}
|