@palbase/backend 22.1.0 → 23.1.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 (81) hide show
  1. package/dist/bin/palbase-backend.cjs +750 -40
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +5 -5
  4. package/dist/{chunk-YL4C5NRY.js → chunk-HQRJDARQ.js} +2 -2
  5. package/dist/{chunk-74XDEF5J.js → chunk-M5MCBWJI.js} +723 -37
  6. package/dist/chunk-M5MCBWJI.js.map +1 -0
  7. package/dist/{chunk-W5ODXPY3.js → chunk-NS5V43YQ.js} +14 -1
  8. package/dist/chunk-NS5V43YQ.js.map +1 -0
  9. package/dist/{chunk-SQC5EIWY.js → chunk-OHALWEOG.js} +19 -9
  10. package/dist/chunk-OHALWEOG.js.map +1 -0
  11. package/dist/{chunk-I3ON7MYF.js → chunk-PY7YJDCT.js} +129 -18
  12. package/dist/chunk-PY7YJDCT.js.map +1 -0
  13. package/dist/{chunk-N32VDWKH.js → chunk-R3KN6RHD.js} +4 -59
  14. package/dist/chunk-R3KN6RHD.js.map +1 -0
  15. package/dist/{chunk-QMVK4X3V.js → chunk-RCLNBJCM.js} +98 -98
  16. package/dist/chunk-RCLNBJCM.js.map +1 -0
  17. package/dist/db/env.cjs.map +1 -1
  18. package/dist/db/env.d.cts +3 -21
  19. package/dist/db/env.d.ts +3 -21
  20. package/dist/db/index.cjs +140 -16
  21. package/dist/db/index.cjs.map +1 -1
  22. package/dist/db/index.d.cts +3 -2
  23. package/dist/db/index.d.ts +3 -2
  24. package/dist/db/index.js +2 -2
  25. package/dist/{endpoint-BVT6jcVW.d.cts → endpoint-CVWXh6oG.d.ts} +147 -15
  26. package/dist/{endpoint-BVT6jcVW.d.ts → endpoint-c9h5jriX.d.cts} +147 -15
  27. package/dist/engine/index.cjs +750 -40
  28. package/dist/engine/index.cjs.map +1 -1
  29. package/dist/engine/index.d.cts +6 -5
  30. package/dist/engine/index.d.ts +6 -5
  31. package/dist/engine/index.js +4 -4
  32. package/dist/{index-BS1gW4nV.d.cts → index-BZrJXnVh.d.ts} +142 -72
  33. package/dist/{index-BqCiHao8.d.cts → index-By8Dle5U.d.cts} +196 -21
  34. package/dist/{index-vwHoS0l2.d.ts → index-CwAJ7HEe.d.ts} +196 -21
  35. package/dist/{index-CCZqzych.d.ts → index-CxeQSfJP.d.cts} +142 -72
  36. package/dist/index.cjs +388 -1101
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +89 -1134
  39. package/dist/index.d.ts +89 -1134
  40. package/dist/index.js +133 -902
  41. package/dist/index.js.map +1 -1
  42. package/dist/openapi/index.cjs +32 -61
  43. package/dist/openapi/index.cjs.map +1 -1
  44. package/dist/openapi/index.d.cts +6 -2
  45. package/dist/openapi/index.d.ts +6 -2
  46. package/dist/openapi/index.js +34 -26
  47. package/dist/openapi/index.js.map +1 -1
  48. package/dist/{registry-Bsuf-orT.d.ts → registry-B3niOVYp.d.ts} +108 -170
  49. package/dist/{registry-BWttGlaT.d.cts → registry-CqPK2Qby.d.cts} +108 -170
  50. package/dist/{purchases/keys.cjs → stack.cjs} +4 -4
  51. package/dist/stack.cjs.map +1 -0
  52. package/dist/stack.d.cts +76 -0
  53. package/dist/stack.d.ts +76 -0
  54. package/dist/stack.js +1 -0
  55. package/dist/test/index.cjs +482 -9
  56. package/dist/test/index.cjs.map +1 -1
  57. package/dist/test/index.d.cts +35 -3
  58. package/dist/test/index.d.ts +35 -3
  59. package/dist/test/index.js +480 -8
  60. package/dist/test/index.js.map +1 -1
  61. package/docs/README.md +7 -6
  62. package/docs/llms-full.txt +7 -260
  63. package/docs/llms.txt +0 -2
  64. package/package.json +9 -8
  65. package/stager/return_types.js +23 -0
  66. package/template/package.json +1 -1
  67. package/dist/chunk-74XDEF5J.js.map +0 -1
  68. package/dist/chunk-I3ON7MYF.js.map +0 -1
  69. package/dist/chunk-N32VDWKH.js.map +0 -1
  70. package/dist/chunk-QMVK4X3V.js.map +0 -1
  71. package/dist/chunk-SQC5EIWY.js.map +0 -1
  72. package/dist/chunk-W5ODXPY3.js.map +0 -1
  73. package/dist/purchases/keys.cjs.map +0 -1
  74. package/dist/purchases/keys.d.cts +0 -42
  75. package/dist/purchases/keys.d.ts +0 -42
  76. package/dist/purchases/keys.js +0 -1
  77. package/docs/config.md +0 -147
  78. package/docs/resources.md +0 -97
  79. package/template/config/secrets.ts +0 -24
  80. /package/dist/{chunk-YL4C5NRY.js.map → chunk-HQRJDARQ.js.map} +0 -0
  81. /package/dist/{purchases/keys.js.map → stack.js.map} +0 -0
package/dist/db/env.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ export { BucketTypes, Buckets } from '../stack.cjs';
2
+
1
3
  /**
2
4
  * `@palbase/backend/env` — the controlled global augmentation target for the
3
5
  * project's schema.
@@ -55,25 +57,5 @@ interface TableTypes {
55
57
  */
56
58
  interface Tables {
57
59
  }
58
- /**
59
- * One typed bucket: which renditions `config/storage.ts` declared for it.
60
- *
61
- * `variants` is a UNION of the declared names, so asking for one the bucket
62
- * does not have is a compile error rather than a 404 somebody finds in
63
- * production. The generated `palbase-env.d.ts` fills it; the default `never`
64
- * means a bucket declared without variants accepts no variant name at all,
65
- * which is exactly right.
66
- */
67
- interface BucketTypes {
68
- variants: string;
69
- }
70
- /**
71
- * The project's storage buckets, keyed by bucket name. EMPTY by default; the
72
- * generated `palbase-env.d.ts` augments it, so `Storage.buckets` is typed
73
- * everywhere with no per-file import — the same mechanism `Tables` uses, and
74
- * deliberately so: an author learns one pattern.
75
- */
76
- interface Buckets {
77
- }
78
60
 
79
- export type { BucketTypes, Buckets, TableTypes, Tables };
61
+ export type { TableTypes, Tables };
package/dist/db/env.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { BucketTypes, Buckets } from '../stack.js';
2
+
1
3
  /**
2
4
  * `@palbase/backend/env` — the controlled global augmentation target for the
3
5
  * project's schema.
@@ -55,25 +57,5 @@ interface TableTypes {
55
57
  */
56
58
  interface Tables {
57
59
  }
58
- /**
59
- * One typed bucket: which renditions `config/storage.ts` declared for it.
60
- *
61
- * `variants` is a UNION of the declared names, so asking for one the bucket
62
- * does not have is a compile error rather than a 404 somebody finds in
63
- * production. The generated `palbase-env.d.ts` fills it; the default `never`
64
- * means a bucket declared without variants accepts no variant name at all,
65
- * which is exactly right.
66
- */
67
- interface BucketTypes {
68
- variants: string;
69
- }
70
- /**
71
- * The project's storage buckets, keyed by bucket name. EMPTY by default; the
72
- * generated `palbase-env.d.ts` augments it, so `Storage.buckets` is typed
73
- * everywhere with no per-file import — the same mechanism `Tables` uses, and
74
- * deliberately so: an author learns one pattern.
75
- */
76
- interface Buckets {
77
- }
78
60
 
79
- export type { BucketTypes, Buckets, TableTypes, Tables };
61
+ export type { TableTypes, Tables };
package/dist/db/index.cjs CHANGED
@@ -47,6 +47,9 @@ __export(db_exports, {
47
47
  module.exports = __toCommonJS(db_exports);
48
48
 
49
49
  // src/db/policy.ts
50
+ function quote(name) {
51
+ return `"${name.replace(/"/g, '""')}"`;
52
+ }
50
53
  var PolicyBuilder = class {
51
54
  _def;
52
55
  constructor(name) {
@@ -82,6 +85,41 @@ var PolicyBuilder = class {
82
85
  this._def.using = sqlExpr;
83
86
  return this;
84
87
  }
88
+ /**
89
+ * "Rows of THIS table whose owner the caller is a member of" — the membership
90
+ * pattern, written so it cannot recurse.
91
+ *
92
+ * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each
93
+ * other: `channels` is visible to members, so its policy reads
94
+ * `channel_members`; `channel_members` is visible to members, so its policy
95
+ * reads `channels`. Postgres refuses the pair at query time with `infinite
96
+ * recursion detected in policy for relation ...`, and the error names the
97
+ * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table
98
+ * is protected by `user_id = auth.uid()` and nothing else, and every other
99
+ * table subqueries INTO it. That shape was in the platform's own schema and
100
+ * written down nowhere; a customer recovered it by reading that schema.
101
+ *
102
+ * `(select auth.uid())` rather than a bare call: the scalar subquery is
103
+ * evaluated ONCE per statement instead of per row.
104
+ *
105
+ * @example
106
+ * // channels: visible to members. The membership table gets the simple one.
107
+ * policy("member_read").for("select").to("authenticated")
108
+ * .memberOf("channel_members", "channel_id")
109
+ * // → id IN (SELECT "channel_id" FROM "channel_members"
110
+ * // WHERE "user_id" = (select auth.uid()))
111
+ */
112
+ memberOf(membershipTable, foreignKey, options = {}) {
113
+ if (this._def.using !== null) {
114
+ throw new Error(
115
+ `policy(${this._def.name}).memberOf(): this policy already has a using() expression. Write one or the other \u2014 memberOf IS the using expression.`
116
+ );
117
+ }
118
+ const column = options.column ?? "id";
119
+ const userColumn = options.userColumn ?? "user_id";
120
+ this._def.using = `${quote(column)} IN (SELECT ${quote(foreignKey)} FROM ${quote(membershipTable)} WHERE ${quote(userColumn)} = (select auth.uid()))`;
121
+ return this;
122
+ }
85
123
  /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */
86
124
  withCheck(sqlExpr) {
87
125
  this._def.withCheck = sqlExpr;
@@ -121,27 +159,81 @@ function defineSchema(input) {
121
159
  if (table.checks !== void 0 && table.checks.length > 0) tableDef.checks = table.checks.slice();
122
160
  if (table.indexes !== void 0 && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();
123
161
  if (table.search !== void 0) {
124
- if (table.search.text === void 0 && table.search.vector === void 0) {
125
- throw new Error(
126
- `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`
127
- );
128
- }
129
- if (table.search.text !== void 0 && table.search.text.length === 0) {
130
- throw new Error(`table ${String(name)}: search.text bo\u015F olamaz \u2014 FTS kolu istemiyorsan alan\u0131 hi\xE7 yazma`);
131
- }
132
- const legs = table.search.vector === void 0 ? [] : Array.isArray(table.search.vector) ? table.search.vector : [table.search.vector];
133
- for (const leg of legs) {
134
- if (leg.model !== void 0 && (leg.from === void 0 || leg.from.length === 0)) {
135
- throw new Error(`table ${String(name)}: search.vector.model beyan edildi ama 'from' yok \u2014 embed kayna\u011F\u0131 kolonlar zorunlu (C-2)`);
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
+ );
136
176
  }
137
- if (leg.model === void 0 && leg.from !== void 0) {
138
- throw new Error(`table ${String(name)}: search.vector.from model'siz anlams\u0131z \u2014 auto-embed i\xE7in model verin`);
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`);
139
179
  }
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`);
183
+ }
184
+ if (s.text === void 0 && s.vector === void 0) {
185
+ 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`
187
+ );
188
+ }
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
+ }
201
+ }
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`);
140
207
  }
141
- tableDef.search = table.search;
208
+ tableDef.memory = table.memory;
142
209
  }
143
210
  tables[name] = tableDef;
144
211
  }
212
+ for (const [name, def] of Object.entries(tables)) {
213
+ const m = def.memory;
214
+ if (m === void 0) continue;
215
+ const target = Object.values(tables).find((t) => t.name === m.into);
216
+ if (target === void 0) {
217
+ throw new Error(`table ${name}: memory.into "${m.into}" \u015Femada declared de\u011Fil`);
218
+ }
219
+ const subject = m.subject ?? "owner";
220
+ if (!(subject in def.columns)) {
221
+ throw new Error(`table ${name}: memory.subject "${subject}" kolonu kaynak tabloda yok`);
222
+ }
223
+ if (!(subject in target.columns)) {
224
+ throw new Error(`table ${name}: memory.subject "${subject}" kolonu hedef "${m.into}" tablosunda yok`);
225
+ }
226
+ const factCol = target.columns["fact"];
227
+ const factDef = factCol !== void 0 && "_def" in factCol ? factCol._def : factCol;
228
+ if (factDef === void 0 || factDef.type !== "text") {
229
+ throw new Error(`table ${name}: memory.into "${m.into}" tablosunda "fact" (text) kolonu zorunlu`);
230
+ }
231
+ for (const c of m.from) {
232
+ if (!(c in def.columns)) {
233
+ throw new Error(`table ${name}: memory.from kolonu "${c}" kaynak tabloda yok`);
234
+ }
235
+ }
236
+ }
145
237
  const extensions = [...new Set(input.extensions ?? [])];
146
238
  return { tables, extensions };
147
239
  }
@@ -235,6 +327,21 @@ var ColumnBuilder = class _ColumnBuilder {
235
327
  this._def.defaultNow = true;
236
328
  return new _ColumnBuilder(this._def.type, this._def);
237
329
  }
330
+ /**
331
+ * The DATABASE assigns this column's value — a trigger, a rule, an identity.
332
+ *
333
+ * The column becomes optional on INSERT (the author has nothing to send) while
334
+ * the DDL stays free of a DEFAULT this schema would not honour. It is NOT
335
+ * `default()`: that declares a value the schema promises to write.
336
+ *
337
+ * Naming: deliberately not `generated()`. Postgres has GENERATED columns and
338
+ * they are a different thing; borrowing the word would send a reader — or a
339
+ * model writing a schema — to the wrong feature.
340
+ */
341
+ dbAssigned() {
342
+ this._def.dbAssigned = true;
343
+ return new _ColumnBuilder(this._def.type, this._def);
344
+ }
238
345
  /** Add a foreign key reference. */
239
346
  /**
240
347
  * Declares that this column used to be called `previous`.
@@ -369,6 +476,9 @@ var openai = {
369
476
  ...opts?.dimensions !== void 0 ? { dimensions: opts.dimensions } : {},
370
477
  ...opts?.baseURL !== void 0 ? { baseURL: opts.baseURL } : {}
371
478
  };
479
+ },
480
+ chat(model) {
481
+ return { provider: "openai", model };
372
482
  }
373
483
  };
374
484
 
@@ -611,6 +721,19 @@ var TxPlanBuilder = class {
611
721
  }
612
722
  return this.push({ op: "insert", table: name, values: encoded }, `${name}.insert()`);
613
723
  },
724
+ upsert: (values, options) => {
725
+ const encoded = encodeMap(values, false);
726
+ if (Object.keys(encoded).length === 0) {
727
+ throw new TxPlanError(`${name}.upsert() needs at least one column`);
728
+ }
729
+ if (options.onConflict.length === 0) {
730
+ throw new TxPlanError(`${name}.upsert() needs at least one onConflict column`);
731
+ }
732
+ return this.push(
733
+ { op: "upsert", table: name, values: encoded, onConflict: options.onConflict },
734
+ `${name}.upsert()`
735
+ );
736
+ },
614
737
  insertMany: (rows) => {
615
738
  if (rows.length === 0) {
616
739
  return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);
@@ -784,10 +907,11 @@ function translateRejection(err, builder) {
784
907
  function makeTypedTable(name, raw2) {
785
908
  return {
786
909
  insert: (data) => raw2.insert(name, data),
910
+ upsert: (data, opts) => raw2.upsert(name, data, opts),
787
911
  update: (id, data) => raw2.update(name, id, data),
788
912
  delete: (id) => raw2.delete(name, id),
789
913
  findById: (id) => raw2.findById(name, id),
790
- findMany: (query) => raw2.findMany(name, query)
914
+ findMany: (query, opts) => raw2.findMany(name, query, opts)
791
915
  };
792
916
  }
793
917
  function makeTypedDB(schema, raw2) {