@ramonyx/bundler 0.1.0 → 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/README.md +1 -1
- package/dist/assets.d.ts +39 -0
- package/dist/assets.js +105 -0
- package/dist/assets.js.map +1 -0
- package/dist/build.d.ts +23 -6
- package/dist/build.js +99 -8
- package/dist/build.js.map +1 -1
- package/dist/dev.d.ts +6 -0
- package/dist/dev.js +122 -2
- package/dist/dev.js.map +1 -1
- package/dist/devtools.d.ts +43 -0
- package/dist/devtools.js +146 -0
- package/dist/devtools.js.map +1 -0
- package/dist/edge.d.ts +28 -0
- package/dist/edge.js +91 -0
- package/dist/edge.js.map +1 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +20 -0
- package/dist/manifest.js +29 -0
- package/dist/manifest.js.map +1 -0
- package/dist/plugin.d.ts +27 -0
- package/dist/plugin.js +41 -0
- package/dist/plugin.js.map +1 -0
- package/dist/prerender.d.ts +49 -0
- package/dist/prerender.js +104 -0
- package/dist/prerender.js.map +1 -0
- package/dist/server-only.d.ts +6 -0
- package/dist/server-only.js +69 -0
- package/dist/server-only.js.map +1 -0
- package/package.json +3 -3
package/dist/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../packages/bundler/src/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport type { ServerResponse } from \"node:http\";\nimport { join, relative } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport {\n generateClientEntry,\n loadPageRoutes,\n type ModuleImporter,\n RouteManifestError,\n} from \"@ramonyx/compiler\";\nimport { type Connect, createServer } from \"vite\";\n\nexport interface DevServerOptions {\n readonly appDir: string;\n /** URL server SSR yang diproksikan (mis. \"http://localhost:3000\"). */\n readonly target: string;\n readonly port?: number;\n}\n\nexport interface DevServer {\n readonly url: string;\n /** Importer untuk compiler: modul mengikuti module graph Vite (invalidasi saat file berubah). */\n readonly importer: ModuleImporter;\n readonly target: string;\n close(): Promise<void>;\n}\n\nconst ENTRY_FILE = \"client-entry.ts\";\n\n/** Path yang dimiliki Vite (jangan diproksikan ke SSR). */\nfunction isViteRequest(url: string): boolean {\n const path = url.split(\"?\")[0] ?? \"\";\n return (\n path.startsWith(\"/@\") ||\n path.startsWith(\"/node_modules/\") ||\n path.startsWith(\"/.ramonyx/\") ||\n path.startsWith(\"/src/\") ||\n path === \"/favicon.ico\"\n );\n}\n\nconst HOP_BY_HOP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"content-length\",\n \"content-encoding\",\n]);\n\n/**\n * Proxy manual ke SSR (bukan `server.proxy` Vite): request non-Vite diteruskan dengan `fetch`,\n * respons dipipe kembali apa adanya. Body request non-GET/HEAD dialirkan via `Readable.toWeb`.\n */\nasync function proxyToSsr(\n target: string,\n req: Connect.IncomingMessage,\n res: ServerResponse,\n next: Connect.NextFunction,\n): Promise<void> {\n try {\n const url = new URL(req.url ?? \"/\", target);\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(name, item);\n }\n } else {\n headers.set(name, value);\n }\n }\n\n const method = req.method ?? \"GET\";\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n redirect: \"manual\",\n };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = Readable.toWeb(req) as unknown as BodyInit;\n init.duplex = \"half\";\n }\n\n const response = await fetch(url, init);\n res.statusCode = response.status;\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\" && !HOP_BY_HOP.has(name)) {\n res.setHeader(name, value);\n }\n });\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) {\n res.setHeader(\"set-cookie\", cookies);\n }\n\n if (response.body === null) {\n res.end();\n return;\n }\n await pipeline(Readable.fromWeb(response.body as never), res);\n } catch (error) {\n next(error);\n }\n}\n\n/**\n * Dev server: Vite (transform + HMR) sebagai front, proxy ke server SSR.\n * Modul halaman/manifest dimuat lewat `vite.ssrLoadModule` agar SSR ikut segar saat file berubah\n * (tanpa restart); perubahan di `src/routes` meregenerasi entry client + full-reload browser.\n */\nexport async function createDevServer(options: DevServerOptions): Promise<DevServer> {\n const appDir = options.appDir;\n const entryDir = join(appDir, \".ramonyx\");\n const entryFile = join(entryDir, ENTRY_FILE);\n const routesDir = join(appDir, \"src\", \"routes\");\n\n const vite = await createServer({\n configFile: false,\n root: appDir,\n appType: \"custom\",\n logLevel: \"info\",\n esbuild: { jsx: \"automatic\" },\n server: { port: options.port ?? 5173 },\n plugins: [\n {\n name: \"ramonyx-ssr-proxy\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n if (req.url === undefined || isViteRequest(req.url)) {\n next();\n return;\n }\n void proxyToSsr(options.target, req, res, next);\n });\n },\n },\n ],\n });\n\n const importer: ModuleImporter = async (absolute, label) => {\n try {\n return (await vite.ssrLoadModule(absolute)) as Record<string, unknown>;\n } catch (error) {\n throw new RouteManifestError(\n `[dev] gagal memuat ${label} (${relative(appDir, absolute) || absolute}) via Vite: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }\n };\n\n const regenerateEntry = async (): Promise<void> => {\n const pages = await loadPageRoutes({ dir: routesDir, importer });\n await mkdir(entryDir, { recursive: true });\n await writeFile(entryFile, generateClientEntry(pages, { from: entryDir }));\n };\n await regenerateEntry();\n\n vite.watcher.on(\"all\", (_event, file) => {\n if (!file.startsWith(routesDir)) {\n return;\n }\n void regenerateEntry()\n .catch(() => undefined)\n .finally(() => {\n vite.ws.send({ type: \"full-reload\" });\n });\n });\n\n await vite.listen();\n const address = vite.httpServer?.address();\n const port =\n typeof address === \"object\" && address !== null ? address.port : (options.port ?? 5173);\n\n return {\n url: `http://localhost:${port}`,\n importer,\n target: options.target,\n close: () => vite.close(),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../../packages/bundler/src/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport type { ServerResponse } from \"node:http\";\nimport { extname, join, relative } from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport {\n generateClientEntry,\n loadPageRoutes,\n type ModuleImporter,\n RouteManifestError,\n} from \"@ramonyx/compiler\";\nimport { type Connect, createServer, type Plugin, type PluginOption } from \"vite\";\nimport { createDevtoolsCollector, type DevtoolsCollector, devtoolsPanelHtml } from \"./devtools.ts\";\nimport { readAssetManifest } from \"./manifest.ts\";\nimport { serverOnlyPlugin } from \"./server-only.ts\";\n\nexport interface DevServerOptions {\n readonly appDir: string;\n /** URL server SSR yang diproksikan (mis. \"http://localhost:3000\"). */\n readonly target: string;\n readonly port?: number;\n /** Plugin Vite tambahan (dari plugin Ramonyx — ADR-0067). */\n readonly plugins?: readonly PluginOption[];\n}\n\nexport interface DevServer {\n readonly url: string;\n /** Importer untuk compiler: modul mengikuti module graph Vite (invalidasi saat file berubah). */\n readonly importer: ModuleImporter;\n readonly target: string;\n /** Kolektor panel devtools (ADR-0077) — pasang `hooks`/`middleware`-nya ke handler aplikasi. */\n readonly devtools: DevtoolsCollector;\n close(): Promise<void>;\n}\n\nconst ENTRY_FILE = \"client-entry.ts\";\n\nconst DEV_ASSET_TYPES: Record<string, string> = {\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n};\n\n/**\n * Dev: sajikan `src/assets/**` apa adanya di `/assets/*` (tanpa hash) — paritas dengan\n * resolver aset dev (`createAssetResolver(..., { fallbackToPath: true })`, ADR-0069).\n */\nfunction assetsDevPlugin(appDir: string): Plugin {\n return {\n name: \"ramonyx-assets-dev\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = req.url ?? \"\";\n if (!url.startsWith(\"/assets/\")) {\n next();\n return;\n }\n let rel: string;\n try {\n rel = decodeURIComponent(url.slice(\"/assets/\".length).split(\"?\")[0] ?? \"\");\n } catch {\n next();\n return;\n }\n if (rel.length === 0 || rel.includes(\"..\")) {\n next();\n return;\n }\n const file = join(appDir, \"src\", \"assets\", rel);\n if (!existsSync(file)) {\n next();\n return;\n }\n void readFile(file)\n .then((data) => {\n res.setHeader(\n \"content-type\",\n DEV_ASSET_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\",\n );\n res.setHeader(\"cache-control\", \"no-cache\");\n res.end(data);\n })\n .catch(() => next());\n });\n },\n };\n}\n\n/** Path yang dimiliki Vite (jangan diproksikan ke SSR). */\nfunction isViteRequest(url: string): boolean {\n const path = url.split(\"?\")[0] ?? \"\";\n return (\n path.startsWith(\"/@\") ||\n path.startsWith(\"/node_modules/\") ||\n path.startsWith(\"/.ramonyx/\") ||\n path.startsWith(\"/src/\") ||\n path === \"/favicon.ico\"\n );\n}\n\nconst HOP_BY_HOP = new Set([\n \"connection\",\n \"keep-alive\",\n \"transfer-encoding\",\n \"content-length\",\n \"content-encoding\",\n]);\n\n/**\n * Proxy manual ke SSR (bukan `server.proxy` Vite): request non-Vite diteruskan dengan `fetch`,\n * respons dipipe kembali apa adanya. Body request non-GET/HEAD dialirkan via `Readable.toWeb`.\n */\nasync function proxyToSsr(\n target: string,\n req: Connect.IncomingMessage,\n res: ServerResponse,\n next: Connect.NextFunction,\n): Promise<void> {\n try {\n const url = new URL(req.url ?? \"/\", target);\n const headers = new Headers();\n for (const [name, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(name, item);\n }\n } else {\n headers.set(name, value);\n }\n }\n\n const method = req.method ?? \"GET\";\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n redirect: \"manual\",\n };\n if (method !== \"GET\" && method !== \"HEAD\") {\n init.body = Readable.toWeb(req) as unknown as BodyInit;\n init.duplex = \"half\";\n }\n\n const response = await fetch(url, init);\n res.statusCode = response.status;\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\" && !HOP_BY_HOP.has(name)) {\n res.setHeader(name, value);\n }\n });\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) {\n res.setHeader(\"set-cookie\", cookies);\n }\n\n if (response.body === null) {\n res.end();\n return;\n }\n await pipeline(Readable.fromWeb(response.body as never), res);\n } catch (error) {\n next(error);\n }\n}\n\n/**\n * Dev server: Vite (transform + HMR) sebagai front, proxy ke server SSR.\n * Modul halaman/manifest dimuat lewat `vite.ssrLoadModule` agar SSR ikut segar saat file berubah\n * (tanpa restart); perubahan di `src/routes` meregenerasi entry client + full-reload browser.\n */\nexport async function createDevServer(options: DevServerOptions): Promise<DevServer> {\n const appDir = options.appDir;\n const entryDir = join(appDir, \".ramonyx\");\n const entryFile = join(entryDir, ENTRY_FILE);\n const routesDir = join(appDir, \"src\", \"routes\");\n\n const devtools = createDevtoolsCollector();\n const clientDir = join(appDir, \"dist\", \"client\");\n\n /** Ukuran bundel/aset dari manifest build (bila sudah pernah dibangun). */\n const refreshAssets = async (): Promise<void> => {\n const manifest = await readAssetManifest(clientDir);\n if (manifest === null) {\n devtools.setAssets([]);\n return;\n }\n const names = new Set<string>([manifest.client, ...manifest.files]);\n const entries: { name: string; bytes: number }[] = [];\n for (const name of names) {\n try {\n const info = await stat(join(clientDir, name));\n entries.push({ name, bytes: info.size });\n } catch {\n // berkas hilang (mis. dibersihkan) — lewati\n }\n }\n if (manifest.assets !== undefined) {\n for (const entry of Object.values(manifest.assets)) {\n entries.push({ name: entry.file, bytes: entry.bytes });\n }\n }\n devtools.setAssets(entries);\n };\n\n const vite = await createServer({\n configFile: false,\n root: appDir,\n appType: \"custom\",\n logLevel: \"info\",\n esbuild: { jsx: \"automatic\" },\n server: { port: options.port ?? 5173 },\n plugins: [\n ...(options.plugins ?? []),\n serverOnlyPlugin(),\n assetsDevPlugin(appDir),\n {\n name: \"ramonyx-devtools\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const path = (req.url ?? \"\").split(\"?\")[0] ?? \"\";\n if (path === \"/__ramonyx/devtools\") {\n res.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n res.setHeader(\"cache-control\", \"no-store\");\n res.end(devtoolsPanelHtml());\n return;\n }\n if (path === \"/__ramonyx/data\") {\n void refreshAssets()\n .catch(() => undefined)\n .then(() => {\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"cache-control\", \"no-store\");\n res.end(JSON.stringify(devtools.snapshot()));\n });\n return;\n }\n next();\n });\n },\n },\n {\n name: \"ramonyx-ssr-proxy\",\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n if (req.url === undefined || isViteRequest(req.url)) {\n next();\n return;\n }\n void proxyToSsr(options.target, req, res, next);\n });\n },\n },\n ],\n });\n\n const importer: ModuleImporter = async (absolute, label) => {\n try {\n return (await vite.ssrLoadModule(absolute)) as Record<string, unknown>;\n } catch (error) {\n throw new RouteManifestError(\n `[dev] gagal memuat ${label} (${relative(appDir, absolute) || absolute}) via Vite: ${\n error instanceof Error ? error.message : String(error)\n }`,\n { cause: error },\n );\n }\n };\n\n const regenerateEntry = async (): Promise<void> => {\n const pages = await loadPageRoutes({ dir: routesDir, importer });\n devtools.setRoutes(\n pages.map((page) => ({\n path: page.path,\n ...(page.pageFile !== undefined ? { file: relative(appDir, page.pageFile) } : {}),\n })),\n );\n await mkdir(entryDir, { recursive: true });\n await writeFile(entryFile, generateClientEntry(pages, { from: entryDir }));\n };\n await regenerateEntry();\n\n vite.watcher.on(\"all\", (_event, file) => {\n if (!file.startsWith(routesDir)) {\n return;\n }\n void regenerateEntry()\n .catch(() => undefined)\n .finally(() => {\n vite.ws.send({ type: \"full-reload\" });\n });\n });\n\n await vite.listen();\n const address = vite.httpServer?.address();\n const port =\n typeof address === \"object\" && address !== null ? address.port : (options.port ?? 5173);\n\n return {\n url: `http://localhost:${port}`,\n importer,\n target: options.target,\n devtools,\n close: () => vite.close(),\n };\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AppHooks, Middleware } from "@ramonyx/core";
|
|
2
|
+
export interface DevtoolsRoute {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly file?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DevtoolsAsset {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly bytes: number;
|
|
9
|
+
}
|
|
10
|
+
export interface DevtoolsRequest {
|
|
11
|
+
readonly method: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
status?: number;
|
|
14
|
+
ms?: number;
|
|
15
|
+
loaderMs?: number;
|
|
16
|
+
renderMs?: number;
|
|
17
|
+
cached?: boolean;
|
|
18
|
+
/** `payload` = HTML memuat payload hydration; `none` = tidak; undefined = bukan HTML. */
|
|
19
|
+
hydration?: "payload" | "none";
|
|
20
|
+
}
|
|
21
|
+
export interface DevtoolsSnapshot {
|
|
22
|
+
readonly generatedAt: string;
|
|
23
|
+
readonly routes: readonly DevtoolsRoute[];
|
|
24
|
+
readonly assets: readonly DevtoolsAsset[];
|
|
25
|
+
readonly requests: readonly DevtoolsRequest[];
|
|
26
|
+
}
|
|
27
|
+
export interface DevtoolsCollector {
|
|
28
|
+
/** Pasang ke `createHandler`/`createPageRoutes` (gabung `mergeHooks`). */
|
|
29
|
+
readonly hooks: AppHooks;
|
|
30
|
+
/** Bungkus handler (paling luar) agar semua request tercatat. */
|
|
31
|
+
readonly middleware: Middleware;
|
|
32
|
+
setRoutes(routes: readonly DevtoolsRoute[]): void;
|
|
33
|
+
setAssets(assets: readonly DevtoolsAsset[]): void;
|
|
34
|
+
snapshot(): DevtoolsSnapshot;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Kolektor devtools. Catatan kejujuran: korelasi loader/render → request memakai
|
|
38
|
+
* "request terbuka terakhir dengan path sama" (event hook tidak membawa identitas request);
|
|
39
|
+
* cukup untuk dev berkonkurensi rendah, didokumentasikan sebagai aproksimasi.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createDevtoolsCollector(): DevtoolsCollector;
|
|
42
|
+
/** Halaman panel (HTML mandiri, tanpa build) — polling `/__ramonyx/data`. */
|
|
43
|
+
export declare function devtoolsPanelHtml(): string;
|
package/dist/devtools.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Panel devtools (ADR-0077): kolektor data dev-only — rute, timing request/loader/render,
|
|
2
|
+
// status payload hydration, ukuran bundel/aset. Ditenagai primitif yang sudah ada
|
|
3
|
+
// (`AppHooks` ADR-0065 + middleware ADR-0067). **Tidak pernah aktif di produksi** — hanya
|
|
4
|
+
// `createDevServer` yang membuatnya.
|
|
5
|
+
const MAX_REQUESTS = 50;
|
|
6
|
+
function round2(value) {
|
|
7
|
+
return Math.round(value * 100) / 100;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Kolektor devtools. Catatan kejujuran: korelasi loader/render → request memakai
|
|
11
|
+
* "request terbuka terakhir dengan path sama" (event hook tidak membawa identitas request);
|
|
12
|
+
* cukup untuk dev berkonkurensi rendah, didokumentasikan sebagai aproksimasi.
|
|
13
|
+
*/
|
|
14
|
+
export function createDevtoolsCollector() {
|
|
15
|
+
const requests = [];
|
|
16
|
+
let routes = [];
|
|
17
|
+
let assets = [];
|
|
18
|
+
const catat = (request) => {
|
|
19
|
+
requests.push(request);
|
|
20
|
+
if (requests.length > MAX_REQUESTS) {
|
|
21
|
+
requests.shift();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const terakhirDenganPath = (path) => {
|
|
25
|
+
for (let index = requests.length - 1; index >= 0; index -= 1) {
|
|
26
|
+
const record = requests[index];
|
|
27
|
+
if (record !== undefined && record.path === path && record.status === undefined) {
|
|
28
|
+
return record;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
const middleware = async (context, next) => {
|
|
34
|
+
const mulai = performance.now();
|
|
35
|
+
const record = {
|
|
36
|
+
method: context.request.method,
|
|
37
|
+
path: new URL(context.request.url).pathname,
|
|
38
|
+
};
|
|
39
|
+
catat(record);
|
|
40
|
+
const response = await next();
|
|
41
|
+
record.status = response.status;
|
|
42
|
+
record.ms = round2(performance.now() - mulai);
|
|
43
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
44
|
+
if (contentType.includes("text/html")) {
|
|
45
|
+
try {
|
|
46
|
+
const html = await response.clone().text();
|
|
47
|
+
record.hydration = html.includes('id="ramonyx-payload"') ? "payload" : "none";
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// body tidak terbaca (streaming diputus) — biarkan undefined
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return response;
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
middleware,
|
|
57
|
+
hooks: {
|
|
58
|
+
onLoaderEnd: (event) => {
|
|
59
|
+
const record = terakhirDenganPath(event.path);
|
|
60
|
+
if (record !== undefined) {
|
|
61
|
+
record.loaderMs = round2(event.durationMs);
|
|
62
|
+
record.cached = event.cached;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
onRenderEnd: (event) => {
|
|
66
|
+
const record = terakhirDenganPath(event.path);
|
|
67
|
+
if (record !== undefined) {
|
|
68
|
+
record.renderMs = round2(event.durationMs);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
setRoutes(next) {
|
|
73
|
+
routes = [...next];
|
|
74
|
+
},
|
|
75
|
+
setAssets(next) {
|
|
76
|
+
assets = [...next];
|
|
77
|
+
},
|
|
78
|
+
snapshot() {
|
|
79
|
+
return {
|
|
80
|
+
generatedAt: new Date().toISOString(),
|
|
81
|
+
routes,
|
|
82
|
+
assets,
|
|
83
|
+
requests: [...requests].reverse(),
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Halaman panel (HTML mandiri, tanpa build) — polling `/__ramonyx/data`. */
|
|
89
|
+
export function devtoolsPanelHtml() {
|
|
90
|
+
return `<!doctype html>
|
|
91
|
+
<html lang="id">
|
|
92
|
+
<head>
|
|
93
|
+
<meta charset="utf-8" />
|
|
94
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
95
|
+
<title>Ramonyx Devtools</title>
|
|
96
|
+
<style>
|
|
97
|
+
:root { --bg:#0f1115; --fg:#e6e8ee; --redup:#9aa2b1; --aksen:#7cc4ff; --garis:#262b36; }
|
|
98
|
+
* { box-sizing: border-box; }
|
|
99
|
+
body { margin:0; background:var(--bg); color:var(--fg); font:14px/1.5 ui-sans-serif, system-ui, sans-serif; }
|
|
100
|
+
.shell { max-width: 1100px; margin: 0 auto; padding: 20px; }
|
|
101
|
+
h1 { font-size: 20px; margin: 0 0 4px; } h2 { font-size: 14px; color: var(--redup); text-transform: uppercase; letter-spacing: .08em; margin: 24px 0 8px; }
|
|
102
|
+
table { border-collapse: collapse; width: 100%; font-size: 13px; }
|
|
103
|
+
th, td { border: 1px solid var(--garis); padding: 5px 8px; text-align: left; }
|
|
104
|
+
th { color: var(--redup); font-weight: 500; }
|
|
105
|
+
code { font-family: ui-monospace, monospace; color: var(--aksen); }
|
|
106
|
+
.ok { color: #7ddc9a; } .bad { color: #ff8080; } .dim { color: var(--redup); }
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="shell">
|
|
111
|
+
<h1>Ramonyx Devtools <span class="dim">(dev-only)</span></h1>
|
|
112
|
+
<p class="dim">Data dari <code>/__ramonyx/data</code> — rute, timing request/loader/render, hydration, ukuran bundel. Diperbarui tiap 2 dtk.</p>
|
|
113
|
+
<h2>Bundel & aset</h2>
|
|
114
|
+
<table id="aset"><thead><tr><th>Nama</th><th>Ukuran</th></tr></thead><tbody></tbody></table>
|
|
115
|
+
<h2>Rute</h2>
|
|
116
|
+
<table id="rute"><thead><tr><th>Path</th><th>Berkas</th></tr></thead><tbody></tbody></table>
|
|
117
|
+
<h2>Request terakhir</h2>
|
|
118
|
+
<table id="req"><thead><tr><th>Method</th><th>Path</th><th>Status</th><th>Total</th><th>Loader</th><th>Render</th><th>Cache</th><th>Hydration</th></tr></thead><tbody></tbody></table>
|
|
119
|
+
</div>
|
|
120
|
+
<script>
|
|
121
|
+
const fmt = (n) => (typeof n === "number" ? n + " ms" : "–");
|
|
122
|
+
const kb = (n) => (n / 1024).toFixed(1) + " KB";
|
|
123
|
+
async function segarkan() {
|
|
124
|
+
try {
|
|
125
|
+
const data = await (await fetch("/__ramonyx/data", { cache: "no-store" })).json();
|
|
126
|
+
document.querySelector("#aset tbody").innerHTML = data.assets
|
|
127
|
+
.map((a) => "<tr><td><code>" + a.name + "</code></td><td>" + kb(a.bytes) + "</td></tr>")
|
|
128
|
+
.join("");
|
|
129
|
+
document.querySelector("#rute tbody").innerHTML = data.routes
|
|
130
|
+
.map((r) => "<tr><td><code>" + r.path + "</code></td><td class='dim'>" + (r.file ?? "–") + "</td></tr>")
|
|
131
|
+
.join("");
|
|
132
|
+
document.querySelector("#req tbody").innerHTML = data.requests
|
|
133
|
+
.map((r) => "<tr><td>" + r.method + "</td><td><code>" + r.path + "</code></td><td class='" + ((r.status ?? 0) >= 400 ? "bad" : "ok") + "'>" + (r.status ?? "…") + "</td><td>" + fmt(r.ms) + "</td><td>" + fmt(r.loaderMs) + "</td><td>" + fmt(r.renderMs) + "</td><td>" + (r.cached === true ? "hit" : r.cached === false ? "miss" : "–") + "</td><td>" + (r.hydration === "payload" ? "payload ✓" : r.hydration === "none" ? "tidak" : "–") + "</td></tr>")
|
|
134
|
+
.join("");
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error("devtools: gagal memuat data", error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
segarkan();
|
|
140
|
+
setInterval(segarkan, 2000);
|
|
141
|
+
</script>
|
|
142
|
+
</body>
|
|
143
|
+
</html>
|
|
144
|
+
`;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=devtools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devtools.js","sourceRoot":"","sources":["../../../packages/bundler/src/devtools.ts"],"names":[],"mappings":"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","sourcesContent":["// Panel devtools (ADR-0077): kolektor data dev-only — rute, timing request/loader/render,\n// status payload hydration, ukuran bundel/aset. Ditenagai primitif yang sudah ada\n// (`AppHooks` ADR-0065 + middleware ADR-0067). **Tidak pernah aktif di produksi** — hanya\n// `createDevServer` yang membuatnya.\n\nimport type { AppHooks, Middleware } from \"@ramonyx/core\";\n\nexport interface DevtoolsRoute {\n readonly path: string;\n readonly file?: string;\n}\n\nexport interface DevtoolsAsset {\n readonly name: string;\n readonly bytes: number;\n}\n\nexport interface DevtoolsRequest {\n readonly method: string;\n readonly path: string;\n status?: number;\n ms?: number;\n loaderMs?: number;\n renderMs?: number;\n cached?: boolean;\n /** `payload` = HTML memuat payload hydration; `none` = tidak; undefined = bukan HTML. */\n hydration?: \"payload\" | \"none\";\n}\n\nexport interface DevtoolsSnapshot {\n readonly generatedAt: string;\n readonly routes: readonly DevtoolsRoute[];\n readonly assets: readonly DevtoolsAsset[];\n readonly requests: readonly DevtoolsRequest[];\n}\n\nexport interface DevtoolsCollector {\n /** Pasang ke `createHandler`/`createPageRoutes` (gabung `mergeHooks`). */\n readonly hooks: AppHooks;\n /** Bungkus handler (paling luar) agar semua request tercatat. */\n readonly middleware: Middleware;\n setRoutes(routes: readonly DevtoolsRoute[]): void;\n setAssets(assets: readonly DevtoolsAsset[]): void;\n snapshot(): DevtoolsSnapshot;\n}\n\nconst MAX_REQUESTS = 50;\n\nfunction round2(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n/**\n * Kolektor devtools. Catatan kejujuran: korelasi loader/render → request memakai\n * \"request terbuka terakhir dengan path sama\" (event hook tidak membawa identitas request);\n * cukup untuk dev berkonkurensi rendah, didokumentasikan sebagai aproksimasi.\n */\nexport function createDevtoolsCollector(): DevtoolsCollector {\n const requests: DevtoolsRequest[] = [];\n let routes: readonly DevtoolsRoute[] = [];\n let assets: readonly DevtoolsAsset[] = [];\n\n const catat = (request: DevtoolsRequest): void => {\n requests.push(request);\n if (requests.length > MAX_REQUESTS) {\n requests.shift();\n }\n };\n\n const terakhirDenganPath = (path: string): DevtoolsRequest | undefined => {\n for (let index = requests.length - 1; index >= 0; index -= 1) {\n const record = requests[index];\n if (record !== undefined && record.path === path && record.status === undefined) {\n return record;\n }\n }\n return undefined;\n };\n\n const middleware: Middleware = async (context, next) => {\n const mulai = performance.now();\n const record: DevtoolsRequest = {\n method: context.request.method,\n path: new URL(context.request.url).pathname,\n };\n catat(record);\n\n const response = await next();\n record.status = response.status;\n record.ms = round2(performance.now() - mulai);\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n try {\n const html = await response.clone().text();\n record.hydration = html.includes('id=\"ramonyx-payload\"') ? \"payload\" : \"none\";\n } catch {\n // body tidak terbaca (streaming diputus) — biarkan undefined\n }\n }\n return response;\n };\n\n return {\n middleware,\n hooks: {\n onLoaderEnd: (event) => {\n const record = terakhirDenganPath(event.path);\n if (record !== undefined) {\n record.loaderMs = round2(event.durationMs);\n record.cached = event.cached;\n }\n },\n onRenderEnd: (event) => {\n const record = terakhirDenganPath(event.path);\n if (record !== undefined) {\n record.renderMs = round2(event.durationMs);\n }\n },\n },\n setRoutes(next) {\n routes = [...next];\n },\n setAssets(next) {\n assets = [...next];\n },\n snapshot() {\n return {\n generatedAt: new Date().toISOString(),\n routes,\n assets,\n requests: [...requests].reverse(),\n };\n },\n };\n}\n\n/** Halaman panel (HTML mandiri, tanpa build) — polling `/__ramonyx/data`. */\nexport function devtoolsPanelHtml(): string {\n return `<!doctype html>\n<html lang=\"id\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>Ramonyx Devtools</title>\n<style>\n :root { --bg:#0f1115; --fg:#e6e8ee; --redup:#9aa2b1; --aksen:#7cc4ff; --garis:#262b36; }\n * { box-sizing: border-box; }\n body { margin:0; background:var(--bg); color:var(--fg); font:14px/1.5 ui-sans-serif, system-ui, sans-serif; }\n .shell { max-width: 1100px; margin: 0 auto; padding: 20px; }\n h1 { font-size: 20px; margin: 0 0 4px; } h2 { font-size: 14px; color: var(--redup); text-transform: uppercase; letter-spacing: .08em; margin: 24px 0 8px; }\n table { border-collapse: collapse; width: 100%; font-size: 13px; }\n th, td { border: 1px solid var(--garis); padding: 5px 8px; text-align: left; }\n th { color: var(--redup); font-weight: 500; }\n code { font-family: ui-monospace, monospace; color: var(--aksen); }\n .ok { color: #7ddc9a; } .bad { color: #ff8080; } .dim { color: var(--redup); }\n</style>\n</head>\n<body>\n<div class=\"shell\">\n <h1>Ramonyx Devtools <span class=\"dim\">(dev-only)</span></h1>\n <p class=\"dim\">Data dari <code>/__ramonyx/data</code> — rute, timing request/loader/render, hydration, ukuran bundel. Diperbarui tiap 2 dtk.</p>\n <h2>Bundel & aset</h2>\n <table id=\"aset\"><thead><tr><th>Nama</th><th>Ukuran</th></tr></thead><tbody></tbody></table>\n <h2>Rute</h2>\n <table id=\"rute\"><thead><tr><th>Path</th><th>Berkas</th></tr></thead><tbody></tbody></table>\n <h2>Request terakhir</h2>\n <table id=\"req\"><thead><tr><th>Method</th><th>Path</th><th>Status</th><th>Total</th><th>Loader</th><th>Render</th><th>Cache</th><th>Hydration</th></tr></thead><tbody></tbody></table>\n</div>\n<script>\nconst fmt = (n) => (typeof n === \"number\" ? n + \" ms\" : \"–\");\nconst kb = (n) => (n / 1024).toFixed(1) + \" KB\";\nasync function segarkan() {\n try {\n const data = await (await fetch(\"/__ramonyx/data\", { cache: \"no-store\" })).json();\n document.querySelector(\"#aset tbody\").innerHTML = data.assets\n .map((a) => \"<tr><td><code>\" + a.name + \"</code></td><td>\" + kb(a.bytes) + \"</td></tr>\")\n .join(\"\");\n document.querySelector(\"#rute tbody\").innerHTML = data.routes\n .map((r) => \"<tr><td><code>\" + r.path + \"</code></td><td class='dim'>\" + (r.file ?? \"–\") + \"</td></tr>\")\n .join(\"\");\n document.querySelector(\"#req tbody\").innerHTML = data.requests\n .map((r) => \"<tr><td>\" + r.method + \"</td><td><code>\" + r.path + \"</code></td><td class='\" + ((r.status ?? 0) >= 400 ? \"bad\" : \"ok\") + \"'>\" + (r.status ?? \"…\") + \"</td><td>\" + fmt(r.ms) + \"</td><td>\" + fmt(r.loaderMs) + \"</td><td>\" + fmt(r.renderMs) + \"</td><td>\" + (r.cached === true ? \"hit\" : r.cached === false ? \"miss\" : \"–\") + \"</td><td>\" + (r.hydration === \"payload\" ? \"payload ✓\" : r.hydration === \"none\" ? \"tidak\" : \"–\") + \"</td></tr>\")\n .join(\"\");\n } catch (error) {\n console.error(\"devtools: gagal memuat data\", error);\n }\n}\nsegarkan();\nsetInterval(segarkan, 2000);\n</script>\n</body>\n</html>\n`;\n}\n"]}
|
package/dist/edge.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type PluginOption } from "vite";
|
|
2
|
+
export interface BuildEdgeOptions {
|
|
3
|
+
readonly appDir: string;
|
|
4
|
+
/** Relatif terhadap appDir; default "dist/edge". */
|
|
5
|
+
readonly outDir?: string;
|
|
6
|
+
/** URL bundle klien (default: manifest `dist/client`, fallback `/assets/client.js`). */
|
|
7
|
+
readonly clientScript?: string;
|
|
8
|
+
/** Aktifkan SSR streaming di artefak; default true (renderer React mendukung). */
|
|
9
|
+
readonly streaming?: boolean;
|
|
10
|
+
readonly minify?: boolean;
|
|
11
|
+
/** Plugin Vite tambahan (harus edge-safe — ADR-0067). */
|
|
12
|
+
readonly plugins?: readonly PluginOption[];
|
|
13
|
+
}
|
|
14
|
+
export interface BuildEdgeResult {
|
|
15
|
+
readonly outDir: string;
|
|
16
|
+
readonly entryFile: string;
|
|
17
|
+
readonly outputFile: string;
|
|
18
|
+
readonly bytes: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Membangun artefak edge dari aplikasi Ramonyx.
|
|
22
|
+
*
|
|
23
|
+
* Manifest rute dibangun saat build (impor statis hasil codegen) sehingga artefak tidak
|
|
24
|
+
* menyentuh filesystem saat runtime; seluruh dependency dibundel (`ssr.noExternal`),
|
|
25
|
+
* `process.env.NODE_ENV` di-define sebagai `"production"`, dan hasilnya diperiksa:
|
|
26
|
+
* impor `node:*` yang lolos = error (runtime edge tidak menyediakannya).
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildEdge(options: BuildEdgeOptions): Promise<BuildEdgeResult>;
|
package/dist/edge.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Build target edge/serverless (ADR-0058): bundel SSR satu berkas dari entry yang digenerate
|
|
2
|
+
// (impor statis, tanpa `node:fs`) + guard agar tidak ada API Node yang lolos.
|
|
3
|
+
//
|
|
4
|
+
// Hasil: `<outDir>/index.js` — ESM dengan `export default { fetch(request) }`,
|
|
5
|
+
// kontrak Cloudflare Workers / Vercel Edge / Deno Deploy / runtime fetch standar.
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
8
|
+
import { join, resolve } from "node:path";
|
|
9
|
+
import { generateServerEntry, listApiRoutes, loadPageRoutes } from "@ramonyx/compiler";
|
|
10
|
+
import { errorHint } from "@ramonyx/core";
|
|
11
|
+
import { build } from "vite";
|
|
12
|
+
import { assetUrl } from "./assets.js";
|
|
13
|
+
import { readClientScript } from "./build.js";
|
|
14
|
+
import { readAssetManifest } from "./manifest.js";
|
|
15
|
+
const NODE_IMPORT = /["'](node:[a-z0-9_/-]+)["']/g;
|
|
16
|
+
/**
|
|
17
|
+
* Membangun artefak edge dari aplikasi Ramonyx.
|
|
18
|
+
*
|
|
19
|
+
* Manifest rute dibangun saat build (impor statis hasil codegen) sehingga artefak tidak
|
|
20
|
+
* menyentuh filesystem saat runtime; seluruh dependency dibundel (`ssr.noExternal`),
|
|
21
|
+
* `process.env.NODE_ENV` di-define sebagai `"production"`, dan hasilnya diperiksa:
|
|
22
|
+
* impor `node:*` yang lolos = error (runtime edge tidak menyediakannya).
|
|
23
|
+
*/
|
|
24
|
+
export async function buildEdge(options) {
|
|
25
|
+
// Path absolut: entry Vite diresolusi relatif terhadap `root`, path relatif akan tergandakan.
|
|
26
|
+
const appDir = resolve(options.appDir);
|
|
27
|
+
const routesDir = join(appDir, "src/routes");
|
|
28
|
+
const outDir = resolve(appDir, options.outDir ?? "dist/edge");
|
|
29
|
+
const entryDir = join(appDir, ".ramonyx");
|
|
30
|
+
const entryFile = join(entryDir, "edge-entry.ts");
|
|
31
|
+
const [pages, apiRoutes] = await Promise.all([
|
|
32
|
+
loadPageRoutes({ dir: routesDir }),
|
|
33
|
+
listApiRoutes({ dir: routesDir }),
|
|
34
|
+
]);
|
|
35
|
+
const middlewareCandidate = join(routesDir, "middleware.ts");
|
|
36
|
+
const middlewareFile = existsSync(middlewareCandidate) ? middlewareCandidate : undefined;
|
|
37
|
+
const clientDir = join(appDir, "dist/client");
|
|
38
|
+
const clientScript = options.clientScript ?? (await readClientScript(clientDir));
|
|
39
|
+
// Peta aset di-inline (artefak edge tanpa fs — ADR-0069).
|
|
40
|
+
const manifest = await readAssetManifest(clientDir);
|
|
41
|
+
const assets = {};
|
|
42
|
+
for (const path of Object.keys(manifest?.assets ?? {})) {
|
|
43
|
+
const url = assetUrl(manifest, path);
|
|
44
|
+
if (url !== undefined) {
|
|
45
|
+
assets[path] = url;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
await mkdir(entryDir, { recursive: true });
|
|
49
|
+
await writeFile(entryFile, generateServerEntry({
|
|
50
|
+
from: entryDir,
|
|
51
|
+
pages,
|
|
52
|
+
apiRoutes,
|
|
53
|
+
middlewareFile,
|
|
54
|
+
clientScript,
|
|
55
|
+
streaming: options.streaming ?? true,
|
|
56
|
+
assets,
|
|
57
|
+
}));
|
|
58
|
+
await build({
|
|
59
|
+
configFile: false,
|
|
60
|
+
root: appDir,
|
|
61
|
+
logLevel: "warn",
|
|
62
|
+
esbuild: { jsx: "automatic" },
|
|
63
|
+
plugins: [...(options.plugins ?? [])],
|
|
64
|
+
// `*.server.ts` tetap nyata di edge (server) — plugin stub hanya untuk bundle klien.
|
|
65
|
+
// Runtime edge tidak punya `process` — define agar React memakai build produksi.
|
|
66
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
67
|
+
ssr: { noExternal: true },
|
|
68
|
+
build: {
|
|
69
|
+
outDir,
|
|
70
|
+
emptyOutDir: true,
|
|
71
|
+
target: "es2022",
|
|
72
|
+
minify: options.minify ?? true,
|
|
73
|
+
ssr: entryFile,
|
|
74
|
+
rollupOptions: {
|
|
75
|
+
output: { entryFileNames: "index.js", format: "esm", codeSplitting: false },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
const outputFile = join(outDir, "index.js");
|
|
80
|
+
const bundle = await readFile(outputFile, "utf8");
|
|
81
|
+
const nodeImports = [
|
|
82
|
+
...new Set([...bundle.matchAll(NODE_IMPORT)].map((match) => match[1] ?? "")),
|
|
83
|
+
];
|
|
84
|
+
if (nodeImports.length > 0) {
|
|
85
|
+
throw new Error(`bundel edge memuat API Node (${nodeImports.join(", ")}) — periksa middleware/kode aplikasi ` +
|
|
86
|
+
`yang memakai \`node:*\` (mis. \`guardedFetch\` dari @ramonyx/security/ssrf). ${errorHint("RMX-EDGE-1")}`);
|
|
87
|
+
}
|
|
88
|
+
const info = await stat(outputFile);
|
|
89
|
+
return { outDir, entryFile, outputFile, bytes: info.size };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=edge.js.map
|
package/dist/edge.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge.js","sourceRoot":"","sources":["../../../packages/bundler/src/edge.ts"],"names":[],"mappings":"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","sourcesContent":["// Build target edge/serverless (ADR-0058): bundel SSR satu berkas dari entry yang digenerate\n// (impor statis, tanpa `node:fs`) + guard agar tidak ada API Node yang lolos.\n//\n// Hasil: `<outDir>/index.js` — ESM dengan `export default { fetch(request) }`,\n// kontrak Cloudflare Workers / Vercel Edge / Deno Deploy / runtime fetch standar.\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { generateServerEntry, listApiRoutes, loadPageRoutes } from \"@ramonyx/compiler\";\nimport { errorHint } from \"@ramonyx/core\";\nimport { build, type PluginOption } from \"vite\";\nimport { assetUrl } from \"./assets.ts\";\nimport { readClientScript } from \"./build.ts\";\nimport { readAssetManifest } from \"./manifest.ts\";\n\nexport interface BuildEdgeOptions {\n readonly appDir: string;\n /** Relatif terhadap appDir; default \"dist/edge\". */\n readonly outDir?: string;\n /** URL bundle klien (default: manifest `dist/client`, fallback `/assets/client.js`). */\n readonly clientScript?: string;\n /** Aktifkan SSR streaming di artefak; default true (renderer React mendukung). */\n readonly streaming?: boolean;\n readonly minify?: boolean;\n /** Plugin Vite tambahan (harus edge-safe — ADR-0067). */\n readonly plugins?: readonly PluginOption[];\n}\n\nexport interface BuildEdgeResult {\n readonly outDir: string;\n readonly entryFile: string;\n readonly outputFile: string;\n readonly bytes: number;\n}\n\nconst NODE_IMPORT = /[\"'](node:[a-z0-9_/-]+)[\"']/g;\n\n/**\n * Membangun artefak edge dari aplikasi Ramonyx.\n *\n * Manifest rute dibangun saat build (impor statis hasil codegen) sehingga artefak tidak\n * menyentuh filesystem saat runtime; seluruh dependency dibundel (`ssr.noExternal`),\n * `process.env.NODE_ENV` di-define sebagai `\"production\"`, dan hasilnya diperiksa:\n * impor `node:*` yang lolos = error (runtime edge tidak menyediakannya).\n */\nexport async function buildEdge(options: BuildEdgeOptions): Promise<BuildEdgeResult> {\n // Path absolut: entry Vite diresolusi relatif terhadap `root`, path relatif akan tergandakan.\n const appDir = resolve(options.appDir);\n const routesDir = join(appDir, \"src/routes\");\n const outDir = resolve(appDir, options.outDir ?? \"dist/edge\");\n const entryDir = join(appDir, \".ramonyx\");\n const entryFile = join(entryDir, \"edge-entry.ts\");\n\n const [pages, apiRoutes] = await Promise.all([\n loadPageRoutes({ dir: routesDir }),\n listApiRoutes({ dir: routesDir }),\n ]);\n\n const middlewareCandidate = join(routesDir, \"middleware.ts\");\n const middlewareFile = existsSync(middlewareCandidate) ? middlewareCandidate : undefined;\n const clientDir = join(appDir, \"dist/client\");\n const clientScript = options.clientScript ?? (await readClientScript(clientDir));\n\n // Peta aset di-inline (artefak edge tanpa fs — ADR-0069).\n const manifest = await readAssetManifest(clientDir);\n const assets: Record<string, string> = {};\n for (const path of Object.keys(manifest?.assets ?? {})) {\n const url = assetUrl(manifest, path);\n if (url !== undefined) {\n assets[path] = url;\n }\n }\n\n await mkdir(entryDir, { recursive: true });\n await writeFile(\n entryFile,\n generateServerEntry({\n from: entryDir,\n pages,\n apiRoutes,\n middlewareFile,\n clientScript,\n streaming: options.streaming ?? true,\n assets,\n }),\n );\n\n await build({\n configFile: false,\n root: appDir,\n logLevel: \"warn\",\n esbuild: { jsx: \"automatic\" },\n plugins: [...(options.plugins ?? [])],\n // `*.server.ts` tetap nyata di edge (server) — plugin stub hanya untuk bundle klien.\n // Runtime edge tidak punya `process` — define agar React memakai build produksi.\n define: { \"process.env.NODE_ENV\": JSON.stringify(\"production\") },\n ssr: { noExternal: true },\n build: {\n outDir,\n emptyOutDir: true,\n target: \"es2022\",\n minify: options.minify ?? true,\n ssr: entryFile,\n rollupOptions: {\n output: { entryFileNames: \"index.js\", format: \"esm\", codeSplitting: false },\n },\n },\n });\n\n const outputFile = join(outDir, \"index.js\");\n const bundle = await readFile(outputFile, \"utf8\");\n const nodeImports = [\n ...new Set([...bundle.matchAll(NODE_IMPORT)].map((match) => match[1] ?? \"\")),\n ];\n if (nodeImports.length > 0) {\n throw new Error(\n `bundel edge memuat API Node (${nodeImports.join(\", \")}) — periksa middleware/kode aplikasi ` +\n `yang memakai \\`node:*\\` (mis. \\`guardedFetch\\` dari @ramonyx/security/ssrf). ${errorHint(\"RMX-EDGE-1\")}`,\n );\n }\n\n const info = await stat(outputFile);\n return { outDir, entryFile, outputFile, bytes: info.size };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
export type { AssetUrlOptions, CollectAssetsResult, CreateAssetResolverOptions, } from "./assets.js";
|
|
2
|
+
export { assetsDirExists, assetUrl, collectAssets, createAssetResolver, DEFAULT_ASSETS_DIR, fontPreloadTag, } from "./assets.js";
|
|
1
3
|
export type { BuildClientOptions, BuildClientResult } from "./build.js";
|
|
2
|
-
export { buildClient } from "./build.js";
|
|
4
|
+
export { buildClient, readClientScript } from "./build.js";
|
|
3
5
|
export type { DevServer, DevServerOptions } from "./dev.js";
|
|
4
6
|
export { createDevServer } from "./dev.js";
|
|
7
|
+
export type { BuildEdgeOptions, BuildEdgeResult } from "./edge.js";
|
|
8
|
+
export { buildEdge } from "./edge.js";
|
|
9
|
+
export type { AssetEntry, AssetManifest, AssetMap } from "./manifest.js";
|
|
10
|
+
export { CLIENT_MANIFEST_FILE, readAssetManifest, writeAssetManifest } from "./manifest.js";
|
|
11
|
+
export type { LoadedPlugins, PluginContext, RamonyxPlugin } from "./plugin.js";
|
|
12
|
+
export { definePlugin, loadPlugins } from "./plugin.js";
|
|
13
|
+
export type { PrerenderOptions, PrerenderResult, PrerenderRouteInfo, } from "./prerender.js";
|
|
14
|
+
export { prerenderRoutes } from "./prerender.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { assetsDirExists, assetUrl, collectAssets, createAssetResolver, DEFAULT_ASSETS_DIR, fontPreloadTag, } from "./assets.js";
|
|
2
|
+
export { buildClient, readClientScript } from "./build.js";
|
|
2
3
|
export { createDevServer } from "./dev.js";
|
|
4
|
+
export { buildEdge } from "./edge.js";
|
|
5
|
+
export { CLIENT_MANIFEST_FILE, readAssetManifest, writeAssetManifest } from "./manifest.js";
|
|
6
|
+
export { definePlugin, loadPlugins } from "./plugin.js";
|
|
7
|
+
export { prerenderRoutes } from "./prerender.js";
|
|
3
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/bundler/src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../packages/bundler/src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE5F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAMxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export type {\n AssetUrlOptions,\n CollectAssetsResult,\n CreateAssetResolverOptions,\n} from \"./assets.ts\";\nexport {\n assetsDirExists,\n assetUrl,\n collectAssets,\n createAssetResolver,\n DEFAULT_ASSETS_DIR,\n fontPreloadTag,\n} from \"./assets.ts\";\nexport type { BuildClientOptions, BuildClientResult } from \"./build.ts\";\nexport { buildClient, readClientScript } from \"./build.ts\";\nexport type { DevServer, DevServerOptions } from \"./dev.ts\";\nexport { createDevServer } from \"./dev.ts\";\nexport type { BuildEdgeOptions, BuildEdgeResult } from \"./edge.ts\";\nexport { buildEdge } from \"./edge.ts\";\nexport type { AssetEntry, AssetManifest, AssetMap } from \"./manifest.ts\";\nexport { CLIENT_MANIFEST_FILE, readAssetManifest, writeAssetManifest } from \"./manifest.ts\";\nexport type { LoadedPlugins, PluginContext, RamonyxPlugin } from \"./plugin.ts\";\nexport { definePlugin, loadPlugins } from \"./plugin.ts\";\nexport type {\n PrerenderOptions,\n PrerenderResult,\n PrerenderRouteInfo,\n} from \"./prerender.ts\";\nexport { prerenderRoutes } from \"./prerender.ts\";\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Nama berkas manifest aset di direktori keluaran klien (ADR-0055). */
|
|
2
|
+
export declare const CLIENT_MANIFEST_FILE = "ramonyx.assets.json";
|
|
3
|
+
export interface AssetEntry {
|
|
4
|
+
/** Path relatif terhadap direktori keluaran klien, mis. `assets/img/logo-abc123.png`. */
|
|
5
|
+
readonly file: string;
|
|
6
|
+
readonly bytes: number;
|
|
7
|
+
}
|
|
8
|
+
export type AssetMap = Readonly<Record<string, AssetEntry>>;
|
|
9
|
+
/** Manifest aset hasil build (`dist/client/ramonyx.assets.json`). */
|
|
10
|
+
export interface AssetManifest {
|
|
11
|
+
/** Nama berkas bundle klien (relatif terhadap direktori keluaran), mis. `client-abc.js`. */
|
|
12
|
+
readonly client: string;
|
|
13
|
+
readonly files: readonly string[];
|
|
14
|
+
/** Aset dari `src/assets/**` (key = path relatif posix) — ADR-0069. */
|
|
15
|
+
readonly assets?: AssetMap;
|
|
16
|
+
}
|
|
17
|
+
/** Tulis manifest ke direktori keluaran klien. */
|
|
18
|
+
export declare function writeAssetManifest(clientOutDir: string, manifest: AssetManifest): Promise<void>;
|
|
19
|
+
/** Baca manifest aset; `null` bila belum pernah dibangun. */
|
|
20
|
+
export declare function readAssetManifest(clientDir: string): Promise<AssetManifest | null>;
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Manifest aset klien (`dist/client/ramonyx.assets.json`) — dipakai build, resolver aset
|
|
2
|
+
// (ADR-0069), dan pembaca runtime (`readClientScript`). Dipisah agar tanpa circular import.
|
|
3
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
/** Nama berkas manifest aset di direktori keluaran klien (ADR-0055). */
|
|
6
|
+
export const CLIENT_MANIFEST_FILE = "ramonyx.assets.json";
|
|
7
|
+
/** Tulis manifest ke direktori keluaran klien. */
|
|
8
|
+
export async function writeAssetManifest(clientOutDir, manifest) {
|
|
9
|
+
await writeFile(join(clientOutDir, CLIENT_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
10
|
+
}
|
|
11
|
+
/** Baca manifest aset; `null` bila belum pernah dibangun. */
|
|
12
|
+
export async function readAssetManifest(clientDir) {
|
|
13
|
+
try {
|
|
14
|
+
const raw = await readFile(join(clientDir, CLIENT_MANIFEST_FILE), "utf8");
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
if (typeof parsed.client !== "string" || parsed.client.length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
client: parsed.client,
|
|
21
|
+
files: Array.isArray(parsed.files) ? parsed.files : [],
|
|
22
|
+
...(parsed.assets !== undefined && parsed.assets !== null ? { assets: parsed.assets } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../packages/bundler/src/manifest.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,4FAA4F;AAE5F,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAmB1D,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,YAAoB,EACpB,QAAuB;IAEvB,MAAM,SAAS,CACb,IAAI,CAAC,YAAY,EAAE,oBAAoB,CAAC,EACxC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACzC,CAAC;AACJ,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2B,CAAC;QACzD,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YACtD,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5F,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC","sourcesContent":["// Manifest aset klien (`dist/client/ramonyx.assets.json`) — dipakai build, resolver aset\n// (ADR-0069), dan pembaca runtime (`readClientScript`). Dipisah agar tanpa circular import.\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/** Nama berkas manifest aset di direktori keluaran klien (ADR-0055). */\nexport const CLIENT_MANIFEST_FILE = \"ramonyx.assets.json\";\n\nexport interface AssetEntry {\n /** Path relatif terhadap direktori keluaran klien, mis. `assets/img/logo-abc123.png`. */\n readonly file: string;\n readonly bytes: number;\n}\n\nexport type AssetMap = Readonly<Record<string, AssetEntry>>;\n\n/** Manifest aset hasil build (`dist/client/ramonyx.assets.json`). */\nexport interface AssetManifest {\n /** Nama berkas bundle klien (relatif terhadap direktori keluaran), mis. `client-abc.js`. */\n readonly client: string;\n readonly files: readonly string[];\n /** Aset dari `src/assets/**` (key = path relatif posix) — ADR-0069. */\n readonly assets?: AssetMap;\n}\n\n/** Tulis manifest ke direktori keluaran klien. */\nexport async function writeAssetManifest(\n clientOutDir: string,\n manifest: AssetManifest,\n): Promise<void> {\n await writeFile(\n join(clientOutDir, CLIENT_MANIFEST_FILE),\n `${JSON.stringify(manifest, null, 2)}\\n`,\n );\n}\n\n/** Baca manifest aset; `null` bila belum pernah dibangun. */\nexport async function readAssetManifest(clientDir: string): Promise<AssetManifest | null> {\n try {\n const raw = await readFile(join(clientDir, CLIENT_MANIFEST_FILE), \"utf8\");\n const parsed = JSON.parse(raw) as Partial<AssetManifest>;\n if (typeof parsed.client !== \"string\" || parsed.client.length === 0) {\n return null;\n }\n return {\n client: parsed.client,\n files: Array.isArray(parsed.files) ? parsed.files : [],\n ...(parsed.assets !== undefined && parsed.assets !== null ? { assets: parsed.assets } : {}),\n };\n } catch {\n return null;\n }\n}\n"]}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type AppHooks, type Logger, type Middleware, type RamonyxConfig } from "@ramonyx/core";
|
|
2
|
+
import type { PluginOption } from "vite";
|
|
3
|
+
export interface PluginContext {
|
|
4
|
+
readonly appDir: string;
|
|
5
|
+
/** Config hasil `resolveConfig` (termasuk key pass-through untuk plugin). */
|
|
6
|
+
readonly config: RamonyxConfig;
|
|
7
|
+
readonly logger: Logger;
|
|
8
|
+
readonly mode: "dev" | "build" | "start";
|
|
9
|
+
}
|
|
10
|
+
export interface RamonyxPlugin {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
/** Plugin Vite (klien, dev, edge) — diteruskan apa adanya; tunduk guard `node:*` (ADR-0058/0063). */
|
|
13
|
+
vite?(context: PluginContext): PluginOption | readonly PluginOption[] | Promise<PluginOption | readonly PluginOption[]>;
|
|
14
|
+
/** Middleware global pre-routing (harus edge-safe bila artefak edge dipakai). */
|
|
15
|
+
middleware?(context: PluginContext): Middleware | readonly Middleware[] | Promise<Middleware | readonly Middleware[]>;
|
|
16
|
+
/** Hook aplikasi (timing/invalidasi) — digabung dengan hook lain (ADR-0065). */
|
|
17
|
+
hooks?(context: PluginContext): AppHooks | Promise<AppHooks>;
|
|
18
|
+
}
|
|
19
|
+
/** Identitas + tipe untuk plugin; mengembalikan nilai apa adanya. */
|
|
20
|
+
export declare function definePlugin(plugin: RamonyxPlugin): RamonyxPlugin;
|
|
21
|
+
export interface LoadedPlugins {
|
|
22
|
+
readonly vite: PluginOption[];
|
|
23
|
+
readonly middleware: Middleware[];
|
|
24
|
+
readonly hooks: AppHooks | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Resolusi plugin → daftar konkret (vite/middleware/hooks) untuk dipakai build/dev/start. */
|
|
27
|
+
export declare function loadPlugins(plugins: readonly RamonyxPlugin[] | undefined, context: PluginContext): Promise<LoadedPlugins>;
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Kontrak plugin (ADR-0065/0067) — passthrough Vite + middleware + hooks aplikasi.
|
|
2
|
+
//
|
|
3
|
+
// Kontrak ini **experimental** sampai ada ≥2 plugin nyata (kebijakan ADR-0065): stabil untuk
|
|
4
|
+
// dipakai, tetapi dapat bertambah (aditif) tanpa dijanjikan beku.
|
|
5
|
+
import { mergeHooks, } from "@ramonyx/core";
|
|
6
|
+
/** Identitas + tipe untuk plugin; mengembalikan nilai apa adanya. */
|
|
7
|
+
export function definePlugin(plugin) {
|
|
8
|
+
return plugin;
|
|
9
|
+
}
|
|
10
|
+
/** Resolusi plugin → daftar konkret (vite/middleware/hooks) untuk dipakai build/dev/start. */
|
|
11
|
+
export async function loadPlugins(plugins, context) {
|
|
12
|
+
const vite = [];
|
|
13
|
+
const middleware = [];
|
|
14
|
+
const hooks = [];
|
|
15
|
+
for (const plugin of plugins ?? []) {
|
|
16
|
+
const viteResult = await plugin.vite?.(context);
|
|
17
|
+
if (viteResult !== undefined) {
|
|
18
|
+
if (Array.isArray(viteResult)) {
|
|
19
|
+
vite.push(...viteResult);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
vite.push(viteResult);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const middlewareResult = await plugin.middleware?.(context);
|
|
26
|
+
if (middlewareResult !== undefined) {
|
|
27
|
+
if (Array.isArray(middlewareResult)) {
|
|
28
|
+
middleware.push(...middlewareResult);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
middleware.push(middlewareResult);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const hooksResult = await plugin.hooks?.(context);
|
|
35
|
+
if (hooksResult !== undefined) {
|
|
36
|
+
hooks.push(hooksResult);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { vite, middleware, hooks: mergeHooks(...hooks) };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../packages/bundler/src/plugin.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,6FAA6F;AAC7F,kEAAkE;AAElE,OAAO,EAIL,UAAU,GAEX,MAAM,eAAe,CAAC;AAyBvB,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,OAAO,MAAM,CAAC;AAChB,CAAC;AAQD,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA6C,EAC7C,OAAsB;IAEtB,MAAM,IAAI,GAAmB,EAAE,CAAC;IAChC,MAAM,UAAU,GAAiB,EAAE,CAAC;IACpC,MAAM,KAAK,GAAe,EAAE,CAAC;IAE7B,KAAK,MAAM,MAAM,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;QACnC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,GAAI,UAA6B,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,UAA0B,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,MAAM,gBAAgB,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC;QAC5D,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACpC,UAAU,CAAC,IAAI,CAAC,GAAI,gBAAiC,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,IAAI,CAAC,gBAA8B,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC;AAC3D,CAAC","sourcesContent":["// Kontrak plugin (ADR-0065/0067) — passthrough Vite + middleware + hooks aplikasi.\n//\n// Kontrak ini **experimental** sampai ada ≥2 plugin nyata (kebijakan ADR-0065): stabil untuk\n// dipakai, tetapi dapat bertambah (aditif) tanpa dijanjikan beku.\n\nimport {\n type AppHooks,\n type Logger,\n type Middleware,\n mergeHooks,\n type RamonyxConfig,\n} from \"@ramonyx/core\";\nimport type { PluginOption } from \"vite\";\n\nexport interface PluginContext {\n readonly appDir: string;\n /** Config hasil `resolveConfig` (termasuk key pass-through untuk plugin). */\n readonly config: RamonyxConfig;\n readonly logger: Logger;\n readonly mode: \"dev\" | \"build\" | \"start\";\n}\n\nexport interface RamonyxPlugin {\n readonly name: string;\n /** Plugin Vite (klien, dev, edge) — diteruskan apa adanya; tunduk guard `node:*` (ADR-0058/0063). */\n vite?(\n context: PluginContext,\n ): PluginOption | readonly PluginOption[] | Promise<PluginOption | readonly PluginOption[]>;\n /** Middleware global pre-routing (harus edge-safe bila artefak edge dipakai). */\n middleware?(\n context: PluginContext,\n ): Middleware | readonly Middleware[] | Promise<Middleware | readonly Middleware[]>;\n /** Hook aplikasi (timing/invalidasi) — digabung dengan hook lain (ADR-0065). */\n hooks?(context: PluginContext): AppHooks | Promise<AppHooks>;\n}\n\n/** Identitas + tipe untuk plugin; mengembalikan nilai apa adanya. */\nexport function definePlugin(plugin: RamonyxPlugin): RamonyxPlugin {\n return plugin;\n}\n\nexport interface LoadedPlugins {\n readonly vite: PluginOption[];\n readonly middleware: Middleware[];\n readonly hooks: AppHooks | undefined;\n}\n\n/** Resolusi plugin → daftar konkret (vite/middleware/hooks) untuk dipakai build/dev/start. */\nexport async function loadPlugins(\n plugins: readonly RamonyxPlugin[] | undefined,\n context: PluginContext,\n): Promise<LoadedPlugins> {\n const vite: PluginOption[] = [];\n const middleware: Middleware[] = [];\n const hooks: AppHooks[] = [];\n\n for (const plugin of plugins ?? []) {\n const viteResult = await plugin.vite?.(context);\n if (viteResult !== undefined) {\n if (Array.isArray(viteResult)) {\n vite.push(...(viteResult as PluginOption[]));\n } else {\n vite.push(viteResult as PluginOption);\n }\n }\n\n const middlewareResult = await plugin.middleware?.(context);\n if (middlewareResult !== undefined) {\n if (Array.isArray(middlewareResult)) {\n middleware.push(...(middlewareResult as Middleware[]));\n } else {\n middleware.push(middlewareResult as Middleware);\n }\n }\n\n const hooksResult = await plugin.hooks?.(context);\n if (hooksResult !== undefined) {\n hooks.push(hooksResult);\n }\n }\n\n return { vite, middleware, hooks: mergeHooks(...hooks) };\n}\n"]}
|