@palbase/backend 2.0.0 → 2.0.2

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/docs/llms.txt ADDED
@@ -0,0 +1,16 @@
1
+ # Palbase Backend SDK (`@palbase/backend`)
2
+
3
+ > File-based TypeScript backend SDK. Endpoints use `req` (PBRequest) + imported service singletons (`Database`, `Cache`, …). Workers/jobs/hooks/webhooks use a `ctx` object. Not Express, not Supabase Edge Functions.
4
+
5
+ ## Docs
6
+
7
+ - [README](./README.md)
8
+ - [getting-started](./getting-started.md)
9
+ - [routing](./routing.md)
10
+ - [endpoints](./endpoints.md)
11
+ - [database](./database.md)
12
+ - [schema](./schema.md)
13
+ - [services](./services.md)
14
+ - [errors](./errors.md)
15
+ - [background](./background.md)
16
+ - [events](./events.md)
@@ -0,0 +1,34 @@
1
+ # File-based routing
2
+
3
+ The path of a file under `endpoints/` plus its filename determine the route.
4
+ The filename is the HTTP method.
5
+
6
+ | File | Route |
7
+ |------|-------|
8
+ | `endpoints/hello/get.ts` | `GET /hello` |
9
+ | `endpoints/items/post.ts` | `POST /items` |
10
+ | `endpoints/posts/[id]/get.ts` | `GET /posts/:id` |
11
+ | `endpoints/posts/[id]/patch.ts` | `PATCH /posts/:id` |
12
+ | `endpoints/rooms/[id]/sessions/post.ts` | `POST /rooms/:id/sessions` |
13
+
14
+ Rules:
15
+
16
+ - The method file name is one of `get`, `post`, `put`, `patch`, `delete` (`.ts`).
17
+ - A `[segment]` directory becomes a `:segment` path param, read via `req.params.segment`.
18
+ - Each method file `export default defineEndpoint({...})` — one endpoint per file.
19
+ - There is no central router file and no manual registration. Adding a file adds a route.
20
+
21
+ ```ts
22
+ // endpoints/posts/[id]/get.ts → GET /posts/:id
23
+ import { defineEndpoint, z, Database, HttpError } from "@palbase/backend";
24
+
25
+ export default defineEndpoint({
26
+ method: "GET",
27
+ output: z.object({ id: z.string(), title: z.string() }),
28
+ handler: async (req) => {
29
+ const post = await Database.findById("posts", req.params.id!);
30
+ if (!post) throw new HttpError(404, "post_not_found", "No such post");
31
+ return { id: post.id as string, title: post.title as string };
32
+ },
33
+ });
34
+ ```
package/docs/schema.md ADDED
@@ -0,0 +1,82 @@
1
+ # Schema & typed database access
2
+
3
+ Declare your tables in `db/schema.ts` with `defineSchema`. This drives
4
+ migrations and, via `typedDatabase`, a fully-typed `.tables.*` API.
5
+
6
+ ## Defining a schema
7
+
8
+ ```ts
9
+ import {
10
+ defineSchema, table,
11
+ uuid, text, integer, boolean, timestamp, jsonb, enumType,
12
+ } from "@palbase/backend";
13
+
14
+ export default defineSchema({
15
+ rooms: table("rooms", {
16
+ id: uuid().primaryKey().defaultRandom(),
17
+ name: text().notNull(),
18
+ capacity: integer().nullable(),
19
+ is_active: boolean().default(true),
20
+ created_at: timestamp().defaultNow(),
21
+ }),
22
+ sessions: table("sessions", {
23
+ id: uuid().primaryKey().defaultRandom(),
24
+ room_id: uuid().notNull().references("rooms", "id").onDelete("cascade"),
25
+ user_id: uuid().notNull(),
26
+ data: jsonb().nullable(),
27
+ started_at: timestamp().defaultNow(),
28
+ }),
29
+ orders: table("orders", {
30
+ id: uuid().primaryKey().defaultRandom(),
31
+ status: enumType("order_status", ["pending", "paid", "shipped", "cancelled"]),
32
+ amount: integer().notNull(),
33
+ }),
34
+ });
35
+ ```
36
+
37
+ ## Column builders
38
+
39
+ | Builder | Postgres type |
40
+ |---------|---------------|
41
+ | `uuid()` | `uuid` |
42
+ | `text()` | `text` |
43
+ | `integer()` | `integer` |
44
+ | `boolean()` | `boolean` |
45
+ | `timestamp()` | `timestamptz` |
46
+ | `jsonb()` | `jsonb` |
47
+ | `enumType(name, values)` | a Postgres enum |
48
+
49
+ Chainable modifiers: `.primaryKey()`, `.notNull()` (default), `.nullable()`,
50
+ `.default(value)`, `.defaultRandom()` (uuid → `gen_random_uuid()`),
51
+ `.defaultNow()` (timestamp → `now()`), `.references(table, column)`,
52
+ `.onDelete("cascade" | "set null" | "restrict" | "no action")`.
53
+
54
+ ## Typed DB access
55
+
56
+ `typedDatabase(schema)` returns a typed facade. `insert` demands the right
57
+ columns; rows come back typed; nullable columns are `T | null`.
58
+
59
+ ```ts
60
+ import { defineEndpoint, z, typedDatabase } from "@palbase/backend";
61
+ import schema from "../../db/schema.js";
62
+
63
+ const Db = typedDatabase(schema);
64
+
65
+ export default defineEndpoint({
66
+ method: "POST",
67
+ input: z.object({ name: z.string() }),
68
+ output: z.object({ id: z.string(), name: z.string() }),
69
+ handler: async (req) => {
70
+ const room = await Db.tables.rooms.insert({ name: req.input.name });
71
+ return { id: room.id, name: room.name };
72
+ },
73
+ });
74
+ ```
75
+
76
+ Note the `.js` extension on `../../db/schema.js` even though the file is
77
+ `db/schema.ts` — this is standard ESM module resolution; you still author the
78
+ file as `.ts`.
79
+
80
+ `Db.tables.<name>` exposes `insert`, `update(id, data)`, `delete(id)`,
81
+ `findById(id)`, `findMany(query?)`, and `Db.transaction(fn)` mirrors the
82
+ untyped transaction with typed tables.
@@ -0,0 +1,105 @@
1
+ # Services
2
+
3
+ In **endpoints**, import service singletons from `@palbase/backend`. In
4
+ **workers/jobs/hooks/webhooks**, the equivalents live on `ctx` (`ctx.cache`,
5
+ `ctx.queue`, `ctx.log`, `ctx.db`).
6
+
7
+ Available singletons: `Database`, `Documents`, `Storage`, `Cache`, `Queue`,
8
+ `Log`, `Notifications`, `Flags`.
9
+
10
+ **Not available to backend handlers** (do not import them here): Realtime,
11
+ Functions, CMS, Links, Analytics, and Auth. Auth runs on the client SDK; the
12
+ others are out of scope for backend endpoints.
13
+
14
+ ## Cache
15
+
16
+ JSON-typed key/value cache.
17
+
18
+ ```ts
19
+ import { Cache } from "@palbase/backend";
20
+
21
+ await Cache.set("k", { hits: 1 }, 60); // value + TTL seconds
22
+ const v = await Cache.get<{ hits: number }>("k"); // typed, null on miss
23
+ await Cache.incr("counter");
24
+ await Cache.del("k");
25
+
26
+ // Stampede-safe read-through: only one caller across all pods runs fn.
27
+ const profile = await Cache.getOrSet("user:42", 300, async () => {
28
+ return Database.findById("users", "42");
29
+ });
30
+ ```
31
+
32
+ `getOrSet` caches whatever `fn` returns, including `null` — return a sentinel or
33
+ guard upstream if you don't want misses cached.
34
+
35
+ ## Queue
36
+
37
+ Enqueue work for a worker (see [background.md](./background.md)).
38
+
39
+ ```ts
40
+ import { Queue } from "@palbase/backend";
41
+ const { jobId } = await Queue.push("process-order", { orderId: "ord_1", amount: 1000 });
42
+ ```
43
+
44
+ ## Log
45
+
46
+ ```ts
47
+ import { Log } from "@palbase/backend";
48
+ Log.info("created order", { orderId });
49
+ Log.warn("retrying");
50
+ Log.error("failed", err);
51
+ Log.debug("detail");
52
+ ```
53
+
54
+ ## Storage
55
+
56
+ Bucket-scoped file operations.
57
+
58
+ ```ts
59
+ import { Storage } from "@palbase/backend";
60
+ const bucket = Storage.bucket("avatars");
61
+ const { data, error } = await bucket.upload("u/42.png", file);
62
+ const { data: signed } = await bucket.createSignedUrl("u/42.png", 3600);
63
+ const pub = bucket.getPublicUrl("u/42.png"); // sync, no network
64
+ await bucket.remove(["u/42.png"]);
65
+ ```
66
+
67
+ All Storage calls return `{ data, error }` — check `error` before using `data`.
68
+
69
+ ## Documents
70
+
71
+ Firestore-like document store.
72
+
73
+ ```ts
74
+ import { Documents } from "@palbase/backend";
75
+ const col = Documents.collection("rooms");
76
+ const { data: ref } = await col.add({ name: "Lobby" });
77
+ const snap = await col.where("active", "==", true).orderBy("name").limit(10).get();
78
+ const { data: doc } = await Documents.doc("rooms/abc").get();
79
+ ```
80
+
81
+ ## Notifications
82
+
83
+ ```ts
84
+ import { Notifications } from "@palbase/backend";
85
+ await Notifications.email.send({ /* PalbaseEmailSendParams */ });
86
+ await Notifications.push.send({ /* PalbasePushSendParams */ });
87
+ await Notifications.sms.send({ /* PalbaseSmsSendParams */ });
88
+ ```
89
+
90
+ ## Flags
91
+
92
+ ```ts
93
+ import { defineEndpoint, z, Flags } from "@palbase/backend";
94
+
95
+ export default defineEndpoint({
96
+ method: "GET",
97
+ auth: { required: true }, // req.user is non-null here
98
+ output: z.object({ enabled: z.boolean() }),
99
+ handler: async (req) => {
100
+ const { data: enabled } = await Flags.isEnabled("new-checkout", { userId: req.user.id });
101
+ const { data: variant } = await Flags.getVariant("button-color", { userId: req.user.id });
102
+ return { enabled: enabled ?? false };
103
+ },
104
+ });
105
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palbase/backend",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Palbase Backend SDK — defineEndpoint, context types, schema DSL",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -45,7 +45,8 @@
45
45
  }
46
46
  },
47
47
  "files": [
48
- "dist"
48
+ "dist",
49
+ "docs"
49
50
  ],
50
51
  "dependencies": {
51
52
  "@asteasolutions/zod-to-openapi": "^7.3.4",
@@ -65,6 +66,7 @@
65
66
  "build": "tsup",
66
67
  "test": "vitest run",
67
68
  "test:watch": "vitest",
68
- "typecheck": "tsc --noEmit"
69
+ "typecheck": "tsc --noEmit",
70
+ "docs:build": "node scripts/build-llms.mjs"
69
71
  }
70
72
  }