@palbase/backend 35.0.0 → 36.0.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 +556 -487
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +6 -6
- package/dist/{chunk-L4R7WXLH.js → chunk-7WAGQ3VR.js} +4 -171
- package/dist/chunk-7WAGQ3VR.js.map +1 -0
- package/dist/{chunk-UMESJJRS.js → chunk-CS6NQ6PO.js} +2 -1
- package/dist/chunk-CS6NQ6PO.js.map +1 -0
- package/dist/{chunk-BOD3DT6D.js → chunk-EHKEMHB4.js} +560 -430
- package/dist/chunk-EHKEMHB4.js.map +1 -0
- package/dist/{chunk-PRH45NZU.js → chunk-FFO36MQQ.js} +2 -45
- package/dist/chunk-FFO36MQQ.js.map +1 -0
- package/dist/{chunk-P7MGSAFT.js → chunk-LFUNRWUE.js} +1 -40
- package/dist/chunk-LFUNRWUE.js.map +1 -0
- package/dist/{chunk-RZLY4BOY.js → chunk-PDD55QWN.js} +2 -2
- package/dist/{chunk-YO5GYM73.js → chunk-X7UR3VXA.js} +5 -6
- package/dist/chunk-X7UR3VXA.js.map +1 -0
- package/dist/{chunk-6FEHCEB7.js → chunk-YANGWAIM.js} +3 -3
- package/dist/db/index.cjs +1 -232
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +3 -46
- package/dist/db/index.d.ts +3 -46
- package/dist/db/index.js +4 -12
- package/dist/engine/index.cjs +556 -487
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +4 -4
- package/dist/engine/index.d.ts +4 -4
- package/dist/engine/index.js +6 -6
- package/dist/{index-DllNjpTl.d.cts → index-CI7S0Wqv.d.cts} +61 -8
- package/dist/{endpoint-BI0yGuEL.d.ts → index-CUy50OLU.d.ts} +6 -82
- package/dist/{endpoint-DaGnjt42.d.cts → index-DRx880KY.d.cts} +6 -82
- package/dist/{index-E8Sd6NFy.d.ts → index-Ogi30dbt.d.ts} +61 -8
- package/dist/index.cjs +5 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -7
- package/dist/index.d.ts +6 -7
- package/dist/index.js +7 -15
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +1 -0
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +3 -3
- package/dist/openapi/index.d.ts +3 -3
- package/dist/openapi/index.js +2 -2
- package/dist/{registry-BnKvIyve.d.cts → registry-C7UCkQf0.d.cts} +1 -1
- package/dist/{registry-zDCj0eOU.d.ts → registry-DJcvbomD.d.ts} +1 -1
- package/dist/test/index.cjs +3 -11
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +2 -2
- package/dist/test/index.d.ts +2 -2
- package/dist/test/index.js +2 -9
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +84 -67
- package/docs/examples/database-dx.ts +12 -17
- package/docs/llms-full.txt +82 -65
- package/package.json +1 -1
- package/stager/inferred_returns.js +153 -0
- package/stager/return_types.js +9 -4
- package/stager/stage.js +3 -1
- package/template/AGENTS.md +5 -5
- package/template/package.json +1 -1
- package/dist/chunk-BOD3DT6D.js.map +0 -1
- package/dist/chunk-L4R7WXLH.js.map +0 -1
- package/dist/chunk-P7MGSAFT.js.map +0 -1
- package/dist/chunk-PRH45NZU.js.map +0 -1
- package/dist/chunk-UMESJJRS.js.map +0 -1
- package/dist/chunk-YO5GYM73.js.map +0 -1
- package/docs/examples/check-query-contracts.ts +0 -5
- package/docs/examples/database-dx.contract.json +0 -65
- /package/dist/{chunk-RZLY4BOY.js.map → chunk-PDD55QWN.js.map} +0 -0
- /package/dist/{chunk-6FEHCEB7.js.map → chunk-YANGWAIM.js.map} +0 -0
package/stager/return_types.js
CHANGED
|
@@ -80,7 +80,7 @@ const RETURN_BUFFER_SYMBOL_KEY = 'palbase.backend.returnBuffer';
|
|
|
80
80
|
* - imports: local-binding-name → module-specifier (for the injector's import)
|
|
81
81
|
* Throws ReturnTypeError on an un-resolvable/disallowed return type.
|
|
82
82
|
*/
|
|
83
|
-
function readReturnTypes(sourceText, fileLabel) {
|
|
83
|
+
function readReturnTypes(sourceText, fileLabel, inferReturn) {
|
|
84
84
|
const tsapi = loadTS();
|
|
85
85
|
const sf = tsapi.createSourceFile(
|
|
86
86
|
fileLabel || 'controller.ts',
|
|
@@ -249,6 +249,11 @@ function readReturnTypes(sourceText, fileLabel) {
|
|
|
249
249
|
// silent gap @Returns had (codegen would emit an untyped struct), so it's a
|
|
250
250
|
// HARD error: the author must say what the route returns.
|
|
251
251
|
if (!m.type) {
|
|
252
|
+
if (inferReturn) {
|
|
253
|
+
const expression = inferReturn(fileLabel, className, fnName);
|
|
254
|
+
if (expression !== null) methods.push({ fnName, expression });
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
252
257
|
throw err(
|
|
253
258
|
fnName,
|
|
254
259
|
'route method has no return type — annotate it (e.g. `: Promise<TodoSchema>`, ' +
|
|
@@ -326,7 +331,7 @@ function buildInjection(parsed) {
|
|
|
326
331
|
lines.push(' __ctor[__RBUF][fn] = schema;');
|
|
327
332
|
lines.push(' };');
|
|
328
333
|
for (const m of parsed.methods) {
|
|
329
|
-
const expr = m.isArray ? `z.array(${m.typeName})` : m.typeName;
|
|
334
|
+
const expr = m.expression ?? (m.isArray ? `z.array(${m.typeName})` : m.typeName);
|
|
330
335
|
lines.push(` __bind(${JSON.stringify(m.fnName)}, ${expr});`);
|
|
331
336
|
}
|
|
332
337
|
lines.push('})();');
|
|
@@ -340,8 +345,8 @@ function buildInjection(parsed) {
|
|
|
340
345
|
* add the import). Pure string transform — the caller writes the result to the
|
|
341
346
|
* file esbuild will bundle.
|
|
342
347
|
*/
|
|
343
|
-
function injectReturnBindings(sourceText, fileLabel) {
|
|
344
|
-
const parsed = readReturnTypes(sourceText, fileLabel);
|
|
348
|
+
function injectReturnBindings(sourceText, fileLabel, inferReturn) {
|
|
349
|
+
const parsed = readReturnTypes(sourceText, fileLabel, inferReturn);
|
|
345
350
|
const snippet = buildInjection(parsed);
|
|
346
351
|
if (!snippet) return sourceText;
|
|
347
352
|
let out = sourceText;
|
package/stager/stage.js
CHANGED
|
@@ -21,6 +21,7 @@ const path = require("node:path");
|
|
|
21
21
|
|
|
22
22
|
const generics = require("./generics.js");
|
|
23
23
|
const returnTypes = require("./return_types.js");
|
|
24
|
+
const { createReturnInference } = require("./inferred_returns.js");
|
|
24
25
|
const throwAnalysis = require("./throw_analysis.js");
|
|
25
26
|
|
|
26
27
|
/**
|
|
@@ -103,6 +104,7 @@ function stageControllers(srcDir, stageDir, projectRoot) {
|
|
|
103
104
|
// normally lives. `projectRoot` is the third argument precisely so a check
|
|
104
105
|
// can be wider than the staging copy.
|
|
105
106
|
const examined = generics.assertNoGenericDepsInTree(projectRoot);
|
|
107
|
+
const inferReturn = createReturnInference(projectRoot);
|
|
106
108
|
|
|
107
109
|
let injected = 0;
|
|
108
110
|
for (const file of walk(srcDir)) {
|
|
@@ -110,7 +112,7 @@ function stageControllers(srcDir, stageDir, projectRoot) {
|
|
|
110
112
|
const dest = path.join(stageDir, rel);
|
|
111
113
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
112
114
|
if (/\.controller\.(c?ts|tsx)$/i.test(path.basename(file))) {
|
|
113
|
-
let out = returnTypes.injectReturnBindings(fs.readFileSync(file, "utf8"),
|
|
115
|
+
let out = returnTypes.injectReturnBindings(fs.readFileSync(file, "utf8"), file, inferReturn);
|
|
114
116
|
out = throwAnalysis.injectThrowBindings(out, file, {
|
|
115
117
|
readFile: (p) => {
|
|
116
118
|
try {
|
package/template/AGENTS.md
CHANGED
|
@@ -6,7 +6,6 @@ router to register with — a `@Module` says what exists, who owns it and what i
|
|
|
6
6
|
may reach, and a class no module lists does not exist.
|
|
7
7
|
|
|
8
8
|
Everything comes from one package:
|
|
9
|
-
|
|
10
9
|
```ts
|
|
11
10
|
import { Controller, Get, Post, Body, Param, User, z, Database, NotFound } from "@palbase/backend";
|
|
12
11
|
```
|
|
@@ -24,7 +23,7 @@ agents). This file does not repeat it; it says what the code should LOOK like.
|
|
|
24
23
|
|
|
25
24
|
| Layer | DOES | NEVER |
|
|
26
25
|
|---|---|---|
|
|
27
|
-
| `modules/<domain>/<name>.controller.ts` | HTTP only: validate
|
|
26
|
+
| `modules/<domain>/<name>.controller.ts` | HTTP only: validate input, return the typed service result, turn a missing row into a status | imports `Database` / `Storage` / `Cache` · holds business rules · stores per-request state on the instance |
|
|
28
27
|
| `modules/<domain>/<name>.service.ts` | the decisions: which rows, whose, in what order; throws the error classes | knows about HTTP (no `req`, no `res`) · reaches for a singleton itself — it takes its dependency through the constructor |
|
|
29
28
|
| `modules/<domain>/dto/<endpoint>.ts` | zod schemas, exported twice under one name: a VALUE and a same-named `z.infer` TYPE | holds logic |
|
|
30
29
|
| `db/public.ts` | IS the database: tables, columns, RLS policies | produces migration files — there are none |
|
|
@@ -84,7 +83,9 @@ wrong in this runtime:
|
|
|
84
83
|
- **Hand-built responses** — no `JSON.stringify`, no `new Response(...)`; the 200
|
|
85
84
|
body IS the schema your return type names.
|
|
86
85
|
- **An inline return type** — `Promise<{ ok: boolean }>`, a union, or a bare
|
|
87
|
-
`interface`.
|
|
86
|
+
`interface`. Omit it for typed CRUD: the build infers the validator and client contract.
|
|
87
|
+
For unknown JSON, recursive values or classes, name a Zod schema; never use `any`.
|
|
88
|
+
Use ordinary CRUD; core owns pool/queue settings.
|
|
88
89
|
|
|
89
90
|
**A controller is exported by NAME, and no file is default-exported.** Its module imports
|
|
90
91
|
it (`import { NotesController } from "./notes.controller"`) to list it in `controllers`;
|
|
@@ -186,8 +187,7 @@ process-wide state. For a stand-in covering the whole database rather than one
|
|
|
186
187
|
table, use `fakeDatabase()` from `@palbase/backend/test`; it answers from memory
|
|
187
188
|
and enforces no RLS, constraints or unique violations.
|
|
188
189
|
|
|
189
|
-
Relative imports
|
|
190
|
-
scaffold's `tsconfig.json` allows it.
|
|
190
|
+
Relative test imports need the extension (`./note.service.ts`); the scaffold allows it.
|
|
191
191
|
|
|
192
192
|
`npm test` answers "is the logic right". It is not the deploy's own validation —
|
|
193
193
|
decorators, return types, SDK major — which answers "would this ship".
|