@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.
Files changed (43) hide show
  1. package/dist/{index-v5sbd3az.js → index-0agjty3z.js} +21 -18
  2. package/dist/index-0agjty3z.js.map +15 -0
  3. package/dist/index-f8w073cm.js +30 -0
  4. package/dist/index-f8w073cm.js.map +10 -0
  5. package/dist/{index-snbxks72.js → index-tbph0859.js} +80 -80
  6. package/dist/{index-snbxks72.js.map → index-tbph0859.js.map} +4 -4
  7. package/dist/index.js +33 -33
  8. package/dist/index.js.map +4 -4
  9. package/dist/server/handler.d.ts.map +1 -1
  10. package/dist/server/index.js +104 -93
  11. package/dist/server/index.js.map +10 -10
  12. package/dist/server/test-server.d.ts +6 -0
  13. package/dist/server/test-server.d.ts.map +1 -1
  14. package/dist/testing-preload.d.ts +2 -0
  15. package/dist/testing-preload.d.ts.map +1 -0
  16. package/dist/testing-preload.js +10 -0
  17. package/dist/testing-preload.js.map +10 -0
  18. package/dist/testing.d.ts +11 -0
  19. package/dist/testing.d.ts.map +1 -0
  20. package/dist/testing.js +13 -0
  21. package/dist/testing.js.map +9 -0
  22. package/dist/transform.js +1 -1
  23. package/package.json +15 -5
  24. package/src/api.ts +14 -14
  25. package/src/devtools.ts +5 -5
  26. package/src/manifest.ts +2 -2
  27. package/src/plugin.ts +21 -21
  28. package/src/server/dev.ts +6 -1
  29. package/src/server/handler.ts +69 -47
  30. package/src/server/isr.ts +5 -5
  31. package/src/server/node-server.ts +6 -6
  32. package/src/server/node.ts +2 -2
  33. package/src/server/plugins.ts +1 -1
  34. package/src/server/prerender.ts +29 -29
  35. package/src/server/shell.ts +8 -8
  36. package/src/server/shutdown.ts +5 -5
  37. package/src/server/storage.ts +1 -1
  38. package/src/server/test-server.ts +12 -1
  39. package/src/server-only.ts +7 -7
  40. package/src/testing-preload.ts +5 -0
  41. package/src/testing.ts +34 -0
  42. package/src/transform.ts +76 -76
  43. package/dist/index-v5sbd3az.js.map +0 -15
@@ -202,19 +202,19 @@ export function serverOnlyImportError(input: {
202
202
  }): MoonsError {
203
203
  const sourceLabel =
204
204
  input.source === "builtin"
205
- ? "Sumber kecocokan: daftar bawaan paket server-only framework."
205
+ ? "Match source: framework built-in server-only package list."
206
206
  : input.source === "config"
207
- ? "Sumber kecocokan: `security.serverOnlyPackages` di moons.config.ts."
208
- : `Sumber kecocokan: marker \`"moons": { "serverOnly": true }\` di ${input.markerPath ?? "package.json"}.`;
207
+ ? "Match source: `security.serverOnlyPackages` in moons.config.ts."
208
+ : `Match source: marker \`"moons": { "serverOnly": true }\` in ${input.markerPath ?? "package.json"}.`;
209
209
  return new MoonsError({
210
210
  code: "E_FORBIDDEN_SERVER_IMPORT",
211
211
  file: input.relativeFile,
212
212
  line: input.line,
213
- message: `mengimpor${input.dynamic === true ? " (dynamic)" : ""} \`${input.specifier}\` — paket server-only \`${input.packageName}\``,
214
- details: `${sourceLabel}\nPaket server-only tidak boleh masuk bundle client.`,
213
+ message: `importing${input.dynamic === true ? " (dynamic)" : ""} \`${input.specifier}\` — server-only package \`${input.packageName}\``,
214
+ details: `${sourceLabel}\nServer-only packages must not enter the client bundle.`,
215
215
  suggestions: [
216
- "Pindahkan operasi tersebut ke `*.server.ts` dan panggil lewat serverFn",
217
- "Atau ganti/hapus import tersebut di modul client",
216
+ "Move the operation into `*.server.ts` and call it via a serverFn",
217
+ "Or replace/remove the import in the client module",
218
218
  ],
219
219
  });
220
220
  }
@@ -0,0 +1,5 @@
1
+ import { registerMoonsTestPlugin } from "./testing";
2
+
3
+ // Marker so fixture tests can skip cleanly under a plain `bun test` run.
4
+ (globalThis as { __moonsTestPreload?: boolean }).__moonsTestPreload = true;
5
+ registerMoonsTestPlugin();
package/src/testing.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { readFileSync } from "node:fs";
2
+ import type { BunPlugin } from "bun";
3
+ import { analyzeServerFile, injectServerFnMeta } from "./transform";
4
+
5
+ /**
6
+ * Annotate a `*.server.ts` module with the transform-generated serverFn meta
7
+ * (`__hash`, `__file`, `__line`, `__exportName`) — the same injection the
8
+ * build performs. Used by `moons test` so tests can import server modules.
9
+ */
10
+ export function transformServerModuleForTest(
11
+ file: string,
12
+ projectRoot = process.cwd(),
13
+ ): string {
14
+ const source = readFileSync(file, "utf8");
15
+ const analysis = analyzeServerFile(source, file, projectRoot);
16
+ return injectServerFnMeta(source, analysis, projectRoot);
17
+ }
18
+
19
+ /** Bun runtime plugin that applies the serverFn meta before tests load code. */
20
+ export function moonsTestPlugin(projectRoot = process.cwd()): BunPlugin {
21
+ return {
22
+ name: "moons-test-server-meta",
23
+ setup(build) {
24
+ build.onLoad({ filter: /\.server\.(ts|tsx)$/ }, (args) => ({
25
+ contents: transformServerModuleForTest(args.path, projectRoot),
26
+ loader: args.path.endsWith(".tsx") ? "tsx" : "ts",
27
+ }));
28
+ },
29
+ };
30
+ }
31
+
32
+ export function registerMoonsTestPlugin(projectRoot = process.cwd()): void {
33
+ Bun.plugin(moonsTestPlugin(projectRoot));
34
+ }
package/src/transform.ts CHANGED
@@ -552,17 +552,17 @@ export function renderServerFnStub(
552
552
  file: filename,
553
553
  line: fn.line,
554
554
  annotation: fn.name,
555
- message: `schema ${kind} serverFn \`${fn.name}\` merujuk nilai server \`${reference}\` dari \`${serverImport.specifier}\``,
555
+ message: `schema ${kind} of serverFn \`${fn.name}\` references server value \`${reference}\` from \`${serverImport.specifier}\``,
556
556
  details:
557
- `\`${reference}\` diimpor dari file server lain dan bukan serverFn — stub client tidak mengekspornya (dulu gagal dengan error mentah bundler \`MISSING_EXPORT\`).\n\n` +
558
- "Pilih salah satu:\n" +
559
- " // a) pindahkan konstanta/schema ke modul client-safe\n" +
557
+ `\`${reference}\` is imported from another server file and is not a serverFn — the client stub does not export it (previously a raw bundler \`MISSING_EXPORT\` error).\n\n` +
558
+ "Pick one:\n" +
559
+ " // a) move the constant/schema to a client-safe module\n" +
560
560
  ` import { ${reference} } from "../shared/schemas";\n` +
561
- " // b) inline nilai yang memang publik di schema, atau\n" +
562
- " // c) validasi tambahan di handler (server) tanpa mereferensikan nilai server di schema",
561
+ " // b) inline the value if it is genuinely public in the schema, or\n" +
562
+ " // c) do extra validation in the server handler without referencing server values in the schema",
563
563
  suggestions: [
564
- "Pindahkan deklarasi yang dirujuk ke modul bersama yang client-safe (mis. `src/shared/schemas.ts`)",
565
- "Atau lakukan validasi di handler server, bukan di ekspresi schema",
564
+ "Move the referenced declaration to a client-safe shared module (e.g. `src/shared/schemas.ts`)",
565
+ "Or do the validation in the server handler instead of the schema expression",
566
566
  ],
567
567
  });
568
568
  }
@@ -576,21 +576,21 @@ export function renderServerFnStub(
576
576
  file: filename,
577
577
  line: fn.line,
578
578
  annotation: fn.name,
579
- message: `schema ${kind} serverFn \`${fn.name}\` merujuk deklarasi lokal \`${reference}\``,
579
+ message: `schema ${kind} of serverFn \`${fn.name}\` references local declaration \`${reference}\``,
580
580
  details:
581
- `\`${reference}\` dibuang dari stub client, sehingga nilainya \`undefined\` di browser (crash hydration).\n\n` +
582
- "Sebelum (ditolak):\n" +
583
- ` const ${reference} = z.object({ … }); // deklarasi lokal di file yang sama\n` +
581
+ `\`${reference}\` is dropped from the client stub, so its value is \`undefined\` in the browser (hydration crash).\n\n` +
582
+ "Before (rejected):\n" +
583
+ ` const ${reference} = z.object({ … }); // local declaration in the same file\n` +
584
584
  ` export const ${fn.name} = serverFn({ ${kind}: ${reference}, … });\n\n` +
585
- "Sesudah (pilih salah satu):\n" +
586
- ` // a) inline schema di argumen\n` +
585
+ "After (pick one):\n" +
586
+ ` // a) inline the schema in the argument\n` +
587
587
  ` export const ${fn.name} = serverFn({ ${kind}: z.object({ … }), … });\n` +
588
- ` // b) pindahkan deklarasi ke modul bersama yang boleh masuk client (mis. src/shared/schemas.ts)\n` +
588
+ ` // b) move the declaration to a shared module that may enter the client (e.g. src/shared/schemas.ts)\n` +
589
589
  ` import { ${reference} } from "../shared/schemas";`,
590
590
  suggestions: [
591
- `Inline schema di argumen \`serverFn({ ${kind}: … })\`, atau`,
592
- `Pindahkan \`${reference}\` ke modul bersama (mis. \`src/shared/schemas.ts\`) lalu impor dari sana`,
593
- "Jangan memindahkan nilai rahasia ke shared — schema harus client-safe (zod/Standard Schema)",
591
+ `Inline the schema in the argument \`serverFn({ ${kind}: … })\`, or`,
592
+ `Move \`${reference}\` to a shared module (e.g. \`src/shared/schemas.ts\`) and import it from there`,
593
+ "Never move secret values to shared — the schema must be client-safe (zod/Standard Schema)",
594
594
  ],
595
595
  });
596
596
  }
@@ -607,9 +607,9 @@ export function renderServerFnStub(
607
607
  throw new MoonsError({
608
608
  code: "E_SERVER_IMPORT_IN_CLIENT",
609
609
  file: filename,
610
- message: `tidak bisa me-resolve \`${reExport.source}\` untuk re-export`,
611
- details: "Re-export dari `*.server.ts` harus bisa di-resolve statis.",
612
- suggestions: ["Perbaiki path re-export", "Hindari re-export dinamis dari file server"],
610
+ message: `cannot resolve \`${reExport.source}\` for re-export`,
611
+ details: "Re-exports from `*.server.ts` must be statically resolvable.",
612
+ suggestions: ["Fix the re-export path", "Avoid dynamic re-exports from server files"],
613
613
  });
614
614
  }
615
615
  const targetNames = serverFnExportNames(target, (specifier) =>
@@ -630,9 +630,9 @@ export function renderServerFnStub(
630
630
  throw new MoonsError({
631
631
  code: "E_SERVER_IMPORT_IN_CLIENT",
632
632
  file: filename,
633
- message: `\`export *\` dari \`${specifier}\` tidak bisa di-resolve`,
634
- details: "`export *` dari `*.server.ts` wajib bisa di-expand statis.",
635
- suggestions: ["Perbaiki path re-export", "Ganti menjadi named re-export"],
633
+ message: `\`export *\` from \`${specifier}\` cannot be resolved`,
634
+ details: "`export *` from `*.server.ts` must be statically expandable.",
635
+ suggestions: ["Fix the re-export path", "Replace it with named re-exports"],
636
636
  });
637
637
  }
638
638
  const targetNames = serverFnExportNames(target, (nested) =>
@@ -646,7 +646,7 @@ export function renderServerFnStub(
646
646
  }
647
647
 
648
648
  if (importLines.length === 0 && exportLines.length === 0) {
649
- return { code: "// @moons: tidak ada serverFn yang di-export\nexport {};\n", referenced };
649
+ return { code: "// @moons: no serverFn exported\nexport {};\n", referenced };
650
650
  }
651
651
 
652
652
  return { code: `${[...importLines, "", ...exportLines].join("\n")}\n`, referenced };
@@ -747,12 +747,12 @@ export function nonContractServerFileError(file: string, projectRoot: string): M
747
747
  return new MoonsError({
748
748
  code: "E_SERVER_IMPORT_IN_CLIENT",
749
749
  file: toRelative(projectRoot, file),
750
- message: "file server memakai ekstensi di luar kontrak `*.server.ts`",
750
+ message: "server file uses an extension outside the `*.server.ts` contract",
751
751
  details:
752
- "Transform zero-trust hanya menangani `*.server.ts`/`*.server.tsx`; file server dengan ekstensi lain tidak bisa di-stub dan tidak boleh masuk graph client.",
752
+ "The zero-trust transform only handles `*.server.ts`/`*.server.tsx`; server files with other extensions cannot be stubbed and must not enter the client graph.",
753
753
  suggestions: [
754
- "Ganti nama file menjadi `*.server.ts`/`*.server.tsx` dan taruh `serverFn` di dalamnya",
755
- "Atau pindahkan nilai yang dibutuhkan ke file non-server",
754
+ "Rename the file to `*.server.ts`/`*.server.tsx` and put the `serverFn` inside it",
755
+ "Or move the value you need into a non-server file",
756
756
  ],
757
757
  });
758
758
  }
@@ -942,12 +942,12 @@ export async function checkClientModuleImports(
942
942
  code: "E_FORBIDDEN_SERVER_IMPORT",
943
943
  file: relativeFile,
944
944
  line,
945
- message: `mengimpor \`${specifier}\` — \`moons.config.ts\` adalah modul server-only`,
945
+ message: `importing \`${specifier}\` — \`moons.config.ts\` is a server-only module`,
946
946
  details:
947
- "Config memuat `context`/`middleware` (kode server) dan tidak pernah masuk bundle client (Addendum J.4).",
947
+ "The config contains `context`/`middleware` (server code) and never enters the client bundle (Addendum J.4).",
948
948
  suggestions: [
949
- "Pindahkan nilai yang dibutuhkan ke modul client-safe (mis. `src/shared/…`)",
950
- "Ambil nilai dari server lewat loader/serverFn",
949
+ "Move the value you need into a client-safe module (e.g. `src/shared/…`)",
950
+ "Get the value from the server via a loader/serverFn",
951
951
  ],
952
952
  });
953
953
  };
@@ -957,12 +957,12 @@ export async function checkClientModuleImports(
957
957
  code: "E_FORBIDDEN_SERVER_IMPORT",
958
958
  file: relativeFile,
959
959
  line,
960
- message: `mengimpor \`${specifier}\` — \`${toRelative(projectRoot, resolvedTarget)}\` ada di \`src/server/**\` (server-only)`,
960
+ message: `importing \`${specifier}\` — \`${toRelative(projectRoot, resolvedTarget)}\` is inside \`src/server/**\` (server-only)`,
961
961
  details:
962
- "Direktori `src/server/**` hanya untuk kode server (Addendum J.4); suffix `.server.ts` bukan satu-satunya jaminan.",
962
+ "The `src/server/**` directory is for server code only (Addendum J.4); the `.server.ts` suffix is not the only guarantee.",
963
963
  suggestions: [
964
- "Pindahkan kode yang client-safe ke `src/shared/`",
965
- "Akses nilainya dari server lewat loader/serverFn",
964
+ "Move client-safe code to `src/shared/`",
965
+ "Access the value from the server via a loader/serverFn",
966
966
  ],
967
967
  });
968
968
  };
@@ -973,12 +973,12 @@ export async function checkClientModuleImports(
973
973
  code: "E_FORBIDDEN_SERVER_IMPORT",
974
974
  file: relativeFile,
975
975
  line,
976
- message: `mengimpor \`${specifier}\` — \`${relApi}\` adalah modul API server-only`,
976
+ message: `importing \`${specifier}\` — \`${relApi}\` is a server-only API module`,
977
977
  details:
978
- "`src/api/**` hanya berjalan di server (endpoint HTTP) dan tidak pernah masuk bundle client.",
978
+ "`src/api/**` only runs on the server (HTTP endpoints) and never enters the client bundle.",
979
979
  suggestions: [
980
- "Pindahkan operasi tersebut ke `*.server.ts` dan panggil lewat serverFn",
981
- "Jangan mengimpor file `src/api` dari route/komponen client",
980
+ "Move the operation into `*.server.ts` and call it via a serverFn",
981
+ "Do not import `src/api` files from client routes/components",
982
982
  ],
983
983
  });
984
984
  };
@@ -1034,8 +1034,8 @@ export async function checkClientModuleImports(
1034
1034
  message,
1035
1035
  details,
1036
1036
  suggestions: [
1037
- "Buat server function yang mengembalikan data yang dibutuhkan, atau",
1038
- "Jika nilainya memang publik, definisikan ulang konstanta itu di modul yang boleh masuk client (jangan memindahkan nilai rahasia)",
1037
+ "Create a server function that returns the data you need, or",
1038
+ "If the value is genuinely public, redefine the constant in a client-safe module (never move secret values)",
1039
1039
  ],
1040
1040
  });
1041
1041
  };
@@ -1045,11 +1045,11 @@ export async function checkClientModuleImports(
1045
1045
  code: "E_FORBIDDEN_SERVER_IMPORT",
1046
1046
  file: relativeFile,
1047
1047
  line,
1048
- message: `mengimpor \`${specifier}\` di modul client`,
1049
- details: "Modul server-only hanya boleh di-import dari *.server.ts.",
1048
+ message: `importing \`${specifier}\` in a client module`,
1049
+ details: "Server-only modules may only be imported from *.server.ts.",
1050
1050
  suggestions: [
1051
- "Pindahkan operasi tersebut ke serverFn, atau",
1052
- "Hapus import tersebut",
1051
+ "Move the operation into a serverFn, or",
1052
+ "Remove the import",
1053
1053
  ],
1054
1054
  });
1055
1055
  };
@@ -1177,13 +1177,13 @@ export async function checkClientModuleImports(
1177
1177
  code: "E_SERVER_IMPORT_IN_CLIENT",
1178
1178
  file: relativeFile,
1179
1179
  line,
1180
- message: `mengimpor \`${name}\` — berasal dari \`${toRelative(projectRoot, serverFile)}\` (via rantai re-export)`,
1180
+ message: `importing \`${name}\` — comes from \`${toRelative(projectRoot, serverFile)}\` (via a re-export chain)`,
1181
1181
  details:
1182
- `\`${toRelative(projectRoot, resolvedTarget)}\` me-re-export nilai dari file server; ` +
1183
- "stub client tidak mengekspornya (dulu gagal dengan error mentah bundler `MISSING_EXPORT`).",
1182
+ `\`${toRelative(projectRoot, resolvedTarget)}\` re-exports a value from a server file; ` +
1183
+ "the client stub does not export it (previously a raw bundler `MISSING_EXPORT` error).",
1184
1184
  suggestions: [
1185
- "Buat server function yang mengembalikan data yang dibutuhkan, atau",
1186
- "Definisikan ulang konstanta publik itu di modul client-safe (jangan pindahkan nilai rahasia)",
1185
+ "Create a server function that returns the data you need, or",
1186
+ "Redefine the public constant in a client-safe module (never move secret values)",
1187
1187
  ],
1188
1188
  });
1189
1189
  }
@@ -1197,7 +1197,7 @@ export async function checkClientModuleImports(
1197
1197
 
1198
1198
  if (statement.type === "ExportAllDeclaration") {
1199
1199
  if (resolvedTarget === null) {
1200
- reject(line, `\`export *\` dari \`${targetRelative}\` tidak bisa di-resolve`, "Re-export dari `*.server.ts` wajib bisa di-resolve statis.");
1200
+ reject(line, `\`export *\` from \`${targetRelative}\` cannot be resolved`, "Re-exports from `*.server.ts` must be statically resolvable.");
1201
1201
  }
1202
1202
  continue; // aman: target menjadi stub
1203
1203
  }
@@ -1205,10 +1205,10 @@ export async function checkClientModuleImports(
1205
1205
  const specifiers = (statement["specifiers"] ?? []) as AstNode[];
1206
1206
  for (const item of specifiers) {
1207
1207
  if (item.type === "ImportDefaultSpecifier") {
1208
- reject(line, `mengimpor default dari ${targetRelative}`, "Default export dari file server tidak boleh menyeberang ke client.");
1208
+ reject(line, `importing the default export from ${targetRelative}`, "Default exports from a server file must not cross to the client.");
1209
1209
  }
1210
1210
  if (item.type === "ImportNamespaceSpecifier") {
1211
- reject(line, `mengimpor namespace (\`* as\`) dari ${targetRelative}`, "Import namespace dari file server tidak boleh menyeberang ke client.");
1211
+ reject(line, `importing the namespace (\`* as\`) from ${targetRelative}`, "Namespace imports from a server file must not cross to the client.");
1212
1212
  }
1213
1213
  const name = ((item["local"] as AstNode | undefined)?.["name"] as string) ?? "";
1214
1214
  // Type-only (Addendum J.5): Babel menaruh `importKind: "type"` di
@@ -1222,8 +1222,8 @@ export async function checkClientModuleImports(
1222
1222
  if (name.length > 0 && !(await isAllowedServerFnImport(resolvedTarget, specifier, name))) {
1223
1223
  reject(
1224
1224
  line,
1225
- `mengimpor \`${name}\` dari ${targetRelative}`,
1226
- "Kode server tidak boleh muncul di client.\nHanya `serverFn` yang diizinkan menyeberang.",
1225
+ `importing \`${name}\` from ${targetRelative}`,
1226
+ "Server code must not appear in the client.\nOnly `serverFn` may cross.",
1227
1227
  );
1228
1228
  }
1229
1229
  }
@@ -1270,11 +1270,11 @@ export async function checkClientModuleImports(
1270
1270
  code: "E_ENV_IN_CLIENT",
1271
1271
  file: relativeFile,
1272
1272
  line: node.loc?.start.line ?? 1,
1273
- message: `memanggil \`${callText}\` di modul yang masuk client`,
1274
- details: "`env()` hanya legal di server.",
1273
+ message: `calling \`${callText}\` in a client module`,
1274
+ details: "`env()` is only legal on the server.",
1275
1275
  suggestions: [
1276
- "Pindahkan pemanggilan ke dalam serverFn, atau",
1277
- "Gunakan import.meta.env untuk nilai publik",
1276
+ "Move the call into a serverFn, or",
1277
+ "Use import.meta.env for public values",
1278
1278
  ],
1279
1279
  });
1280
1280
  });
@@ -1338,7 +1338,7 @@ export async function checkClientModuleImports(
1338
1338
 
1339
1339
  const targetRelative =
1340
1340
  resolvedTarget === null ? request.text : toRelative(projectRoot, resolvedTarget);
1341
- reject(request.node.loc?.start.line ?? 1, `mengimpor (dynamic) \`${request.text}\` dari ${targetRelative}`, "Client tidak boleh melakukan dynamic import ke `*.server.ts`.");
1341
+ reject(request.node.loc?.start.line ?? 1, `importing (dynamic) \`${request.text}\` from ${targetRelative}`, "The client must not dynamically import `*.server.ts`.");
1342
1342
  }
1343
1343
 
1344
1344
  // `import.meta.glob` yang mencakup `*.server.ts` (§12.7) — audit adversarial M6.
@@ -1368,11 +1368,11 @@ export async function checkClientModuleImports(
1368
1368
  code: "E_SERVER_IMPORT_IN_CLIENT",
1369
1369
  file: relativeFile,
1370
1370
  line: node.loc?.start.line ?? 1,
1371
- message: `mengimpor (glob) \`${pattern}\` di modul client`,
1372
- details: "`import.meta.glob` yang mencakup `*.server.ts` dilarang di client.",
1371
+ message: `importing (glob) \`${pattern}\` in a client module`,
1372
+ details: "`import.meta.glob` patterns covering `*.server.ts` are forbidden in the client.",
1373
1373
  suggestions: [
1374
- "Import statis `serverFn` dari `*.server.ts` (hanya itu yang boleh menyeberang), atau",
1375
- "Pindahkan kebutuhan data ke dalam server function",
1374
+ "Statically import the `serverFn` from `*.server.ts` (that is all that may cross), or",
1375
+ "Move the data requirement into a server function",
1376
1376
  ],
1377
1377
  });
1378
1378
  }
@@ -1506,7 +1506,7 @@ export function checkRouteModuleExports(context: RouteExportCheckContext): void
1506
1506
  : base === "_error.tsx" || base === "_404.tsx"
1507
1507
  ? ["default"]
1508
1508
  : ["default", "loader", "meta", "prerender", "paths", "revalidate"];
1509
- const allowedText = `Hanya ${allowed.map((name) => `\`${name}\``).join(", ")} yang boleh di-export.`;
1509
+ const allowedText = `Only ${allowed.map((name) => `\`${name}\``).join(", ")} may be exported.`;
1510
1510
  const relativeFile = toRelative(projectRoot, file);
1511
1511
  const ast = parseModule(code, file);
1512
1512
 
@@ -1524,11 +1524,11 @@ export function checkRouteModuleExports(context: RouteExportCheckContext): void
1524
1524
  code: "E_ROUTE_EXPORT_INVALID",
1525
1525
  file: relativeFile,
1526
1526
  line: statement.loc?.start.line ?? 1,
1527
- message: "`export *` tidak diizinkan di modul route",
1527
+ message: "`export *` is not allowed in route modules",
1528
1528
  details: allowedText,
1529
1529
  suggestions: [
1530
- `Pindahkan isi file ke luar ${toRelative(projectRoot, routesDir)}/, atau`,
1531
- "Hapus `export *` tersebut",
1530
+ `Move the file contents outside ${toRelative(projectRoot, routesDir)}/, or`,
1531
+ "Remove the `export *`",
1532
1532
  ],
1533
1533
  });
1534
1534
  }
@@ -1564,11 +1564,11 @@ export function checkRouteModuleExports(context: RouteExportCheckContext): void
1564
1564
  code: "E_ROUTE_EXPORT_INVALID",
1565
1565
  file: relativeFile,
1566
1566
  line: entry.line,
1567
- message: `export \`${entry.name}\` tidak diizinkan di modul route`,
1567
+ message: `export \`${entry.name}\` is not allowed in route modules`,
1568
1568
  details: allowedText,
1569
1569
  suggestions: [
1570
- `Pindahkan \`${entry.name}\` ke file di luar ${toRelative(projectRoot, routesDir)}/, atau`,
1571
- "Hapus export tersebut",
1570
+ `Move \`${entry.name}\` to a file outside ${toRelative(projectRoot, routesDir)}/, or`,
1571
+ "Remove the export",
1572
1572
  ],
1573
1573
  });
1574
1574
  }
@@ -1578,9 +1578,9 @@ export function checkRouteModuleExports(context: RouteExportCheckContext): void
1578
1578
  throw new MoonsError({
1579
1579
  code: "E_ROUTE_EXPORT_INVALID",
1580
1580
  file: relativeFile,
1581
- message: "modul route wajib mengekspor `default`",
1582
- details: "Setiap file route harus punya `export default` berupa komponen React.",
1583
- suggestions: ["Tambahkan `export default function Page() { ... }`"],
1581
+ message: "route module must export `default`",
1582
+ details: "Every route file needs an `export default` React component.",
1583
+ suggestions: ["Add `export default function Page() { ... }`"],
1584
1584
  });
1585
1585
  }
1586
1586
  }
@@ -1,15 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/server/shell.ts", "../src/server/node.ts", "../src/virtual-modules.ts", "../src/server/dev.ts", "../src/devtools.ts", "../src/manifest.ts"],
4
- "sourcesContent": [
5
- "import { MoonsError } from \"@moonsjs/core\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { ViteDevServer } from \"vite\";\n\nexport type Shell = (\n markup: string,\n payload: string,\n url: string,\n meta?: Record<string, unknown>,\n) => string | Promise<string>;\n\nexport const ROOT_PLACEHOLDER = '<div id=\"root\"></div>';\n\nexport const DEFAULT_TEMPLATE = [\n \"<!doctype html>\",\n '<html lang=\"id\">',\n \"<head>\",\n ' <meta charset=\"utf-8\" />',\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n \" <title>Moons</title>\",\n \"</head>\",\n \"<body>\",\n ` ${ROOT_PLACEHOLDER}`,\n ' <script type=\"module\" src=\"/src/client/main.tsx\"></script>',\n \"</body>\",\n \"</html>\",\n \"\",\n].join(\"\\n\");\n\n/** Inject markup SSR + payload devalue ke shell HTML (PRD §8.2, §17, Addendum B.1). */\nexport function injectShell(\n template: string,\n markup: string,\n payload: string,\n meta?: Record<string, unknown>,\n): string {\n if (!template.includes(ROOT_PLACEHOLDER)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n message: `shell HTML tidak memuat \\`${ROOT_PLACEHOLDER}\\``,\n details: \"index.html aplikasi wajib memuat elemen root tersebut agar SSR bisa meng-inject markup.\",\n suggestions: [\n `Tambahkan ${ROOT_PLACEHOLDER} ke index.html`,\n \"Atau hapus index.html untuk memakai shell bawaan\",\n ],\n });\n }\n const dataScript = `<script id=\"__moons_data\" type=\"application/x-moons\">${payload}</script>`;\n const withRoot = template.replace(ROOT_PLACEHOLDER, `<div id=\"root\">${markup}</div>${dataScript}`);\n return applyMeta(withRoot, meta);\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\");\n}\n\n/**\n * Terapkan meta route ke `<head>` (Addendum B.1): `<title>` + description/og.\n * Tag yang sudah ada (mis. di index.html) ditimpa; yang belum ada disisipkan\n * sebelum `</head>`.\n */\nfunction applyMeta(html: string, meta: Record<string, unknown> | undefined): string {\n if (meta === undefined) {\n return html;\n }\n let out = html;\n if (typeof meta.title === \"string\") {\n const title = `<title>${escapeHtml(meta.title)}</title>`;\n out = /<title>[\\s\\S]*?<\\/title>/.test(out)\n ? out.replace(/<title>[\\s\\S]*?<\\/title>/, title)\n : out.replace(\"</head>\", ` ${title}\\n</head>`);\n }\n\n const tags: Array<{ attr: \"name\" | \"property\"; key: string; value: unknown }> = [\n { attr: \"name\", key: \"description\", value: meta.description },\n { attr: \"property\", key: \"og:title\", value: meta.title },\n { attr: \"property\", key: \"og:description\", value: meta.description },\n ];\n for (const tag of tags) {\n if (typeof tag.value !== \"string\") {\n continue;\n }\n const rendered = `<meta ${tag.attr}=\"${tag.key}\" content=\"${escapeHtml(tag.value)}\" />`;\n const pattern = new RegExp(`<meta[^>]*${tag.attr}=\"${tag.key}\"[^>]*>`);\n out = pattern.test(out)\n ? out.replace(pattern, rendered)\n : out.replace(\"</head>\", ` ${rendered}\\n</head>`);\n }\n return out;\n}\n\n/**\n * Shell untuk dev: baca `index.html` dari disk setiap request (selalu segar)\n * lalu lewatkan ke Vite `transformIndexHtml` (inject `/@vite/client`, dsb).\n */\nexport function createDevShell(server: ViteDevServer, options: { templatePath: string }): Shell {\n return async (markup, payload, url, meta) => {\n const template = existsSync(options.templatePath)\n ? readFileSync(options.templatePath, \"utf8\")\n : DEFAULT_TEMPLATE;\n const html = injectShell(template, markup, payload, meta);\n return await server.transformIndexHtml(url, html);\n };\n}\n\n/** Shell untuk produksi: baca `dist/client/index.html` sekali dari cwd. */\nexport function createFileShell(options: { clientDir?: string } = {}): Shell {\n let cached: string | null = null;\n return async (markup, payload, _url, meta) => {\n if (cached === null) {\n const clientDir = resolve(options.clientDir ?? process.cwd(), \"dist/client\");\n const file = join(clientDir, \"index.html\");\n if (!existsSync(file)) {\n throw new MoonsError({\n code: \"E_INTERNAL\",\n file,\n message: \"`dist/client/index.html` tidak ditemukan\",\n details: \"Build client harus dijalankan sebelum server produksi dinyalakan.\",\n suggestions: [\"Jalankan `bun run build` lebih dulu\"],\n });\n }\n cached = readFileSync(file, \"utf8\");\n }\n return injectShell(cached, markup, payload, meta);\n };\n}\n",
6
- "import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { CLIENT_IP_HEADER } from \"@moonsjs/core\";\n\n/** Batas transport default (Addendum J.2); RPC punya batas lebih kecil dari config. */\nexport const MAX_TRANSPORT_BODY_BYTES = 32 * 1024 * 1024;\n\n/** Request tidak valid (Host/URL malformed) → dipetakan ke 400 oleh server. */\nexport class InvalidRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidRequestError\";\n }\n}\n\n/** Body melebihi batas → dipetakan ke 413; pembacaan dihentikan saat melewati. */\nexport class BodyLimitError extends Error {\n readonly limit: number;\n constructor(limit: number) {\n super(`request body melebihi batas ${limit} byte`);\n this.name = \"BodyLimitError\";\n this.limit = limit;\n }\n}\n\nexport interface ToWebRequestOptions {\n /** Addendum J.1: percayai `x-forwarded-proto`/`x-forwarded-host` (default false). */\n trustProxy?: boolean;\n /** Batas pembacaan body (byte). Default: `MAX_TRANSPORT_BODY_BYTES`. */\n maxBodyBytes?: number;\n}\n\n/**\n * Rekonstruksi URL request (Addendum J.1). Tanpa `trustProxy`, origin/host\n * murni dari header `Host` (perilaku lama, kebal spoofing `x-forwarded-*`).\n * Malformed → `InvalidRequestError` (server memetakan ke 400).\n */\nexport function resolveRequestUrl(\n req: IncomingMessage,\n options: ToWebRequestOptions = {},\n): URL {\n const hostHeader = req.headers.host ?? \"localhost\";\n const trustProxy = options.trustProxy === true;\n const proto = trustProxy ? forwardedProtocol(req.headers[\"x-forwarded-proto\"]) : null;\n const forwardedHostValue = trustProxy ? forwardedHost(req.headers[\"x-forwarded-host\"]) : null;\n const host = forwardedHostValue ?? hostHeader;\n try {\n return new URL(`${proto ?? \"http\"}://${host}${req.url ?? \"/\"}`);\n } catch {\n throw new InvalidRequestError(`header Host tidak valid: ${JSON.stringify(hostHeader)}`);\n }\n}\n\n/** IP klien tepercaya (Addendum J.1): XFF (hanya bila trustProxy) → socket. */\nexport function resolveClientIp(req: IncomingMessage, trustProxy: boolean): string | null {\n if (trustProxy) {\n const forwarded = firstHeaderValue(req.headers[\"x-forwarded-for\"]);\n if (forwarded !== null && isPlausibleIp(forwarded)) {\n return normalizeIp(forwarded);\n }\n }\n const remote = req.socket?.remoteAddress ?? null;\n return remote === null ? null : normalizeIp(remote);\n}\n\n/** `::ffff:127.0.0.1` → `127.0.0.1`; buang zone id (`%eth0`). */\nfunction normalizeIp(value: string): string {\n const withoutZone = stripZoneId(value);\n return withoutZone.startsWith(\"::ffff:\") ? withoutZone.slice(7) : withoutZone;\n}\n\n/** Konversi request Node → Web `Request` (body diteruskan untuk non-GET/HEAD, §7.3 + J.1/J.2). */\nexport async function toWebRequest(\n req: IncomingMessage,\n options: ToWebRequestOptions = {},\n): Promise<Request> {\n const url = resolveRequestUrl(req, options);\n const method = req.method ?? \"GET\";\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined || key === \"content-length\" || key === CLIENT_IP_HEADER) {\n // content-length tidak disalin; fetch menghitung ulang dari body.\n // x-moons-client-ip selalu ditimpa nilai tepercaya di bawah.\n continue;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(key, item);\n }\n } else {\n headers.set(key, value);\n }\n }\n\n const clientIp = resolveClientIp(req, options.trustProxy === true);\n if (clientIp !== null) {\n headers.set(CLIENT_IP_HEADER, clientIp);\n }\n\n if (method === \"GET\" || method === \"HEAD\") {\n return new Request(url, { method, headers });\n }\n\n const body = await readBody(req, options.maxBodyBytes ?? MAX_TRANSPORT_BODY_BYTES);\n // View zero-copy (bukan salinan) — Buffer selalu di atas ArrayBuffer biasa.\n const view = new Uint8Array(body.buffer as ArrayBuffer, body.byteOffset, body.byteLength);\n return new Request(url, { method, headers, body: view });\n}\n\n/**\n * Baca body dengan batas tegas (Addendum J.2): begitu melewati `maxBytes`,\n * pembacaan dihentikan (pause) dan `BodyLimitError` dilempar — tidak pernah\n * seluruh body besar masuk memori, dan hanya satu salinan buffer dibuat.\n */\nexport function readBody(req: IncomingMessage, maxBytes: number): Promise<Buffer> {\n return new Promise((resolvePromise, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n let settled = false;\n\n const fail = (error: Error): void => {\n if (settled) {\n return;\n }\n settled = true;\n req.pause();\n reject(error);\n };\n\n req.on(\"data\", (chunk: Buffer) => {\n if (settled) {\n return;\n }\n size += chunk.length;\n if (size > maxBytes) {\n fail(new BodyLimitError(maxBytes));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => {\n if (!settled) {\n settled = true;\n resolvePromise(Buffer.concat(chunks));\n }\n });\n req.on(\"error\", (error) => fail(error));\n });\n}\n\n/** Addendum J.7: default aman runtime; `config.headers` tetap menang (cek hasHeader). */\nexport const DEFAULT_SECURITY_HEADERS: Record<string, string> = {\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"strict-origin-when-cross-origin\",\n};\n\n/** Tulis Web `Response` ke `ServerResponse` Node (streaming bila ada body). */\nexport async function sendNodeResponse(res: ServerResponse, response: Response): Promise<void> {\n res.statusCode = response.status;\n response.headers.forEach((value, key) => {\n // `set-cookie` ditangani terpisah: forEach menggabungkan nilai ganda\n // menjadi satu string (cookie kedua hilang — D.2).\n if (key === \"set-cookie\") {\n return;\n }\n res.setHeader(key, value);\n });\n const getSetCookie = (response.headers as { getSetCookie?: () => string[] }).getSetCookie;\n if (typeof getSetCookie === \"function\") {\n const cookies = getSetCookie.call(response.headers);\n if (cookies.length > 0) {\n res.setHeader(\"set-cookie\", cookies);\n }\n } else {\n const single = response.headers.get(\"set-cookie\");\n if (single !== null) {\n res.setHeader(\"set-cookie\", single);\n }\n }\n\n for (const [name, value] of Object.entries(DEFAULT_SECURITY_HEADERS)) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n\n if (response.body === null || res.req?.method === \"HEAD\") {\n res.end();\n return;\n }\n\n // Addendum J.2: stream langsung — tidak ada `arrayBuffer()` penuh di memori.\n await pipeline(\n Readable.fromWeb(response.body as unknown as import(\"node:stream/web\").ReadableStream),\n res,\n );\n}\n\nfunction firstHeaderValue(value: string | string[] | undefined): string | null {\n if (value === undefined) {\n return null;\n }\n const raw = Array.isArray(value) ? value[0] : value;\n if (raw === undefined) {\n return null;\n }\n const first = raw.split(\",\")[0]?.trim() ?? \"\";\n return first.length === 0 ? null : first;\n}\n\nfunction forwardedProtocol(value: string | string[] | undefined): \"http\" | \"https\" | null {\n const first = firstHeaderValue(value)?.toLowerCase() ?? null;\n if (first === \"https\") {\n return \"https\";\n }\n if (first === \"http\") {\n return \"http\";\n }\n return null;\n}\n\nfunction forwardedHost(value: string | string[] | undefined): string | null {\n const first = firstHeaderValue(value);\n if (first === null || first.length === 0 || first.length > 255) {\n return null;\n }\n // hostname[:port] — tolak karakter di luar himpunan aman (spasi, CRLF, /, @, ?).\n if (!/^[A-Za-z0-9.\\-[\\]:]+$/.test(first)) {\n return null;\n }\n return first;\n}\n\nfunction isPlausibleIp(value: string): boolean {\n return value.length <= 64 && /^[0-9a-fA-F:.]+$/.test(value);\n}\n\nfunction stripZoneId(value: string): string {\n const index = value.indexOf(\"%\");\n return index === -1 ? value : value.slice(0, index);\n}\n",
7
- "/** Nama virtual module PRD §9.4. Semua di-resolve ke id `\\0`-prefix. */\nexport const VIRTUAL_MODULES = {\n routes: \"virtual:moons/routes\",\n api: \"virtual:moons/api\",\n config: \"virtual:moons/config\",\n clientEntry: \"virtual:moons/client-entry\",\n serverEntry: \"virtual:moons/server-entry\",\n} as const;\n\nexport type VirtualModuleName = (typeof VIRTUAL_MODULES)[keyof typeof VIRTUAL_MODULES];\n\nexport function isVirtualModuleId(id: string): id is VirtualModuleName {\n const clean = id.startsWith(\"\\0\") ? id.slice(1) : id;\n return (Object.values(VIRTUAL_MODULES) as string[]).includes(clean);\n}\n\nexport function toNullPrefixed(id: VirtualModuleName): `\\0${string}` {\n return `\\0${id}`;\n}\n\nexport function fromNullPrefixed(id: string): VirtualModuleName | null {\n const clean = id.startsWith(\"\\0\") ? id.slice(1) : id;\n return isVirtualModuleId(clean) ? (clean as VirtualModuleName) : null;\n}\n",
8
- "import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { ViteDevServer } from \"vite\";\nimport { VIRTUAL_MODULES } from \"../virtual-modules\";\nimport type { PayloadScanOptions } from \"../payload-scan\";\nimport type { PluginRuntime } from \"./plugins\";\nimport type { Shell } from \"./shell\";\nimport { createDevShell } from \"./shell\";\nimport {\n BodyLimitError,\n InvalidRequestError,\n resolveRequestUrl,\n sendNodeResponse,\n toWebRequest,\n} from \"./node\";\nimport { DEFAULT_BODY_LIMIT_BYTES } from \"@moonsjs/core\";\nimport { emptyDevtoolsData, renderDevtoolsHtml, type DevtoolsData } from \"../devtools\";\n\ninterface DevApp {\n handler: (request: Request) => Promise<Response>;\n plugins: PluginRuntime;\n}\n\ntype DevServerEntry = {\n createDevApp: (\n shell: Shell,\n payloadScan?: import(\"../payload-scan\").PayloadScanOptions,\n ) => DevApp;\n};\n\n/**\n * Middleware SSR dev: dipasang sebelum middleware internal Vite, menangani\n * request HTML dan RPC serverFn (`/_moons/fn/*`) — modul/aset tetap Vite.\n * Handler + lifecycle plugin (Addendum B.4) diinisialisasi sekali.\n */\nexport function installDevMiddleware(\n server: ViteDevServer,\n options: {\n templatePath: string;\n payloadScan?: PayloadScanOptions;\n apiPrefix?: string;\n /** Addendum J.1: paritas dev dengan produksi (trustProxy/bodyLimitBytes). */\n trustProxy?: boolean;\n bodyLimitBytes?: number;\n /** Addendum I.4: datasource devtools overlay (dipanggil per request). */\n devtools?: () => DevtoolsData;\n },\n): void {\n let appPromise: Promise<DevApp> | null = null;\n\n const getApp = (): Promise<DevApp> => {\n if (appPromise === null) {\n appPromise = (async () => {\n const entry = (await server.ssrLoadModule(VIRTUAL_MODULES.serverEntry)) as DevServerEntry;\n const app = entry.createDevApp(createDevShell(server, options), options.payloadScan);\n await app.plugins.start();\n await app.plugins.ready();\n return app;\n })();\n }\n return appPromise;\n };\n\n server.httpServer?.once(\"close\", () => {\n void appPromise?.then((app) => app.plugins.shutdown());\n });\n\n server.middlewares.use((req, res, next) => {\n // Addendum I.4 (W4): overlay dev-only — selalu data segar per request.\n if (\n (req.method === \"GET\" || req.method === \"HEAD\") &&\n new URL(req.url ?? \"/\", \"http://localhost\").pathname === \"/__moons/devtools\"\n ) {\n try {\n const data = options.devtools?.() ?? emptyDevtoolsData();\n res.statusCode = 200;\n res.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n res.end(req.method === \"HEAD\" ? undefined : renderDevtoolsHtml(data));\n } catch (error) {\n res.statusCode = 500;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(`[moons] devtools gagal dirender: ${String(error)}`);\n }\n return;\n }\n\n if (!shouldHandle(req, options.apiPrefix)) {\n next();\n return;\n }\n void handleRequest(getApp, req, res, options).catch((error: unknown) => {\n if (error instanceof InvalidRequestError) {\n res.statusCode = 400;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Bad Request\");\n return;\n }\n if (error instanceof BodyLimitError) {\n res.statusCode = 413;\n res.setHeader(\"content-type\", \"text/plain; charset=utf-8\");\n res.end(\"Payload Too Large\");\n res.once(\"finish\", () => req.destroy());\n return;\n }\n next(error as Error);\n });\n });\n}\n\nasync function handleRequest(\n getApp: () => Promise<DevApp>,\n req: IncomingMessage,\n res: ServerResponse,\n options: { trustProxy?: boolean; bodyLimitBytes?: number },\n): Promise<void> {\n const app = await getApp();\n const url = resolveRequestUrl(req, { trustProxy: options.trustProxy === true });\n const isRpc = url.pathname.startsWith(\"/_moons/fn/\");\n const request = await toWebRequest(req, {\n trustProxy: options.trustProxy === true,\n ...(isRpc ? { maxBodyBytes: options.bodyLimitBytes ?? DEFAULT_BODY_LIMIT_BYTES } : {}),\n });\n const response = await app.handler(request);\n await sendNodeResponse(res, response);\n}\n\nfunction shouldHandle(req: IncomingMessage, apiPrefix: string | undefined): boolean {\n const path = new URL(req.url ?? \"/\", \"http://localhost\").pathname;\n\n // RPC serverFn (semua method): dulu hanya GET/HEAD HTML yang dirutekan,\n // sehingga `POST /_moons/fn/<hash>` jatuh ke Vite (\"Cannot POST\", 404) dan\n // serverFn tidak bisa dipakai di dev (temuan eval T2 ronde 2; decisions/0016).\n if (path.startsWith(\"/_moons/fn/\")) {\n return true;\n }\n\n // Addendum D.1: endpoint `src/api` (semua method) dirutekan ke runtime.\n if (apiPrefix !== undefined && (path === apiPrefix || path.startsWith(`${apiPrefix}/`))) {\n return true;\n }\n\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n return false;\n }\n if (path.startsWith(\"/@\") || path.startsWith(\"/node_modules/\") || path.startsWith(\"/__\")) {\n return false;\n }\n const lastSegment = path.split(\"/\").pop() ?? \"\";\n if (lastSegment.includes(\".\")) {\n return false;\n }\n const accept = req.headers.accept ?? \"\";\n return accept.includes(\"text/html\") || accept.includes(\"*/*\");\n}\n",
9
- "/**\n * Addendum I.4 (W4): devtools overlay dev-only — tabel route, registry\n * serverFn (hash §12), endpoint `src/api`, dan status payload-scan.\n * Renderer murni (tanpa I/O) supaya bisa diuji unit; middleware dev yang\n * menyajikannya di `/__moons/devtools`.\n */\n\nexport interface DevtoolsRoute {\n /** Path URL (bentuk PRD §6.1), mis. \"/users/:id\". */\n path: string;\n /** \"page\" | \"layout\" | \"error\" | \"404\" | \"middleware\" | \"api\". */\n kind: string;\n /** Path relatif terhadap root app (posix). */\n file: string;\n}\n\nexport interface DevtoolsFn {\n file: string;\n name: string;\n hash: string;\n}\n\nexport interface DevtoolsData {\n routes: DevtoolsRoute[];\n apiRoutes: DevtoolsRoute[];\n serverFns: DevtoolsFn[];\n /** Canary `leakTest` terpasang → payload-scan aktif (A1). */\n canary: boolean;\n version: string;\n}\n\nexport function emptyDevtoolsData(): DevtoolsData {\n return { routes: [], apiRoutes: [], serverFns: [], canary: false, version: \"\" };\n}\n\nexport function renderDevtoolsHtml(data: DevtoolsData): string {\n const rows = (items: DevtoolsRoute[]): string =>\n items.length === 0\n ? '<tr><td colspan=\"3\" class=\"muted\">(kosong)</td></tr>'\n : items\n .map(\n (item) =>\n `<tr><td><code>${esc(item.path)}</code></td><td><span class=\"kind k-${esc(item.kind)}\">${esc(item.kind)}</span></td><td class=\"muted\">${esc(item.file)}</td></tr>`,\n )\n .join(\"\\n\");\n\n const fnRows =\n data.serverFns.length === 0\n ? '<tr><td colspan=\"3\" class=\"muted\">(tidak ada serverFn)</td></tr>'\n : data.serverFns\n .map(\n (fn) =>\n `<tr><td><code>${esc(fn.hash)}</code></td><td><code>${esc(fn.name)}</code></td><td class=\"muted\">${esc(fn.file)}</td></tr>`,\n )\n .join(\"\\n\");\n\n const canary = data.canary\n ? '<span class=\"ok\">aktif</span> (canary terpasang)'\n : '<span class=\"muted\">nonaktif</span> (tanpa canary)';\n\n return `<!doctype html>\n<html lang=\"id\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>moons devtools</title>\n<style>\n :root { color-scheme: dark; }\n body { margin: 0; padding: 2rem; background: #101418; color: #e6edf3;\n font: 14px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }\n h1 { font-size: 1.1rem; margin: 0 0 .25rem; }\n h2 { font-size: .95rem; margin: 2rem 0 .5rem; color: #9fb0c0; }\n .muted { color: #8b98a5; }\n .ok { color: #3fb950; font-weight: 600; }\n .meta { margin-bottom: 1.5rem; }\n table { border-collapse: collapse; width: 100%; max-width: 1100px; }\n th, td { text-align: left; padding: .35rem .75rem .35rem 0; border-bottom: 1px solid #1f2630; }\n th { color: #8b98a5; font-weight: 600; font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; }\n code { color: #79c0ff; }\n .kind { border: 1px solid #30363d; border-radius: 4px; padding: 0 .35rem; font-size: .8rem; }\n .k-page { color: #d2a8ff; } .k-layout { color: #7ee787; }\n .k-error { color: #ff7b72; } .k-404 { color: #ff7b72; }\n .k-middleware { color: #e3b341; } .k-api { color: #79c0ff; }\n</style>\n</head>\n<body>\n<h1>moons devtools</h1>\n<div class=\"meta muted\">@moonsjs/vite ${esc(data.version)} · dev-only · payload-scan: ${canary}</div>\n\n<h2>Routes (${data.routes.length})</h2>\n<table><thead><tr><th>path</th><th>kind</th><th>file</th></tr></thead>\n<tbody>\n${rows(data.routes)}\n</tbody></table>\n\n<h2>API (${data.apiRoutes.length})</h2>\n<table><thead><tr><th>path</th><th>kind</th><th>file</th></tr></thead>\n<tbody>\n${rows(data.apiRoutes)}\n</tbody></table>\n\n<h2>serverFn registry (${data.serverFns.length})</h2>\n<table><thead><tr><th>hash</th><th>export</th><th>file</th></tr></thead>\n<tbody>\n${fnRows}\n</tbody></table>\n</body>\n</html>\n`;\n}\n\nfunction esc(value: string): string {\n return value.replace(/[&<>\"']/g, (char) => {\n switch (char) {\n case \"&\":\n return \"&amp;\";\n case \"<\":\n return \"&lt;\";\n case \">\":\n return \"&gt;\";\n case '\"':\n return \"&quot;\";\n default:\n return \"&#39;\";\n }\n });\n}\n",
10
- "import { findLayouts, routeKeyFromFile, type ApiRouteDefinition, type RouteDefinition } from \"@moonsjs/core\";\nimport { relative, sep } from \"node:path\";\n\nexport interface ClientManifestEntry {\n page: string;\n layouts: string[];\n}\n\n/** Key manifest untuk halaman kustom `_404` dan `_error` (§11.2). */\nexport const NOT_FOUND_ROUTE_KEY = \"__moons/404\";\nexport const ERROR_ROUTE_KEY = \"__moons/error\";\n\n/**\n * Manifest route untuk client (PRD §8.2): key = key route file\n * (routeKeyFromFile), nilai = page + layout chain dari root ke leaf.\n */\nexport function buildClientManifest(\n routes: RouteDefinition[],\n routesDir: string,\n): Record<string, ClientManifestEntry> {\n const manifest: Record<string, ClientManifestEntry> = {};\n for (const route of routes) {\n if (route.kind !== \"page\") {\n continue;\n }\n const key = routeKeyFromFile(routesDir, route.file);\n manifest[key] = {\n page: key,\n layouts: findLayouts(route, routes).map((layout) => routeKeyFromFile(routesDir, layout.file)),\n };\n }\n\n const notFound = routes.find((route) => route.kind === \"404\");\n if (notFound !== undefined) {\n manifest[NOT_FOUND_ROUTE_KEY] = { page: routeKeyFromFile(routesDir, notFound.file), layouts: [] };\n }\n const errorRoute = routes.find((route) => route.kind === \"error\");\n if (errorRoute !== undefined) {\n manifest[ERROR_ROUTE_KEY] = { page: routeKeyFromFile(routesDir, errorRoute.file), layouts: [] };\n }\n // D.3: semua boundary `_error` (termasuk bersarang) ikut manifest — payload\n // memakai key file boundary yang dipilih runtime.\n for (const route of routes) {\n if (route.kind !== \"error\") {\n continue;\n }\n const key = routeKeyFromFile(routesDir, route.file);\n manifest[key] = { page: key, layouts: [] };\n }\n\n return manifest;\n}\n\n/** `virtual:moons/api` (Addendum D.1 + D.3): tabel API + middleware + peta import(). */\nexport function renderApiModule(\n apiRoutes: ApiRouteDefinition[],\n apiMiddlewares: ReadonlyArray<{ file: string; dir: string }>,\n projectRoot: string,\n): string {\n const loadEntries = apiRoutes\n .map(\n (route) =>\n ` ${JSON.stringify(route.path)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, route.file))}),`,\n )\n .join(\"\\n\");\n const middlewareEntries = apiMiddlewares\n .map(\n (middleware) =>\n ` ${JSON.stringify(middleware.file)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, middleware.file))}),`,\n )\n .join(\"\\n\");\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n `export const apiRoutes = ${JSON.stringify(apiRoutes, null, 2)};`,\n `export const apiMiddlewares = ${JSON.stringify(apiMiddlewares, null, 2)};`,\n \"export const loadApi = {\",\n loadEntries,\n \"};\",\n \"export const loadApiMiddleware = {\",\n middlewareEntries,\n \"};\",\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Isi `virtual:moons/routes`: daftar RouteDefinition, manifest client, dan\n * peta import() dinamis per file route (specifier root-relative).\n */\nexport function renderRoutesModule(\n routes: RouteDefinition[],\n routesDir: string,\n projectRoot: string,\n): string {\n const manifest = buildClientManifest(routes, routesDir);\n\n const loadEntries = routes.map((route) => {\n const key = routeKeyFromFile(routesDir, route.file);\n return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(rootSpecifier(projectRoot, route.file))}),`;\n });\n\n return [\n \"// Generated by @moons. Jangan diubah manual.\",\n `export const routes = ${JSON.stringify(routes, null, 2)};`,\n \"\",\n `export const clientManifest = ${JSON.stringify(manifest, null, 2)};`,\n \"\",\n \"export const loadRoute = {\",\n ...loadEntries,\n \"};\",\n \"\",\n ].join(\"\\n\");\n}\n\n/** Path file absolut project → specifier root-relative yang bisa di-resolve Vite. */\nexport function rootSpecifier(projectRoot: string, file: string): string {\n let rel = relative(projectRoot, file);\n rel = sep === \"/\" ? rel : rel.split(sep).join(\"/\");\n return rel.startsWith(\"/\") ? rel : `/${rel}`;\n}\n"
11
- ],
12
- "mappings": "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",
13
- "debugId": "9EF4B5AD3ED4C6D264756E2164756E21",
14
- "names": []
15
- }