@palbase/backend 25.0.4 → 27.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 +2622 -1012
- 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-CGNN2PUH.js +213 -0
- package/dist/chunk-CGNN2PUH.js.map +1 -0
- package/dist/chunk-DRZFQRJI.js +370 -0
- package/dist/chunk-DRZFQRJI.js.map +1 -0
- package/dist/chunk-GYK6QYS4.js +708 -0
- package/dist/chunk-GYK6QYS4.js.map +1 -0
- package/dist/chunk-I3C4PFIW.js +930 -0
- package/dist/chunk-I3C4PFIW.js.map +1 -0
- package/dist/{chunk-AILPKEK5.js → chunk-OO7R25AI.js} +1433 -563
- package/dist/chunk-OO7R25AI.js.map +1 -0
- package/dist/chunk-TS4U7NBD.js +885 -0
- package/dist/chunk-TS4U7NBD.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/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 +754 -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 +2562 -981
- 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-BrvvxSpn.d.ts +4844 -0
- package/dist/index-Bve7BBTL.d.cts +4844 -0
- package/dist/{index-CUomTA3e.d.ts → index-NuzRCuxe.d.ts} +171 -296
- package/dist/{index-ClpDeSos.d.cts → index-VtToZmUm.d.cts} +171 -296
- package/dist/index.cjs +2694 -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-B0eyOF9x.d.ts} +1 -1
- package/dist/{registry-CC0WBQq6.d.cts → registry-Bk9_rbNd.d.cts} +1 -1
- package/dist/stack.cjs.map +1 -1
- package/dist/test/index.cjs +705 -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 +472 -124
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +34 -18
- package/docs/auth.md +1 -1
- package/docs/background.md +2 -2
- package/docs/database.md +221 -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 +402 -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 -70
- 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-AILPKEK5.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-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 -74
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-VXPNPVAG.js.map} +0 -0
- /package/template/{models/notes → modules/notes/dto}/create.ts +0 -0
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
|
|
4
|
-
import { NoteService } from "./note.service.ts";
|
|
5
|
-
|
|
6
|
-
// WHY THIS TEST NEEDS NO DATABASE
|
|
7
|
-
//
|
|
8
|
-
// `NoteService` is handed the table it works on rather than reaching for the
|
|
9
|
-
// singleton itself. That constructor is the seam: a stand-in goes in here, and
|
|
10
|
-
// the logic — which rows, whose, in what order — is exercised without a
|
|
11
|
-
// database. Test your own services the same way.
|
|
12
|
-
//
|
|
13
|
-
// When you want the whole database surface instead of one table, `fakeDatabase()`
|
|
14
|
-
// from `@palbase/backend/test` is the stand-in.
|
|
15
|
-
//
|
|
16
|
-
// Node's ESM resolver wants the extension on a relative import inside a test
|
|
17
|
-
// (`./note.service.ts`); this scaffold's `tsconfig.json` allows it.
|
|
18
|
-
|
|
19
|
-
test("list asks only for the caller's notes", async () => {
|
|
20
|
-
const seen: unknown[] = [];
|
|
21
|
-
const notes = {
|
|
22
|
-
findMany: async (where: unknown) => {
|
|
23
|
-
seen.push(where);
|
|
24
|
-
return [];
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
await new NoteService(notes as never).list("u_1");
|
|
29
|
-
|
|
30
|
-
assert.deepEqual(seen, [{ user_id: "u_1" }]);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("create writes ownership from the argument, never from the body", async () => {
|
|
34
|
-
const written: unknown[] = [];
|
|
35
|
-
const notes = {
|
|
36
|
-
insert: async (row: unknown) => {
|
|
37
|
-
written.push(row);
|
|
38
|
-
return row;
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
await new NoteService(notes as never).create("u_1", "hello");
|
|
43
|
-
|
|
44
|
-
assert.deepEqual(written, [{ user_id: "u_1", body: "hello" }]);
|
|
45
|
-
});
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Database } from "@palbase/backend";
|
|
2
|
-
import type { Tables } from "@palbase/backend/env";
|
|
3
|
-
|
|
4
|
-
// A SERVICE is where the logic lives. It is a plain class — no decorator, no DI
|
|
5
|
-
// container, nothing to register. What makes the layer real is the two lines at
|
|
6
|
-
// the bottom of this file, not the folder name.
|
|
7
|
-
//
|
|
8
|
-
// THE SEAM IS THE CONSTRUCTOR. The class is handed the table it works on rather
|
|
9
|
-
// than reaching for the singleton itself, so a test constructs it with a
|
|
10
|
-
// stand-in and never needs a database:
|
|
11
|
-
//
|
|
12
|
-
// const svc = new NoteService(fakeNotesTable);
|
|
13
|
-
// assert.deepEqual(await svc.list("u_1"), []);
|
|
14
|
-
//
|
|
15
|
-
// The module then wires the real one ONCE, on the last line, and that instance
|
|
16
|
-
// is what a controller imports. That module-level singleton is also the
|
|
17
|
-
// supported way to hold a dependency ANYWHERE in this runtime: a controller,
|
|
18
|
-
// hook, job or webhook is constructed with no arguments, and one that declares
|
|
19
|
-
// a constructor parameter is refused at build with the class named — there is
|
|
20
|
-
// no injector to fill it, so the field would simply be `undefined` in
|
|
21
|
-
// production.
|
|
22
|
-
//
|
|
23
|
-
// `Database.tables.notes` is typed from `db/public.ts` through the generated
|
|
24
|
-
// `palbase-env.d.ts`, which `palbase build` writes. Before the first build that
|
|
25
|
-
// file does not exist yet and the table is unknown to the type checker; build
|
|
26
|
-
// once and the whole surface below is typed with no import and no generic.
|
|
27
|
-
|
|
28
|
-
/** One row of `notes`, exactly as `db/public.ts` declares it. */
|
|
29
|
-
export type Note = Tables["notes"]["row"];
|
|
30
|
-
|
|
31
|
-
/** The typed surface of one table: `insert`, `update`, `delete`, `findById`,
|
|
32
|
-
* `findMany`. Naming it here is what keeps the seam ONE table wide — a test
|
|
33
|
-
* fake implements five methods, not the whole `Database`. */
|
|
34
|
-
type NotesTable = typeof Database.tables.notes;
|
|
35
|
-
|
|
36
|
-
export class NoteService {
|
|
37
|
-
private readonly notes: NotesTable;
|
|
38
|
-
|
|
39
|
-
// Assigned in the BODY, never as a parameter property (`constructor(private
|
|
40
|
-
// notes: NotesTable)`). `npm test` runs Node's type-stripping test runner,
|
|
41
|
-
// which refuses parameter properties — and refuses them for the whole FILE,
|
|
42
|
-
// so one of them anywhere in a test's import graph reads like a dozen broken
|
|
43
|
-
// tests and is one keyword.
|
|
44
|
-
constructor(notes: NotesTable) {
|
|
45
|
-
this.notes = notes;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** The caller's notes. The filter is written out even though the table's RLS
|
|
49
|
-
* policy already scopes the read to `auth.uid()`: the policy is the backstop
|
|
50
|
-
* that holds when a query forgets, not a reason to stop writing the query. */
|
|
51
|
-
list(userId: string): Promise<Note[]> {
|
|
52
|
-
return this.notes.findMany({ user_id: userId });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** `user_id` is `notNull` with no default, so ownership is written here —
|
|
56
|
-
* it is not something the request body may carry. */
|
|
57
|
-
create(userId: string, body: string): Promise<Note> {
|
|
58
|
-
return this.notes.insert({ user_id: userId, body });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** No `userId` argument, and that is not an oversight: another user's note is
|
|
62
|
-
* invisible to this read, so it comes back `null` exactly as a missing id
|
|
63
|
-
* does. Postgres enforces it, not this method. */
|
|
64
|
-
get(id: string): Promise<Note | null> {
|
|
65
|
-
return this.notes.findById(id);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
remove(id: string): Promise<void> {
|
|
69
|
-
return this.notes.delete(id);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** The wired instance. Controllers import THIS, never the class. */
|
|
74
|
-
export const noteService = new NoteService(Database.tables.notes);
|
|
File without changes
|
|
File without changes
|