@palbase/backend 25.1.0 → 27.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/bin/palbase-backend.cjs +2432 -1039
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +87 -51
  4. package/dist/bin/palbase-backend.js.map +1 -1
  5. package/dist/chunk-BQN723PL.js +930 -0
  6. package/dist/chunk-BQN723PL.js.map +1 -0
  7. package/dist/chunk-CGNN2PUH.js +213 -0
  8. package/dist/chunk-CGNN2PUH.js.map +1 -0
  9. package/dist/{chunk-VDF2T4AS.js → chunk-EB3TUX5J.js} +1228 -591
  10. package/dist/chunk-EB3TUX5J.js.map +1 -0
  11. package/dist/chunk-JVZQCC77.js +728 -0
  12. package/dist/chunk-JVZQCC77.js.map +1 -0
  13. package/dist/chunk-OZKSM3JW.js +370 -0
  14. package/dist/chunk-OZKSM3JW.js.map +1 -0
  15. package/dist/{chunk-YOY5DFQS.js → chunk-TWX6JTGJ.js} +76 -34
  16. package/dist/{chunk-YOY5DFQS.js.map → chunk-TWX6JTGJ.js.map} +1 -1
  17. package/dist/{chunk-35PNTIRN.js → chunk-VVMJEVQP.js} +63 -162
  18. package/dist/chunk-VVMJEVQP.js.map +1 -0
  19. package/dist/{chunk-7D4SUZUM.js → chunk-VXPNPVAG.js} +3 -1
  20. package/dist/chunk-XABHGMUT.js +885 -0
  21. package/dist/chunk-XABHGMUT.js.map +1 -0
  22. package/dist/db/env.cjs.map +1 -1
  23. package/dist/db/env.d.cts +2 -2
  24. package/dist/db/env.d.ts +2 -2
  25. package/dist/db/index.cjs +780 -344
  26. package/dist/db/index.cjs.map +1 -1
  27. package/dist/db/index.d.cts +2 -2
  28. package/dist/db/index.d.ts +2 -2
  29. package/dist/db/index.js +7 -4
  30. package/dist/engine/index.cjs +2366 -1002
  31. package/dist/engine/index.cjs.map +1 -1
  32. package/dist/engine/index.d.cts +6 -6
  33. package/dist/engine/index.d.ts +6 -6
  34. package/dist/engine/index.js +7 -6
  35. package/dist/{index-CUomTA3e.d.ts → index-CAKOgAlP.d.ts} +171 -296
  36. package/dist/index-CgE4sVhg.d.cts +4864 -0
  37. package/dist/{index-ClpDeSos.d.cts → index-H-0qv5d4.d.cts} +171 -296
  38. package/dist/index-V7QRh1wg.d.ts +4864 -0
  39. package/dist/index.cjs +2720 -1169
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +165 -19
  42. package/dist/index.d.ts +165 -19
  43. package/dist/index.js +738 -477
  44. package/dist/index.js.map +1 -1
  45. package/dist/module-Dl1KFVtc.d.cts +54 -0
  46. package/dist/module-Dl1KFVtc.d.ts +54 -0
  47. package/dist/openapi/index.cjs +1330 -484
  48. package/dist/openapi/index.cjs.map +1 -1
  49. package/dist/openapi/index.d.cts +4 -2
  50. package/dist/openapi/index.d.ts +4 -2
  51. package/dist/openapi/index.js +1264 -474
  52. package/dist/openapi/index.js.map +1 -1
  53. package/dist/{registry-dZZ5JKYg.d.ts → registry-4EI8aaFs.d.ts} +1 -1
  54. package/dist/{registry-CC0WBQq6.d.cts → registry-DHsPDY0_.d.cts} +1 -1
  55. package/dist/stack.cjs.map +1 -1
  56. package/dist/test/index.cjs +732 -141
  57. package/dist/test/index.cjs.map +1 -1
  58. package/dist/test/index.d.cts +30 -4
  59. package/dist/test/index.d.ts +30 -4
  60. package/dist/test/index.js +490 -124
  61. package/dist/test/index.js.map +1 -1
  62. package/docs/README.md +33 -18
  63. package/docs/auth.md +1 -1
  64. package/docs/background.md +2 -2
  65. package/docs/database.md +255 -50
  66. package/docs/endpoints.md +3 -4
  67. package/docs/events.md +3 -3
  68. package/docs/getting-started.md +1 -1
  69. package/docs/llms-full.txt +435 -117
  70. package/docs/migrations.md +2 -2
  71. package/docs/schema.md +19 -10
  72. package/docs/services.md +116 -26
  73. package/package.json +8 -4
  74. package/stager/generics.js +205 -0
  75. package/stager/stage.js +39 -3
  76. package/template/AGENTS.md +110 -72
  77. package/template/db/public.ts +1 -1
  78. package/template/{controllers → modules/health}/health.controller.ts +1 -1
  79. package/template/modules/health/health.module.ts +24 -0
  80. package/template/modules/notes/note.service.test.ts +49 -0
  81. package/template/modules/notes/note.service.ts +108 -0
  82. package/template/{controllers → modules/notes}/notes.controller.ts +17 -11
  83. package/template/modules/notes/notes.module.ts +37 -0
  84. package/template/package.json +5 -3
  85. package/template/scripts/test.sh +33 -0
  86. package/template/tsconfig.json +29 -30
  87. package/dist/chunk-35PNTIRN.js.map +0 -1
  88. package/dist/chunk-CJSKYY76.js +0 -627
  89. package/dist/chunk-CJSKYY76.js.map +0 -1
  90. package/dist/chunk-CRQKCRGF.js +0 -276
  91. package/dist/chunk-CRQKCRGF.js.map +0 -1
  92. package/dist/chunk-G4R6BTLV.js +0 -662
  93. package/dist/chunk-G4R6BTLV.js.map +0 -1
  94. package/dist/chunk-VDF2T4AS.js.map +0 -1
  95. package/dist/chunk-XABBC7JP.js +0 -55
  96. package/dist/chunk-XABBC7JP.js.map +0 -1
  97. package/dist/endpoint-CTEHhb7A.d.ts +0 -2386
  98. package/dist/endpoint-DYHMo6cC.d.cts +0 -2386
  99. package/dist/index-CW21M9Z3.d.ts +0 -1222
  100. package/dist/index-CmBK76nx.d.cts +0 -1222
  101. package/template/services/note.service.test.ts +0 -45
  102. package/template/services/note.service.ts +0 -76
  103. /package/dist/{chunk-7D4SUZUM.js.map → chunk-VXPNPVAG.js.map} +0 -0
  104. /package/template/{models/notes → modules/notes/dto}/create.ts +0 -0
@@ -3,17 +3,20 @@ import {
3
3
  BootRefused,
4
4
  createApp,
5
5
  loadConfig
6
- } from "../chunk-VDF2T4AS.js";
7
- import "../chunk-CRQKCRGF.js";
8
- import "../chunk-XABBC7JP.js";
9
- import "../chunk-CJSKYY76.js";
6
+ } from "../chunk-EB3TUX5J.js";
7
+ import "../chunk-BQN723PL.js";
8
+ import "../chunk-OZKSM3JW.js";
9
+ import "../chunk-JVZQCC77.js";
10
10
  import {
11
11
  getRegisteredControllers
12
- } from "../chunk-35PNTIRN.js";
13
- import "../chunk-7D4SUZUM.js";
12
+ } from "../chunk-VVMJEVQP.js";
13
+ import "../chunk-CGNN2PUH.js";
14
+ import {
15
+ __name
16
+ } from "../chunk-VXPNPVAG.js";
14
17
 
15
18
  // src/bin/palbase-backend.ts
16
- import { readdir, stat } from "fs/promises";
19
+ import { readdir } from "fs/promises";
17
20
  import { join, resolve } from "path";
18
21
  import { pathToFileURL } from "url";
19
22
  var USAGE = `palbase-backend \u2014 run this project's backend
@@ -35,6 +38,7 @@ function die(message) {
35
38
  console.error(message);
36
39
  process.exit(1);
37
40
  }
41
+ __name(die, "die");
38
42
  async function loadDotEnv(root) {
39
43
  const file = Bun.file(join(root, ".env"));
40
44
  if (!await file.exists()) return;
@@ -52,24 +56,35 @@ async function loadDotEnv(root) {
52
56
  process.env[key] = value;
53
57
  }
54
58
  }
55
- async function findControllers(root) {
56
- const dir = join(root, "controllers");
57
- try {
58
- if (!(await stat(dir)).isDirectory()) return [];
59
- } catch {
60
- return [];
61
- }
59
+ __name(loadDotEnv, "loadDotEnv");
60
+ var NEVER_WALK = /* @__PURE__ */ new Set([
61
+ "node_modules",
62
+ "dist",
63
+ "build",
64
+ ".git"
65
+ ]);
66
+ async function findModules(root) {
62
67
  const out = [];
63
- const walk = async (d) => {
64
- for (const entry of await readdir(d, { withFileTypes: true })) {
68
+ const walk = /* @__PURE__ */ __name(async (d) => {
69
+ let entries;
70
+ try {
71
+ entries = await readdir(d, {
72
+ withFileTypes: true
73
+ });
74
+ } catch {
75
+ return;
76
+ }
77
+ for (const entry of entries) {
78
+ if (NEVER_WALK.has(entry.name) || entry.name.startsWith(".palbase")) continue;
65
79
  const full = join(d, entry.name);
66
80
  if (entry.isDirectory()) await walk(full);
67
- else if (/\.controller\.(ts|js|mts|mjs)$/.test(entry.name)) out.push(full);
81
+ else if (/\.module\.(ts|js|mts|mjs)$/.test(entry.name)) out.push(full);
68
82
  }
69
- };
70
- await walk(dir);
83
+ }, "walk");
84
+ await walk(root);
71
85
  return out.sort();
72
86
  }
87
+ __name(findModules, "findModules");
73
88
  async function importSchemas(root) {
74
89
  let entries;
75
90
  try {
@@ -85,86 +100,107 @@ async function importSchemas(root) {
85
100
  }
86
101
  return out;
87
102
  }
103
+ __name(importSchemas, "importSchemas");
88
104
  async function main() {
89
105
  const command = process.argv[2] ?? "serve";
90
106
  if (command === "--help" || command === "-h" || command === "help") {
91
107
  console.log(USAGE);
92
108
  return;
93
109
  }
94
- if (!["serve", "dev", "routes"].includes(command)) {
110
+ if (![
111
+ "serve",
112
+ "dev",
113
+ "routes"
114
+ ].includes(command)) {
95
115
  die(`palbase-backend: unknown command "${command}".
96
116
 
97
117
  ${USAGE}`);
98
118
  }
99
119
  if (typeof Bun === "undefined") {
100
- die(
101
- "palbase-backend needs Bun: the engine serves `fetch` natively and opens its own\nPostgres pool through Bun.sql. Install it from https://bun.sh, then re-run."
102
- );
120
+ die("palbase-backend needs Bun: the engine serves `fetch` natively and opens its own\nPostgres pool through Bun.sql. Install it from https://bun.sh, then re-run.");
103
121
  }
104
122
  if (command === "dev" && !process.env.PALBASE_WATCHING) {
105
123
  const self = Bun.fileURLToPath(import.meta.url);
106
- const child = Bun.spawn(["bun", "--watch", self, "serve"], {
107
- stdio: ["inherit", "inherit", "inherit"],
108
- env: { ...process.env, PALBASE_WATCHING: "1" }
124
+ const child = Bun.spawn([
125
+ "bun",
126
+ "--watch",
127
+ self,
128
+ "serve"
129
+ ], {
130
+ stdio: [
131
+ "inherit",
132
+ "inherit",
133
+ "inherit"
134
+ ],
135
+ env: {
136
+ ...process.env,
137
+ PALBASE_WATCHING: "1"
138
+ }
109
139
  });
110
140
  process.exit(await child.exited);
111
141
  }
112
142
  const root = resolve(process.env.PALBASE_PROJECT_DIR ?? process.cwd());
113
143
  await loadDotEnv(root);
114
- const files = await findControllers(root);
144
+ const files = await findModules(root);
115
145
  if (files.length === 0) {
116
- die(
117
- `palbase-backend: no controllers found under ${join(root, "controllers")}.
118
- A backend is its controllers \u2014 add one and run again:
146
+ die(`palbase-backend: no *.module.ts under ${root}.
147
+ A module is what says which classes exist, who owns them and what they may
148
+ reach \u2014 and it is the only place that says it. Add one and run again:
119
149
 
120
- // controllers/hello.controller.ts
121
- import { Controller, Get } from "@palbase/backend";
122
- @Controller("/hello")
123
- class HelloController {
124
- @Get("") hi(): Promise<{ ok: boolean }> { return Promise.resolve({ ok: true }); }
125
- }
126
- `
127
- );
150
+ // todos.module.ts
151
+ import { Module, type Token } from "@palbase/backend";
152
+ import { TodosController } from "./controllers/todos.controller.ts";
153
+ @Module({ controllers: [TodosController as Token] })
154
+ export class TodosModule {}
155
+ `);
128
156
  }
129
157
  for (const file of files) await import(pathToFileURL(file).href);
130
158
  const controllers = getRegisteredControllers();
131
159
  if (controllers.length === 0) {
132
- die(
133
- `palbase-backend: ${files.length} controller file(s) loaded but none registered.
134
- Every one of them is missing its @Controller decorator, or the files were
135
- compiled with decorators stripped. Nothing would answer, so this is fatal.`
136
- );
160
+ die(`palbase-backend: ${files.length} module file(s) loaded but no controller registered.
161
+ Either none of the listed classes carries @Controller, or the files were
162
+ compiled with decorators stripped. Nothing would answer, so this is fatal.`);
137
163
  }
138
164
  let config;
139
165
  try {
140
166
  config = loadConfig(process.env);
141
167
  } catch (e) {
142
168
  if (e instanceof BootRefused) {
143
- die(
144
- `${e.message}
169
+ die(`${e.message}
145
170
 
146
171
  Put them in a .env beside package.json, or export them. A local stack
147
- (docker compose up) publishes both.`
148
- );
172
+ (docker compose up) publishes both.`);
149
173
  }
150
174
  throw e;
151
175
  }
152
- const app = await createApp({ config, controllers, schemas: await importSchemas(root) });
176
+ const app = await createApp({
177
+ config,
178
+ controllers,
179
+ schemas: await importSchemas(root)
180
+ });
153
181
  if (command === "routes") {
154
182
  for (const route of app.routes) console.log(route.id);
155
183
  await app.shutdown();
156
184
  return;
157
185
  }
158
- Bun.serve({ port: config.port, idleTimeout: 60, fetch: app.handle });
186
+ Bun.serve({
187
+ port: config.port,
188
+ idleTimeout: 60,
189
+ fetch: app.handle
190
+ });
159
191
  console.log(`palbase-backend listening on http://localhost:${config.port}`);
160
- console.log(` ${app.routes.length} endpoint(s) from ${files.length} controller file(s)`);
192
+ console.log(` ${app.routes.length} endpoint(s) from ${files.length} module file(s)`);
161
193
  for (const route of app.routes) console.log(` ${route.id}`);
162
- for (const signal of ["SIGTERM", "SIGINT"]) {
194
+ for (const signal of [
195
+ "SIGTERM",
196
+ "SIGINT"
197
+ ]) {
163
198
  process.on(signal, () => {
164
199
  void app.shutdown().finally(() => process.exit(0));
165
200
  });
166
201
  }
167
202
  }
203
+ __name(main, "main");
168
204
  main().catch((e) => {
169
205
  console.error(e instanceof Error ? e.message : e);
170
206
  process.exit(1);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/palbase-backend.ts"],"sourcesContent":["#!/usr/bin/env bun\n/**\n * palbase-backend — run this project's backend.\n *\n * npm run dev → palbase-backend dev (reloads on change)\n * npm start → palbase-backend serve\n *\n * There is no scaffolding step and no server file to write. The project IS the\n * backend: every `controllers/*.controller.ts` is imported, which is what\n * registers it, and the engine is built around whatever registered.\n *\n * It is the same engine the deployed runtime builds — not a development\n * stand-in. A dev server that is a different program from the production one is\n * a source of \"works locally\" reports, and this one has no second implementation\n * to disagree with.\n */\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport { createApp, loadConfig, BootRefused } from \"../engine/index.js\";\nimport { getRegisteredControllers } from \"../decorators/controller.js\";\n\nconst USAGE = `palbase-backend — run this project's backend\n\n palbase-backend serve start the backend\n palbase-backend dev start it and reload on change\n palbase-backend routes print the route table and exit\n\nConfiguration comes from the environment (a .env beside package.json is read):\n\n DATABASE_URL required — the stack's Postgres\n AUTH_JWKS_URL required — where your stack publishes its signing keys\n MODULE_BASE_URL where Documents/Storage/Notifications/Flags/Realtime live\n PALBASE_ANON_KEY publishable key, sent on module calls\n PALBASE_SERVICE_ROLE_KEY secret key, for privileged module calls\n PORT default 3000\n`;\n\nfunction die(message: string): never {\n console.error(message);\n process.exit(1);\n}\n\n/** Read a `.env` beside the project, without adding a dependency for it. */\nasync function loadDotEnv(root: string): Promise<void> {\n const file = Bun.file(join(root, \".env\"));\n if (!(await file.exists())) return;\n for (const raw of (await file.text()).split(\"\\n\")) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const eq = line.indexOf(\"=\");\n if (eq < 1) continue;\n const key = line.slice(0, eq).trim();\n // The environment wins: an exported value is the operator being explicit,\n // and a file quietly overriding it is how a \"why is it still pointing at\n // the old database\" hour begins.\n if (process.env[key] !== undefined) continue;\n let value = line.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n process.env[key] = value;\n }\n}\n\n/** Every `*.controller.ts` under `controllers/`, sorted, recursively. */\nasync function findControllers(root: string): Promise<string[]> {\n const dir = join(root, \"controllers\");\n try {\n if (!(await stat(dir)).isDirectory()) return [];\n } catch {\n return [];\n }\n const out: string[] = [];\n const walk = async (d: string): Promise<void> => {\n for (const entry of await readdir(d, { withFileTypes: true })) {\n const full = join(d, entry.name);\n if (entry.isDirectory()) await walk(full);\n else if (/\\.controller\\.(ts|js|mts|mjs)$/.test(entry.name)) out.push(full);\n }\n };\n await walk(dir);\n // Sorted so route precedence is the same on every machine.\n return out.sort();\n}\n\nasync function importSchemas(root: string): Promise<unknown[]> {\n // ONE SCHEMA PER FILE, so the whole directory is the declaration. Reading a\n // single well-known file would take the first one and leave the rest of the\n // project's tables with no typed surface and no complaint.\n //\n // SORTED, because readdir order is not specified: an unsorted set would hand\n // the runtime a different answer from one boot to the next.\n let entries: string[];\n try {\n entries = (await readdir(join(root, \"db\"))).sort();\n } catch {\n // Not every project declares a database; the typed `.tables` surface is\n // simply absent then.\n return [];\n }\n const out: unknown[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".ts\") && !entry.endsWith(\".js\")) continue;\n if (entry.endsWith(\".d.ts\")) continue;\n out.push((await import(pathToFileURL(join(root, \"db\", entry)).href)).default);\n }\n return out;\n}\n\nasync function main(): Promise<void> {\n const command = process.argv[2] ?? \"serve\";\n if (command === \"--help\" || command === \"-h\" || command === \"help\") {\n console.log(USAGE);\n return;\n }\n if (![\"serve\", \"dev\", \"routes\"].includes(command)) {\n die(`palbase-backend: unknown command \"${command}\".\\n\\n${USAGE}`);\n }\n if (typeof Bun === \"undefined\") {\n die(\n \"palbase-backend needs Bun: the engine serves `fetch` natively and opens its own\\n\" +\n \"Postgres pool through Bun.sql. Install it from https://bun.sh, then re-run.\",\n );\n }\n\n // `dev` is `serve` under Bun's watcher. Re-exec rather than reimplement:\n // one code path serves, and the reload is the runtime's job, not ours.\n if (command === \"dev\" && !process.env.PALBASE_WATCHING) {\n const self = Bun.fileURLToPath(import.meta.url);\n const child = Bun.spawn([\"bun\", \"--watch\", self, \"serve\"], {\n stdio: [\"inherit\", \"inherit\", \"inherit\"],\n env: { ...process.env, PALBASE_WATCHING: \"1\" },\n });\n process.exit(await child.exited);\n }\n\n const root = resolve(process.env.PALBASE_PROJECT_DIR ?? process.cwd());\n await loadDotEnv(root);\n\n const files = await findControllers(root);\n if (files.length === 0) {\n die(\n `palbase-backend: no controllers found under ${join(root, \"controllers\")}.\\n` +\n `A backend is its controllers — add one and run again:\\n\\n` +\n ` // controllers/hello.controller.ts\\n` +\n ` import { Controller, Get } from \"@palbase/backend\";\\n` +\n ` @Controller(\"/hello\")\\n` +\n ` class HelloController {\\n` +\n ` @Get(\"\") hi(): Promise<{ ok: boolean }> { return Promise.resolve({ ok: true }); }\\n` +\n ` }\\n`,\n );\n }\n\n // Importing IS the registration — the decorator records each class as it runs.\n for (const file of files) await import(pathToFileURL(file).href);\n const controllers = getRegisteredControllers();\n if (controllers.length === 0) {\n die(\n `palbase-backend: ${files.length} controller file(s) loaded but none registered.\\n` +\n `Every one of them is missing its @Controller decorator, or the files were\\n` +\n `compiled with decorators stripped. Nothing would answer, so this is fatal.`,\n );\n }\n\n let config;\n try {\n config = loadConfig(process.env as Record<string, string | undefined>);\n } catch (e) {\n if (e instanceof BootRefused) {\n die(\n `${e.message}\\n\\n` +\n `Put them in a .env beside package.json, or export them. A local stack\\n` +\n `(docker compose up) publishes both.`,\n );\n }\n throw e;\n }\n\n const app = await createApp({ config, controllers, schemas: await importSchemas(root) });\n\n if (command === \"routes\") {\n for (const route of app.routes) console.log(route.id);\n await app.shutdown();\n return;\n }\n\n Bun.serve({ port: config.port, idleTimeout: 60, fetch: app.handle });\n console.log(`palbase-backend listening on http://localhost:${config.port}`);\n console.log(` ${app.routes.length} endpoint(s) from ${files.length} controller file(s)`);\n for (const route of app.routes) console.log(` ${route.id}`);\n\n for (const signal of [\"SIGTERM\", \"SIGINT\"] as const) {\n process.on(signal, () => {\n void app.shutdown().finally(() => process.exit(0));\n });\n }\n}\n\n// Not a top-level await: this file is also emitted in a CommonJS flavour, where\n// one is a build error. The rejection handler is the point either way — an\n// unhandled one exits 0 on some runtimes, which would report a dead backend as\n// a successful start.\nmain().catch((e: unknown) => {\n console.error(e instanceof Error ? e.message : e);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/bin/palbase-backend.ts"],"sourcesContent":["#!/usr/bin/env bun\n/**\n * palbase-backend — run this project's backend.\n *\n * npm run dev → palbase-backend dev (reloads on change)\n * npm start → palbase-backend serve\n *\n * There is no scaffolding step and no server file to write. The project IS the\n * backend: every `controllers/*.controller.ts` is imported, which is what\n * registers it, and the engine is built around whatever registered.\n *\n * It is the same engine the deployed runtime builds — not a development\n * stand-in. A dev server that is a different program from the production one is\n * a source of \"works locally\" reports, and this one has no second implementation\n * to disagree with.\n */\nimport { readdir } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport { createApp, loadConfig, BootRefused } from \"../engine/index.js\";\nimport { getRegisteredControllers } from \"../decorators/controller.js\";\n\nconst USAGE = `palbase-backend — run this project's backend\n\n palbase-backend serve start the backend\n palbase-backend dev start it and reload on change\n palbase-backend routes print the route table and exit\n\nConfiguration comes from the environment (a .env beside package.json is read):\n\n DATABASE_URL required — the stack's Postgres\n AUTH_JWKS_URL required — where your stack publishes its signing keys\n MODULE_BASE_URL where Documents/Storage/Notifications/Flags/Realtime live\n PALBASE_ANON_KEY publishable key, sent on module calls\n PALBASE_SERVICE_ROLE_KEY secret key, for privileged module calls\n PORT default 3000\n`;\n\nfunction die(message: string): never {\n console.error(message);\n process.exit(1);\n}\n\n/** Read a `.env` beside the project, without adding a dependency for it. */\nasync function loadDotEnv(root: string): Promise<void> {\n const file = Bun.file(join(root, \".env\"));\n if (!(await file.exists())) return;\n for (const raw of (await file.text()).split(\"\\n\")) {\n const line = raw.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const eq = line.indexOf(\"=\");\n if (eq < 1) continue;\n const key = line.slice(0, eq).trim();\n // The environment wins: an exported value is the operator being explicit,\n // and a file quietly overriding it is how a \"why is it still pointing at\n // the old database\" hour begins.\n if (process.env[key] !== undefined) continue;\n let value = line.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n process.env[key] = value;\n }\n}\n\n/** Every `*.controller.ts` under `controllers/`, sorted, recursively. */\n/** Directories that are never a project's source. */\nconst NEVER_WALK = new Set([\"node_modules\", \"dist\", \"build\", \".git\"]);\n\n/**\n * The project's MODULE files — the same one glob the bundlers use.\n *\n * Importing a module imports the classes it owns, so this reaches every\n * controller, service, job, hook, webhook and room the project declares, and\n * nothing it does not. It used to walk `controllers/` for `*.controller.ts`,\n * which made the directory a declaration and left `dev` seeing a different set\n * of classes than a deploy would.\n *\n * Recursive: a module lives beside the domain it owns, not in a folder this\n * file names.\n */\nasync function findModules(root: string): Promise<string[]> {\n const out: string[] = [];\n const walk = async (d: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n if (NEVER_WALK.has(entry.name) || entry.name.startsWith(\".palbase\")) continue;\n const full = join(d, entry.name);\n if (entry.isDirectory()) await walk(full);\n else if (/\\.module\\.(ts|js|mts|mjs)$/.test(entry.name)) out.push(full);\n }\n };\n await walk(root);\n // Sorted so declaration order is the same on every machine.\n return out.sort();\n}\n\nasync function importSchemas(root: string): Promise<unknown[]> {\n // ONE SCHEMA PER FILE, so the whole directory is the declaration. Reading a\n // single well-known file would take the first one and leave the rest of the\n // project's tables with no typed surface and no complaint.\n //\n // SORTED, because readdir order is not specified: an unsorted set would hand\n // the runtime a different answer from one boot to the next.\n let entries: string[];\n try {\n entries = (await readdir(join(root, \"db\"))).sort();\n } catch {\n // Not every project declares a database; the typed `.tables` surface is\n // simply absent then.\n return [];\n }\n const out: unknown[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".ts\") && !entry.endsWith(\".js\")) continue;\n if (entry.endsWith(\".d.ts\")) continue;\n out.push((await import(pathToFileURL(join(root, \"db\", entry)).href)).default);\n }\n return out;\n}\n\nasync function main(): Promise<void> {\n const command = process.argv[2] ?? \"serve\";\n if (command === \"--help\" || command === \"-h\" || command === \"help\") {\n console.log(USAGE);\n return;\n }\n if (![\"serve\", \"dev\", \"routes\"].includes(command)) {\n die(`palbase-backend: unknown command \"${command}\".\\n\\n${USAGE}`);\n }\n if (typeof Bun === \"undefined\") {\n die(\n \"palbase-backend needs Bun: the engine serves `fetch` natively and opens its own\\n\" +\n \"Postgres pool through Bun.sql. Install it from https://bun.sh, then re-run.\",\n );\n }\n\n // `dev` is `serve` under Bun's watcher. Re-exec rather than reimplement:\n // one code path serves, and the reload is the runtime's job, not ours.\n if (command === \"dev\" && !process.env.PALBASE_WATCHING) {\n const self = Bun.fileURLToPath(import.meta.url);\n const child = Bun.spawn([\"bun\", \"--watch\", self, \"serve\"], {\n stdio: [\"inherit\", \"inherit\", \"inherit\"],\n env: { ...process.env, PALBASE_WATCHING: \"1\" },\n });\n process.exit(await child.exited);\n }\n\n const root = resolve(process.env.PALBASE_PROJECT_DIR ?? process.cwd());\n await loadDotEnv(root);\n\n const files = await findModules(root);\n if (files.length === 0) {\n die(\n `palbase-backend: no *.module.ts under ${root}.\\n` +\n `A module is what says which classes exist, who owns them and what they may\\n` +\n `reach — and it is the only place that says it. Add one and run again:\\n\\n` +\n ` // todos.module.ts\\n` +\n ` import { Module, type Token } from \"@palbase/backend\";\\n` +\n ` import { TodosController } from \"./controllers/todos.controller.ts\";\\n` +\n ` @Module({ controllers: [TodosController as Token] })\\n` +\n ` export class TodosModule {}\\n`,\n );\n }\n\n // Importing IS the registration — for the module AND for everything it owns,\n // because a module imports the classes it lists.\n for (const file of files) await import(pathToFileURL(file).href);\n const controllers = getRegisteredControllers();\n if (controllers.length === 0) {\n die(\n `palbase-backend: ${files.length} module file(s) loaded but no controller registered.\\n` +\n `Either none of the listed classes carries @Controller, or the files were\\n` +\n `compiled with decorators stripped. Nothing would answer, so this is fatal.`,\n );\n }\n\n let config;\n try {\n config = loadConfig(process.env as Record<string, string | undefined>);\n } catch (e) {\n if (e instanceof BootRefused) {\n die(\n `${e.message}\\n\\n` +\n `Put them in a .env beside package.json, or export them. A local stack\\n` +\n `(docker compose up) publishes both.`,\n );\n }\n throw e;\n }\n\n const app = await createApp({ config, controllers, schemas: await importSchemas(root) });\n\n if (command === \"routes\") {\n for (const route of app.routes) console.log(route.id);\n await app.shutdown();\n return;\n }\n\n Bun.serve({ port: config.port, idleTimeout: 60, fetch: app.handle });\n console.log(`palbase-backend listening on http://localhost:${config.port}`);\n console.log(` ${app.routes.length} endpoint(s) from ${files.length} module file(s)`);\n for (const route of app.routes) console.log(` ${route.id}`);\n\n for (const signal of [\"SIGTERM\", \"SIGINT\"] as const) {\n process.on(signal, () => {\n void app.shutdown().finally(() => process.exit(0));\n });\n }\n}\n\n// Not a top-level await: this file is also emitted in a CommonJS flavour, where\n// one is a build error. The rejection handler is the point either way — an\n// unhandled one exits 0 on some runtimes, which would report a dead backend as\n// a successful start.\nmain().catch((e: unknown) => {\n console.error(e instanceof Error ? e.message : e);\n process.exit(1);\n});\n"],"mappings":"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","names":["readdir","join","resolve","pathToFileURL","USAGE","die","message","console","error","process","exit","loadDotEnv","root","file","Bun","join","exists","raw","text","split","line","trim","startsWith","eq","indexOf","key","slice","env","undefined","value","endsWith","NEVER_WALK","Set","findModules","out","walk","d","entries","readdir","withFileTypes","entry","has","name","full","isDirectory","test","push","sort","importSchemas","pathToFileURL","href","default","main","command","argv","log","includes","PALBASE_WATCHING","self","fileURLToPath","url","child","spawn","stdio","exited","resolve","PALBASE_PROJECT_DIR","cwd","files","length","controllers","getRegisteredControllers","config","loadConfig","e","BootRefused","app","createApp","schemas","route","routes","id","shutdown","serve","port","idleTimeout","fetch","handle","signal","on","finally","catch","Error"]}