@palbase/backend 24.3.0 → 25.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 (61) hide show
  1. package/dist/bin/palbase-backend.cjs +101 -60
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +17 -13
  4. package/dist/bin/palbase-backend.js.map +1 -1
  5. package/dist/{chunk-EIXCY4SS.js → chunk-43A3KGWL.js} +80 -49
  6. package/dist/chunk-43A3KGWL.js.map +1 -0
  7. package/dist/{chunk-ERDL5VAE.js → chunk-5CMLOAEF.js} +2 -2
  8. package/dist/chunk-OEQBHE2Z.js +825 -0
  9. package/dist/chunk-OEQBHE2Z.js.map +1 -0
  10. package/dist/{chunk-7Z6MGMXQ.js → chunk-XJ2RSHEU.js} +11 -5
  11. package/dist/chunk-XJ2RSHEU.js.map +1 -0
  12. package/dist/{chunk-UWSYTUGM.js → chunk-ZQRWW37O.js} +44 -1
  13. package/dist/chunk-ZQRWW37O.js.map +1 -0
  14. package/dist/db/env.cjs.map +1 -1
  15. package/dist/db/env.d.cts +29 -13
  16. package/dist/db/env.d.ts +29 -13
  17. package/dist/db/index.cjs +212 -111
  18. package/dist/db/index.cjs.map +1 -1
  19. package/dist/db/index.d.cts +1 -1
  20. package/dist/db/index.d.ts +1 -1
  21. package/dist/db/index.js +11 -1
  22. package/dist/engine/index.cjs +87 -50
  23. package/dist/engine/index.cjs.map +1 -1
  24. package/dist/engine/index.d.cts +2 -2
  25. package/dist/engine/index.d.ts +2 -2
  26. package/dist/engine/index.js +3 -3
  27. package/dist/{index-DEneI8Mn.d.ts → index-BF1f0DfA.d.ts} +5 -2
  28. package/dist/{index-C-ALG22n.d.cts → index-CoaDN9dL.d.cts} +5 -2
  29. package/dist/{index-BTMYod_l.d.ts → index-Ct1iiB4N.d.ts} +203 -61
  30. package/dist/{index-BLAbr9ZH.d.cts → index-CwaWRhyc.d.cts} +203 -61
  31. package/dist/index.cjs +550 -297
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +122 -20
  34. package/dist/index.d.ts +122 -20
  35. package/dist/index.js +164 -217
  36. package/dist/index.js.map +1 -1
  37. package/dist/openapi/index.cjs +100 -36
  38. package/dist/openapi/index.cjs.map +1 -1
  39. package/dist/openapi/index.js +59 -2
  40. package/dist/openapi/index.js.map +1 -1
  41. package/docs/README.md +64 -31
  42. package/docs/endpoints.md +25 -28
  43. package/docs/llms-full.txt +399 -153
  44. package/docs/schema.md +272 -91
  45. package/docs/services.md +39 -4
  46. package/package.json +1 -1
  47. package/template/AGENTS.md +119 -314
  48. package/template/CLAUDE.md +13 -0
  49. package/template/controllers/notes.controller.ts +6 -13
  50. package/template/db/public.ts +38 -0
  51. package/template/models/notes/create.ts +38 -0
  52. package/template/package.json +6 -3
  53. package/template/services/note.service.test.ts +45 -0
  54. package/template/services/note.service.ts +2 -2
  55. package/dist/chunk-7Z6MGMXQ.js.map +0 -1
  56. package/dist/chunk-D5CQES25.js +0 -556
  57. package/dist/chunk-D5CQES25.js.map +0 -1
  58. package/dist/chunk-EIXCY4SS.js.map +0 -1
  59. package/dist/chunk-UWSYTUGM.js.map +0 -1
  60. package/template/db/schema.ts +0 -35
  61. /package/dist/{chunk-ERDL5VAE.js.map → chunk-5CMLOAEF.js.map} +0 -0
package/dist/db/index.cjs CHANGED
@@ -23,29 +23,39 @@ __export(db_exports, {
23
23
  EXTENSION_DEPENDENCIES: () => EXTENSION_DEPENDENCIES,
24
24
  PALBASE_EXTENSIONS: () => PALBASE_EXTENSIONS,
25
25
  PolicyBuilder: () => PolicyBuilder,
26
+ TABLE_META: () => TABLE_META,
26
27
  TxPlanError: () => TxPlanError,
27
28
  TxRefError: () => TxRefError,
28
29
  bigint: () => bigint,
29
30
  boolean: () => boolean,
30
31
  dec: () => dec,
31
32
  defineSchema: () => defineSchema,
33
+ defineTable: () => defineTable,
32
34
  enumType: () => enumType,
33
35
  inc: () => inc,
36
+ installationRef: () => installationRef,
34
37
  integer: () => integer,
35
38
  isPalbaseExtension: () => isPalbaseExtension,
36
39
  jsonb: () => jsonb,
37
40
  makeTypedDB: () => makeTypedDB,
38
41
  now: () => now,
39
42
  openai: () => openai,
43
+ ownedByUser: () => ownedByUser,
40
44
  policy: () => policy,
41
45
  raw: () => raw,
42
46
  text: () => text,
43
47
  timestamp: () => timestamp,
48
+ userRef: () => userRef,
44
49
  uuid: () => uuid,
45
50
  vector: () => vector
46
51
  });
47
52
  module.exports = __toCommonJS(db_exports);
48
53
 
54
+ // src/db/schema-json.ts
55
+ function qualifiedTableKey(schemaName, tableName) {
56
+ return schemaName === "public" ? tableName : `${schemaName}.${tableName}`;
57
+ }
58
+
49
59
  // src/db/policy.ts
50
60
  function quote(name) {
51
61
  return `"${name.replace(/"/g, '""')}"`;
@@ -140,102 +150,179 @@ function policy(name) {
140
150
  function toPolicyDef(p) {
141
151
  return p instanceof PolicyBuilder ? p._def : p;
142
152
  }
143
- function defineSchema(input) {
144
- const tables = {};
145
- for (const name of Object.keys(input.tables)) {
146
- const table = input.tables[name];
147
- if (table === void 0) continue;
148
- const policies = (table.policies ?? []).map(toPolicyDef);
149
- const rls = policies.length > 0 || table.rls !== false;
150
- const tableDef = {
151
- name,
152
- columns: table.columns,
153
- rls,
154
- policies
155
- };
156
- if (table.primaryKey !== void 0) tableDef.primaryKey = table.primaryKey;
157
- if (table.unique !== void 0) tableDef.unique = table.unique;
158
- if (table.raw !== void 0 && table.raw.length > 0) tableDef.raw = table.raw.slice();
159
- if (table.checks !== void 0 && table.checks.length > 0) tableDef.checks = table.checks.slice();
160
- if (table.indexes !== void 0 && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();
161
- if (table.search !== void 0) {
162
- const s = table.search;
163
- if (s.from !== void 0) {
164
- if (s.vector !== void 0) {
165
- throw new Error(
166
- `table ${String(name)}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`
167
- );
168
- }
169
- if (s.from.length === 0) {
170
- throw new Error(`table ${String(name)}: search.from bo\u015F olamaz`);
171
- }
172
- if (s.model === void 0) {
173
- throw new Error(
174
- `table ${String(name)}: search.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin (BYO i\xE7in eski 'vector' bi\xE7imini kullan\u0131n)`
175
- );
176
- }
177
- if (Array.isArray(s.text) && s.text.length === 0) {
178
- throw new Error(`table ${String(name)}: search.text bo\u015F dizi olamaz \u2014 FTS istemiyorsan text: false yaz\u0131n`);
153
+ var TABLE_META = /* @__PURE__ */ Symbol.for("palbase.table.meta");
154
+ function defineTable(name, input) {
155
+ if (name.trim() === "") {
156
+ throw new Error("defineTable(name, \u2026): name must not be empty");
157
+ }
158
+ const policies = (input.policies ?? []).map(toPolicyDef);
159
+ const rls = policies.length > 0 || input.rls !== false;
160
+ const def = {
161
+ name,
162
+ columns: input.columns,
163
+ rls,
164
+ policies
165
+ };
166
+ if (input.primaryKey !== void 0) def.primaryKey = input.primaryKey;
167
+ if (input.unique !== void 0) def.unique = input.unique;
168
+ if (input.raw !== void 0 && input.raw.length > 0) def.raw = input.raw.slice();
169
+ if (input.checks !== void 0 && input.checks.length > 0) def.checks = input.checks.slice();
170
+ if (input.indexes !== void 0 && input.indexes.length > 0) def.indexes = input.indexes.slice();
171
+ if (input.search !== void 0) {
172
+ const s = input.search;
173
+ if (s.from !== void 0) {
174
+ if (s.vector !== void 0) {
175
+ throw new Error(
176
+ `table ${name}: search beyan\u0131nda tek bi\xE7im kullan\u0131n \u2014 'from' (yeni) ile 'vector' (eski) birlikte olamaz`
177
+ );
178
+ }
179
+ if (s.from.length === 0) {
180
+ throw new Error(`table ${name}: search.from bo\u015F olamaz`);
181
+ }
182
+ if (s.model === void 0) {
183
+ throw new Error(
184
+ `table ${name}: search.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin (BYO i\xE7in eski 'vector' bi\xE7imini kullan\u0131n)`
185
+ );
186
+ }
187
+ if (Array.isArray(s.text) && s.text.length === 0) {
188
+ throw new Error(`table ${name}: search.text bo\u015F dizi olamaz \u2014 FTS istemiyorsan text: false yaz\u0131n`);
189
+ }
190
+ } else {
191
+ if (typeof s.text === "boolean") {
192
+ throw new Error(`table ${name}: text:${String(s.text)} yaln\u0131z yeni bi\xE7imde ('from' ile) ge\xE7erli`);
193
+ }
194
+ if (s.text === void 0 && s.vector === void 0) {
195
+ throw new Error(
196
+ `table ${name}: search beyan\u0131 bo\u015F \u2014 en az bir kol (text ya da vector) verin, yoksa alan\u0131 hi\xE7 yazmay\u0131n`
197
+ );
198
+ }
199
+ if (s.text !== void 0 && s.text.length === 0) {
200
+ throw new Error(`table ${name}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
201
+ }
202
+ const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [s.vector];
203
+ for (const leg of legs) {
204
+ if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
205
+ throw new Error(`table ${name}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
179
206
  }
180
- } else {
181
- if (typeof s.text === "boolean") {
182
- throw new Error(`table ${String(name)}: text:${String(s.text)} yaln\u0131z yeni bi\xE7imde ('from' ile) ge\xE7erli`);
207
+ if (leg.model === void 0 && leg.from !== void 0) {
208
+ throw new Error(`table ${name}: search.vector.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin`);
183
209
  }
184
- if (s.text === void 0 && s.vector === void 0) {
210
+ }
211
+ }
212
+ def.search = s;
213
+ }
214
+ if (input.memory !== void 0) {
215
+ if (input.memory.from.length === 0) {
216
+ throw new Error(`table ${name}: memory.from bo\u015F olamaz`);
217
+ }
218
+ def.memory = input.memory;
219
+ }
220
+ for (const b of Object.values(input.columns)) {
221
+ b._def.ownerTable = def;
222
+ }
223
+ const handle = { ...input.columns };
224
+ Object.defineProperty(handle, TABLE_META, { value: def, enumerable: false });
225
+ return handle;
226
+ }
227
+ var declaringSchemaOf = /* @__PURE__ */ new WeakMap();
228
+ function resolveReferences(tables, schemaName) {
229
+ for (const table of Object.values(tables)) {
230
+ for (const [colName, builder] of Object.entries(table.columns)) {
231
+ const def = builder._def;
232
+ if (def.selfRefColumn !== void 0) {
233
+ if (!(def.selfRefColumn in table.columns)) {
185
234
  throw new Error(
186
- `table ${String(name)}: search beyan\u0131 bo\u015F \u2014 en az bir kol (text ya da vector) verin, yoksa alan\u0131 hi\xE7 yazmay\u0131n`
235
+ `table "${table.name}" column "${colName}": selfReferences("${def.selfRefColumn}") \u2014 no such column on this table`
187
236
  );
188
237
  }
189
- if (s.text !== void 0 && s.text.length === 0) {
190
- throw new Error(`table ${String(name)}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
191
- }
192
- const legs = s.vector === void 0 ? [] : Array.isArray(s.vector) ? s.vector : [s.vector];
193
- for (const leg of legs) {
194
- if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
195
- throw new Error(`table ${String(name)}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
196
- }
197
- if (leg.model === void 0 && leg.from !== void 0) {
198
- throw new Error(`table ${String(name)}: search.vector.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin`);
199
- }
200
- }
238
+ def.references = {
239
+ table: qualifiedTableKey(schemaName, table.name),
240
+ column: def.selfRefColumn
241
+ };
242
+ continue;
201
243
  }
202
- tableDef.search = s;
203
- }
204
- if (table.memory !== void 0) {
205
- if (table.memory.from.length === 0) {
206
- throw new Error(`table ${String(name)}: memory.from bo\u015F olamaz`);
244
+ if (def.referencesThunk === void 0) continue;
245
+ const target = def.referencesThunk();
246
+ const owner = target?._def?.ownerTable;
247
+ if (owner === void 0) {
248
+ throw new Error(
249
+ `table "${table.name}" column "${colName}": references(() => \u2026) must point at a column of a table declared with defineTable(...)`
250
+ );
251
+ }
252
+ const targetColumn = Object.entries(owner.columns).find(
253
+ ([, b]) => b._def === target._def
254
+ )?.[0];
255
+ if (targetColumn === void 0) {
256
+ throw new Error(
257
+ `table "${table.name}" column "${colName}": the referenced column was not found on table "${owner.name}"`
258
+ );
207
259
  }
208
- tableDef.memory = table.memory;
260
+ const targetSchema = declaringSchemaOf.get(owner);
261
+ if (targetSchema === void 0) {
262
+ throw new Error(
263
+ `table "${table.name}" column "${colName}": references(() => \u2026) points at table "${owner.name}", which no defineSchema(...) has claimed yet \u2014 a foreign key cannot be written without its target's schema. Declare that table's schema first (one file per schema: db/public.ts, db/billing.ts \u2026, imported by this one).`
264
+ );
265
+ }
266
+ def.references = {
267
+ table: qualifiedTableKey(targetSchema, owner.name),
268
+ column: targetColumn
269
+ };
209
270
  }
210
- tables[name] = tableDef;
211
271
  }
212
- for (const [name, def] of Object.entries(tables)) {
272
+ }
273
+ function defineSchema(name, input) {
274
+ if (typeof name !== "string") {
275
+ throw new Error(
276
+ `defineSchema(...) takes the schema NAME first: defineSchema("public", { tables: [todos, lists] }). The one-argument form defineSchema({ tables: { \u2026 } }) is gone \u2014 a schema that does not say its own name cannot be told apart from another schema's table of the same name, which is what a cross-schema foreign key has to do. Migrate db/public.ts (one file per schema: db/public.ts, db/billing.ts \u2026): name the schema, and lift each table key onto the table itself with defineTable("todos", { columns: { \u2026 } }), then list the tables in the array.`
277
+ );
278
+ }
279
+ if (name.trim() === "") {
280
+ throw new Error("defineSchema(name, \u2026): name must not be empty");
281
+ }
282
+ const tables = {};
283
+ for (const handle of input.tables) {
284
+ const table = handle[TABLE_META];
285
+ if (tables[table.name] !== void 0) {
286
+ throw new Error(
287
+ `defineSchema("${name}"): two tables declare the name "${table.name}" \u2014 table names must be unique within a schema`
288
+ );
289
+ }
290
+ tables[table.name] = table;
291
+ declaringSchemaOf.set(table, name);
292
+ }
293
+ resolveReferences(tables, name);
294
+ for (const [name2, def] of Object.entries(tables)) {
213
295
  const m = def.memory;
214
296
  if (m === void 0) continue;
215
297
  const target = Object.values(tables).find((t) => t.name === m.into);
216
298
  if (target === void 0) {
217
- throw new Error(`table ${name}: memory.into "${m.into}" \u015Femada declared de\u011Fil`);
299
+ throw new Error(`table ${name2}: memory.into "${m.into}" \u015Femada declared de\u011Fil`);
218
300
  }
219
301
  const subject = m.subject ?? "owner";
220
302
  if (!(subject in def.columns)) {
221
- throw new Error(`table ${name}: memory.subject "${subject}" kolonu kaynak tabloda yok`);
303
+ throw new Error(`table ${name2}: memory.subject "${subject}" kolonu kaynak tabloda yok`);
222
304
  }
223
305
  if (!(subject in target.columns)) {
224
- throw new Error(`table ${name}: memory.subject "${subject}" kolonu hedef "${m.into}" tablosunda yok`);
306
+ throw new Error(`table ${name2}: memory.subject "${subject}" kolonu hedef "${m.into}" tablosunda yok`);
225
307
  }
226
308
  const factCol = target.columns["fact"];
227
309
  const factDef = factCol !== void 0 && "_def" in factCol ? factCol._def : factCol;
228
310
  if (factDef === void 0 || factDef.type !== "text") {
229
- throw new Error(`table ${name}: memory.into "${m.into}" tablosunda "fact" (text) kolonu zorunlu`);
311
+ throw new Error(`table ${name2}: memory.into "${m.into}" tablosunda "fact" (text) kolonu zorunlu`);
230
312
  }
231
313
  for (const c of m.from) {
232
314
  if (!(c in def.columns)) {
233
- throw new Error(`table ${name}: memory.from kolonu "${c}" kaynak tabloda yok`);
315
+ throw new Error(`table ${name2}: memory.from kolonu "${c}" kaynak tabloda yok`);
234
316
  }
235
317
  }
236
318
  }
237
319
  const extensions = [...new Set(input.extensions ?? [])];
238
- return { tables, extensions };
320
+ return {
321
+ name,
322
+ tables,
323
+ extensions,
324
+ exposed: input.exposed ?? name === "public"
325
+ };
239
326
  }
240
327
 
241
328
  // src/db/extensions.ts
@@ -380,59 +467,46 @@ var ColumnBuilder = class _ColumnBuilder {
380
467
  ignored: true
381
468
  });
382
469
  }
383
- references(table, column) {
384
- refuseOnVector(this._def, "references");
385
- this._def.references = { table, column };
386
- return new _ColumnBuilder(this._def.type, this._def);
387
- }
388
470
  /**
389
- * Add a real DB-level foreign key to the built-in auth users
390
- * (`REFERENCES auth.users(id)`), so a column like `user_id` gets true
391
- * database cascade/integrity instead of app-layer-only. Sugar for
392
- * `.references("auth.users", "id")`.
471
+ * Foreign key onto another table's column.
393
472
  *
394
- * `auth.users` lives in the SAME tenant database (palauth-owned), so this is
395
- * a genuine cross-schema integrity constraint scoped to THIS tenant's users.
396
- * The referenced `auth.users.id` is `text` (palauth ids are `usr_<uuid>`), so
397
- * the referencing column must be `text()` too.
473
+ * The target is a THUNK, not a direct reference. In a cycle (`x y`, `y → x`)
474
+ * the second table does not exist yet when the first is built; a direct
475
+ * reference makes TypeScript chase its own tail (TS7022 measured, and making
476
+ * the return type independent of the target does NOT help). The thunk is
477
+ * invoked in `defineSchema`, where every binding exists and every table
478
+ * already knows its name.
398
479
  *
399
- * ON DELETE is REQUIRED here and may only be `cascade` or `set null`: an
400
- * account-erasure request must never be blocked by a lingering FK, so
401
- * `restrict` / `no action` are not accepted (they don't type-check). Example:
402
- * `text().notNull().referencesAuthUser("cascade")`, or
403
- * `text().nullable().referencesAuthUser("set null")`. The server
404
- * (validateAuthUserFK) enforces this — and the remaining rules the type can't
405
- * express (referencing column is text, `set null` needs a nullable column) —
406
- * as the real boundary; this signature is the compile-time DX mirror.
480
+ * In a cycle, ONE side needs an explicit return type:
481
+ * `references((): AnyColumn => y.id)`. One side is enough measured.
482
+ * For a self-reference use `selfReferences(column)`: no thunk, no annotation.
407
483
  */
408
- referencesAuthUser(onDelete) {
409
- refuseOnVector(this._def, "referencesAuthUser");
410
- this._def.references = { table: "auth.users", column: "id" };
411
- this._def.onDeleteAction = onDelete;
484
+ references(target, opts) {
485
+ refuseOnVector(this._def, "references");
486
+ if (typeof target !== "function") {
487
+ throw new Error(
488
+ `references(...) takes a callback: write references(() => otherTable.column). The two-string form references("table", "column") is gone \u2014 a string cannot be type-checked and cannot point at a table that does not exist yet.`
489
+ );
490
+ }
491
+ this._def.referencesThunk = target;
492
+ if (opts?.as !== void 0) this._def.refAs = opts.as;
493
+ if (opts?.onDelete !== void 0) this._def.onDeleteAction = opts.onDelete;
412
494
  return new _ColumnBuilder(this._def.type, this._def);
413
495
  }
414
496
  /**
415
- * Add a real DB-level foreign key to the canonical, server-minted installation
416
- * anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device
417
- * root (`ins_...`). Sugar for `.references("auth.installations", "id")`.
418
- *
419
- * An installation is an APP INSTALL, not a user: this FK is NOT user ownership.
420
- * A user-owned row STILL needs its own `.referencesAuthUser(...)` FK so account
421
- * erasure removes it — an installation reference alone does not tie a row to a
422
- * user's deletion. Use this only for install-scoped state (device prefs, push
423
- * routing, …), alongside a separate auth-user FK where the row is user-owned.
497
+ * Foreign key onto THIS table (`parent_id id`) — category trees, comment
498
+ * replies, org charts.
424
499
  *
425
- * `auth.installations` lives in the SAME tenant DB (palauth-owned); its `id` is
426
- * `text` (`ins_<uuid>`), so the referencing column must be `text()` too. ON
427
- * DELETE is REQUIRED and may only be `cascade` or `set null` (same allowed set
428
- * as an auth-user FK): an installation revoke / orphan cleanup must never be
429
- * blocked by a lingering FK. The server (validateAuthAnchorFK) is the real
430
- * boundary; this signature is the compile-time DX mirror.
500
+ * No thunk and no type annotation: the target table is the one being declared,
501
+ * so there is nothing to defer and nothing for TypeScript to chase in a circle.
502
+ * Drizzle forces an explicit `(): AnyPgColumn =>` here because its reference
503
+ * always goes through a callback; measured, we do not need one.
431
504
  */
432
- referencesInstallation(onDelete) {
433
- refuseOnVector(this._def, "referencesInstallation");
434
- this._def.references = { table: "auth.installations", column: "id" };
435
- this._def.onDeleteAction = onDelete;
505
+ selfReferences(column, opts) {
506
+ refuseOnVector(this._def, "selfReferences");
507
+ this._def.selfRefColumn = column;
508
+ if (opts?.as !== void 0) this._def.refAs = opts.as;
509
+ if (opts?.onDelete !== void 0) this._def.onDeleteAction = opts.onDelete;
436
510
  return new _ColumnBuilder(this._def.type, this._def);
437
511
  }
438
512
  /** Set the ON DELETE action for a foreign key reference. */
@@ -504,6 +578,28 @@ function vector(dimensions) {
504
578
  b._def.dimensions = dimensions;
505
579
  return b;
506
580
  }
581
+ function ownedByUser() {
582
+ const b = new ColumnBuilder("text");
583
+ b._def.nullable = false;
584
+ b._def.references = { table: "auth.users", column: "id" };
585
+ b._def.onDeleteAction = "cascade";
586
+ b._def.owns = true;
587
+ return b;
588
+ }
589
+ function userRef(opts) {
590
+ const b = new ColumnBuilder("text");
591
+ b._def.references = { table: "auth.users", column: "id" };
592
+ b._def.onDeleteAction = opts.onDelete;
593
+ if (opts.as !== void 0) b._def.refAs = opts.as;
594
+ return b;
595
+ }
596
+ function installationRef(opts) {
597
+ const b = new ColumnBuilder("text");
598
+ b._def.references = { table: "auth.installations", column: "id" };
599
+ b._def.onDeleteAction = opts.onDelete;
600
+ if (opts.as !== void 0) b._def.refAs = opts.as;
601
+ return b;
602
+ }
507
603
 
508
604
  // src/db/raw.ts
509
605
  function raw(name, up, opts) {
@@ -1013,24 +1109,29 @@ function makeTypedDB(schema, raw2) {
1013
1109
  EXTENSION_DEPENDENCIES,
1014
1110
  PALBASE_EXTENSIONS,
1015
1111
  PolicyBuilder,
1112
+ TABLE_META,
1016
1113
  TxPlanError,
1017
1114
  TxRefError,
1018
1115
  bigint,
1019
1116
  boolean,
1020
1117
  dec,
1021
1118
  defineSchema,
1119
+ defineTable,
1022
1120
  enumType,
1023
1121
  inc,
1122
+ installationRef,
1024
1123
  integer,
1025
1124
  isPalbaseExtension,
1026
1125
  jsonb,
1027
1126
  makeTypedDB,
1028
1127
  now,
1029
1128
  openai,
1129
+ ownedByUser,
1030
1130
  policy,
1031
1131
  raw,
1032
1132
  text,
1033
1133
  timestamp,
1134
+ userRef,
1034
1135
  uuid,
1035
1136
  vector
1036
1137
  });