@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.
Files changed (70) hide show
  1. package/dist/bin/palbase-backend.cjs +556 -487
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +6 -6
  4. package/dist/{chunk-L4R7WXLH.js → chunk-7WAGQ3VR.js} +4 -171
  5. package/dist/chunk-7WAGQ3VR.js.map +1 -0
  6. package/dist/{chunk-UMESJJRS.js → chunk-CS6NQ6PO.js} +2 -1
  7. package/dist/chunk-CS6NQ6PO.js.map +1 -0
  8. package/dist/{chunk-BOD3DT6D.js → chunk-EHKEMHB4.js} +560 -430
  9. package/dist/chunk-EHKEMHB4.js.map +1 -0
  10. package/dist/{chunk-PRH45NZU.js → chunk-FFO36MQQ.js} +2 -45
  11. package/dist/chunk-FFO36MQQ.js.map +1 -0
  12. package/dist/{chunk-P7MGSAFT.js → chunk-LFUNRWUE.js} +1 -40
  13. package/dist/chunk-LFUNRWUE.js.map +1 -0
  14. package/dist/{chunk-RZLY4BOY.js → chunk-PDD55QWN.js} +2 -2
  15. package/dist/{chunk-YO5GYM73.js → chunk-X7UR3VXA.js} +5 -6
  16. package/dist/chunk-X7UR3VXA.js.map +1 -0
  17. package/dist/{chunk-6FEHCEB7.js → chunk-YANGWAIM.js} +3 -3
  18. package/dist/db/index.cjs +1 -232
  19. package/dist/db/index.cjs.map +1 -1
  20. package/dist/db/index.d.cts +3 -46
  21. package/dist/db/index.d.ts +3 -46
  22. package/dist/db/index.js +4 -12
  23. package/dist/engine/index.cjs +556 -487
  24. package/dist/engine/index.cjs.map +1 -1
  25. package/dist/engine/index.d.cts +4 -4
  26. package/dist/engine/index.d.ts +4 -4
  27. package/dist/engine/index.js +6 -6
  28. package/dist/{index-DllNjpTl.d.cts → index-CI7S0Wqv.d.cts} +61 -8
  29. package/dist/{endpoint-BI0yGuEL.d.ts → index-CUy50OLU.d.ts} +6 -82
  30. package/dist/{endpoint-DaGnjt42.d.cts → index-DRx880KY.d.cts} +6 -82
  31. package/dist/{index-E8Sd6NFy.d.ts → index-Ogi30dbt.d.ts} +61 -8
  32. package/dist/index.cjs +5 -237
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +6 -7
  35. package/dist/index.d.ts +6 -7
  36. package/dist/index.js +7 -15
  37. package/dist/index.js.map +1 -1
  38. package/dist/openapi/index.cjs +1 -0
  39. package/dist/openapi/index.cjs.map +1 -1
  40. package/dist/openapi/index.d.cts +3 -3
  41. package/dist/openapi/index.d.ts +3 -3
  42. package/dist/openapi/index.js +2 -2
  43. package/dist/{registry-BnKvIyve.d.cts → registry-C7UCkQf0.d.cts} +1 -1
  44. package/dist/{registry-zDCj0eOU.d.ts → registry-DJcvbomD.d.ts} +1 -1
  45. package/dist/test/index.cjs +3 -11
  46. package/dist/test/index.cjs.map +1 -1
  47. package/dist/test/index.d.cts +2 -2
  48. package/dist/test/index.d.ts +2 -2
  49. package/dist/test/index.js +2 -9
  50. package/dist/test/index.js.map +1 -1
  51. package/docs/README.md +1 -1
  52. package/docs/database.md +84 -67
  53. package/docs/examples/database-dx.ts +12 -17
  54. package/docs/llms-full.txt +82 -65
  55. package/package.json +1 -1
  56. package/stager/inferred_returns.js +153 -0
  57. package/stager/return_types.js +9 -4
  58. package/stager/stage.js +3 -1
  59. package/template/AGENTS.md +5 -5
  60. package/template/package.json +1 -1
  61. package/dist/chunk-BOD3DT6D.js.map +0 -1
  62. package/dist/chunk-L4R7WXLH.js.map +0 -1
  63. package/dist/chunk-P7MGSAFT.js.map +0 -1
  64. package/dist/chunk-PRH45NZU.js.map +0 -1
  65. package/dist/chunk-UMESJJRS.js.map +0 -1
  66. package/dist/chunk-YO5GYM73.js.map +0 -1
  67. package/docs/examples/check-query-contracts.ts +0 -5
  68. package/docs/examples/database-dx.contract.json +0 -65
  69. /package/dist/{chunk-RZLY4BOY.js.map → chunk-PDD55QWN.js.map} +0 -0
  70. /package/dist/{chunk-6FEHCEB7.js.map → chunk-YANGWAIM.js.map} +0 -0
@@ -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"), rel);
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 {
@@ -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 the body through a named schema, name the 200 shape as the return type, turn a missing row into a status | imports `Database` / `Storage` / `Cache` · holds business rules · stores per-request state on the instance |
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`. The deploy REFUSES it; name a zod schema.
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 inside a test need the extension (`./note.service.ts`); this
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".
@@ -9,7 +9,7 @@
9
9
  "typecheck": "tsc --noEmit"
10
10
  },
11
11
  "dependencies": {
12
- "@palbase/backend": "^34.0.0",
12
+ "@palbase/backend": "^36.0.0",
13
13
  "reflect-metadata": "^0.2.2"
14
14
  },
15
15
  "engines": {