@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.
- package/dist/bin/palbase-backend.cjs +2432 -1039
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +87 -51
- package/dist/bin/palbase-backend.js.map +1 -1
- package/dist/chunk-BQN723PL.js +930 -0
- package/dist/chunk-BQN723PL.js.map +1 -0
- package/dist/chunk-CGNN2PUH.js +213 -0
- package/dist/chunk-CGNN2PUH.js.map +1 -0
- package/dist/{chunk-VDF2T4AS.js → chunk-EB3TUX5J.js} +1228 -591
- package/dist/chunk-EB3TUX5J.js.map +1 -0
- package/dist/chunk-JVZQCC77.js +728 -0
- package/dist/chunk-JVZQCC77.js.map +1 -0
- package/dist/chunk-OZKSM3JW.js +370 -0
- package/dist/chunk-OZKSM3JW.js.map +1 -0
- package/dist/{chunk-YOY5DFQS.js → chunk-TWX6JTGJ.js} +76 -34
- package/dist/{chunk-YOY5DFQS.js.map → chunk-TWX6JTGJ.js.map} +1 -1
- package/dist/{chunk-35PNTIRN.js → chunk-VVMJEVQP.js} +63 -162
- package/dist/chunk-VVMJEVQP.js.map +1 -0
- package/dist/{chunk-7D4SUZUM.js → chunk-VXPNPVAG.js} +3 -1
- package/dist/chunk-XABHGMUT.js +885 -0
- package/dist/chunk-XABHGMUT.js.map +1 -0
- package/dist/db/env.cjs.map +1 -1
- package/dist/db/env.d.cts +2 -2
- package/dist/db/env.d.ts +2 -2
- package/dist/db/index.cjs +780 -344
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +7 -4
- package/dist/engine/index.cjs +2366 -1002
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +6 -6
- package/dist/engine/index.d.ts +6 -6
- package/dist/engine/index.js +7 -6
- package/dist/{index-CUomTA3e.d.ts → index-CAKOgAlP.d.ts} +171 -296
- package/dist/index-CgE4sVhg.d.cts +4864 -0
- package/dist/{index-ClpDeSos.d.cts → index-H-0qv5d4.d.cts} +171 -296
- package/dist/index-V7QRh1wg.d.ts +4864 -0
- package/dist/index.cjs +2720 -1169
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -19
- package/dist/index.d.ts +165 -19
- package/dist/index.js +738 -477
- package/dist/index.js.map +1 -1
- package/dist/module-Dl1KFVtc.d.cts +54 -0
- package/dist/module-Dl1KFVtc.d.ts +54 -0
- package/dist/openapi/index.cjs +1330 -484
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +4 -2
- package/dist/openapi/index.d.ts +4 -2
- package/dist/openapi/index.js +1264 -474
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-dZZ5JKYg.d.ts → registry-4EI8aaFs.d.ts} +1 -1
- package/dist/{registry-CC0WBQq6.d.cts → registry-DHsPDY0_.d.cts} +1 -1
- package/dist/stack.cjs.map +1 -1
- package/dist/test/index.cjs +732 -141
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +30 -4
- package/dist/test/index.d.ts +30 -4
- package/dist/test/index.js +490 -124
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +33 -18
- package/docs/auth.md +1 -1
- package/docs/background.md +2 -2
- package/docs/database.md +255 -50
- package/docs/endpoints.md +3 -4
- package/docs/events.md +3 -3
- package/docs/getting-started.md +1 -1
- package/docs/llms-full.txt +435 -117
- package/docs/migrations.md +2 -2
- package/docs/schema.md +19 -10
- package/docs/services.md +116 -26
- package/package.json +8 -4
- package/stager/generics.js +205 -0
- package/stager/stage.js +39 -3
- package/template/AGENTS.md +110 -72
- package/template/db/public.ts +1 -1
- package/template/{controllers → modules/health}/health.controller.ts +1 -1
- package/template/modules/health/health.module.ts +24 -0
- package/template/modules/notes/note.service.test.ts +49 -0
- package/template/modules/notes/note.service.ts +108 -0
- package/template/{controllers → modules/notes}/notes.controller.ts +17 -11
- package/template/modules/notes/notes.module.ts +37 -0
- package/template/package.json +5 -3
- package/template/scripts/test.sh +33 -0
- package/template/tsconfig.json +29 -30
- package/dist/chunk-35PNTIRN.js.map +0 -1
- package/dist/chunk-CJSKYY76.js +0 -627
- package/dist/chunk-CJSKYY76.js.map +0 -1
- package/dist/chunk-CRQKCRGF.js +0 -276
- package/dist/chunk-CRQKCRGF.js.map +0 -1
- package/dist/chunk-G4R6BTLV.js +0 -662
- package/dist/chunk-G4R6BTLV.js.map +0 -1
- package/dist/chunk-VDF2T4AS.js.map +0 -1
- package/dist/chunk-XABBC7JP.js +0 -55
- package/dist/chunk-XABBC7JP.js.map +0 -1
- package/dist/endpoint-CTEHhb7A.d.ts +0 -2386
- package/dist/endpoint-DYHMo6cC.d.cts +0 -2386
- package/dist/index-CW21M9Z3.d.ts +0 -1222
- package/dist/index-CmBK76nx.d.cts +0 -1222
- package/template/services/note.service.test.ts +0 -45
- package/template/services/note.service.ts +0 -76
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-VXPNPVAG.js.map} +0 -0
- /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-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
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-
|
|
13
|
-
import "../chunk-
|
|
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
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
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 (/\.
|
|
81
|
+
else if (/\.module\.(ts|js|mts|mjs)$/.test(entry.name)) out.push(full);
|
|
68
82
|
}
|
|
69
|
-
};
|
|
70
|
-
await walk(
|
|
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 (![
|
|
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([
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
144
|
+
const files = await findModules(root);
|
|
115
145
|
if (files.length === 0) {
|
|
116
|
-
die(
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
//
|
|
121
|
-
import {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
134
|
-
|
|
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({
|
|
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({
|
|
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}
|
|
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 [
|
|
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"]}
|