@palbase/backend 23.0.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 (60) hide show
  1. package/dist/bin/palbase-backend.cjs +313 -24
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +5 -5
  4. package/dist/{chunk-Y5HXVUMP.js → chunk-HQRJDARQ.js} +2 -2
  5. package/dist/{chunk-REZU6UKT.js → chunk-M5MCBWJI.js} +296 -25
  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-FSGSB42K.js → chunk-OHALWEOG.js} +9 -4
  10. package/dist/chunk-OHALWEOG.js.map +1 -0
  11. package/dist/{chunk-HAF67F2H.js → chunk-PY7YJDCT.js} +57 -3
  12. package/dist/chunk-PY7YJDCT.js.map +1 -0
  13. package/dist/{chunk-ZC6Q2BRD.js → chunk-R3KN6RHD.js} +2 -2
  14. package/dist/{chunk-OMRTHM4X.js → chunk-RCLNBJCM.js} +1 -1
  15. package/dist/chunk-RCLNBJCM.js.map +1 -0
  16. package/dist/db/index.cjs +68 -1
  17. package/dist/db/index.cjs.map +1 -1
  18. package/dist/db/index.d.cts +2 -2
  19. package/dist/db/index.d.ts +2 -2
  20. package/dist/db/index.js +2 -2
  21. package/dist/{endpoint-BavvbW4P.d.ts → endpoint-CVWXh6oG.d.ts} +70 -8
  22. package/dist/{endpoint-i8TTCohk.d.cts → endpoint-c9h5jriX.d.cts} +70 -8
  23. package/dist/engine/index.cjs +313 -24
  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 +4 -4
  28. package/dist/{index-B7YBEG5w.d.ts → index-BZrJXnVh.d.ts} +49 -4
  29. package/dist/{index-Bmvx1EvJ.d.cts → index-By8Dle5U.d.cts} +86 -17
  30. package/dist/{index-B3jmmItD.d.ts → index-CwAJ7HEe.d.ts} +86 -17
  31. package/dist/{index-E7OscPJT.d.cts → index-CxeQSfJP.d.cts} +49 -4
  32. package/dist/index.cjs +104 -3
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +8 -8
  35. package/dist/index.d.ts +8 -8
  36. package/dist/index.js +32 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/openapi/index.cjs +29 -4
  39. package/dist/openapi/index.cjs.map +1 -1
  40. package/dist/openapi/index.d.cts +5 -2
  41. package/dist/openapi/index.d.ts +5 -2
  42. package/dist/openapi/index.js +32 -7
  43. package/dist/openapi/index.js.map +1 -1
  44. package/dist/{registry-DY3d9l1k.d.ts → registry-B3niOVYp.d.ts} +101 -7
  45. package/dist/{registry-C3H2uPeZ.d.cts → registry-CqPK2Qby.d.cts} +101 -7
  46. package/dist/test/index.cjs +482 -9
  47. package/dist/test/index.cjs.map +1 -1
  48. package/dist/test/index.d.cts +35 -3
  49. package/dist/test/index.d.ts +35 -3
  50. package/dist/test/index.js +480 -8
  51. package/dist/test/index.js.map +1 -1
  52. package/package.json +4 -3
  53. package/stager/return_types.js +23 -0
  54. package/dist/chunk-FSGSB42K.js.map +0 -1
  55. package/dist/chunk-HAF67F2H.js.map +0 -1
  56. package/dist/chunk-OMRTHM4X.js.map +0 -1
  57. package/dist/chunk-REZU6UKT.js.map +0 -1
  58. package/dist/chunk-W5ODXPY3.js.map +0 -1
  59. /package/dist/{chunk-Y5HXVUMP.js.map → chunk-HQRJDARQ.js.map} +0 -0
  60. /package/dist/{chunk-ZC6Q2BRD.js.map → chunk-R3KN6RHD.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -57,6 +57,9 @@ __export(src_exports, {
57
57
  Req: () => Req,
58
58
  RequestId: () => RequestId,
59
59
  Secrets: () => Secrets,
60
+ Signal: () => Signal,
61
+ Sse: () => Sse,
62
+ SseOut: () => SseOut,
60
63
  Storage: () => Storage,
61
64
  TooManyRequests: () => TooManyRequests,
62
65
  TraceId: () => TraceId,
@@ -354,6 +357,19 @@ var TxPlanBuilder = class {
354
357
  }
355
358
  return this.push({ op: "insert", table: name, values: encoded }, `${name}.insert()`);
356
359
  },
360
+ upsert: (values, options) => {
361
+ const encoded = encodeMap(values, false);
362
+ if (Object.keys(encoded).length === 0) {
363
+ throw new TxPlanError(`${name}.upsert() needs at least one column`);
364
+ }
365
+ if (options.onConflict.length === 0) {
366
+ throw new TxPlanError(`${name}.upsert() needs at least one onConflict column`);
367
+ }
368
+ return this.push(
369
+ { op: "upsert", table: name, values: encoded, onConflict: options.onConflict },
370
+ `${name}.upsert()`
371
+ );
372
+ },
357
373
  insertMany: (rows) => {
358
374
  if (rows.length === 0) {
359
375
  return new TxRowsImpl(this, SKIPPED_OP, `${name}.insertMany()`);
@@ -564,7 +580,8 @@ function makeTablesAccessor(ops) {
564
580
  update: (id, data) => ops().update(name, id, data),
565
581
  delete: (id) => ops().delete(name, id),
566
582
  findById: (id) => ops().findById(name, id),
567
- findMany: (query) => ops().findMany(name, query),
583
+ findMany: (query, opts) => ops().findMany(name, query, opts),
584
+ upsert: (data, opts) => ops().upsert(name, data, opts),
568
585
  search: (params) => ops().search(name, params),
569
586
  similar: (id, params) => ops().similar(name, id, params),
570
587
  recommend: (params) => ops().recommend(name, params),
@@ -584,13 +601,17 @@ function makeTypedSurface(raw2) {
584
601
  update: (table, id, data) => raw2.update(table, id, data),
585
602
  delete: (table, id) => raw2.delete(table, id),
586
603
  findById: (table, id) => raw2.findById(table, id),
587
- findMany: (table, query) => raw2.findMany(table, query),
604
+ findMany: (table, query, opts) => raw2.findMany(table, query, opts),
605
+ upsert: (table, data, opts) => raw2.upsert(table, data, opts),
588
606
  search: (table, params) => raw2.search(table, params),
589
607
  similar: (table, id, params) => reco.similar(table, id, params),
590
608
  recommend: (table, params) => reco.recommend(table, params),
591
609
  supersede: (table, id, row) => raw2.supersede(table, id, row)
592
610
  };
593
611
  return Object.assign(ops, {
612
+ // Both surfaces get it: a savepoint on the service transaction is as useful
613
+ // as one on the request's, and each is bound to its own connection.
614
+ attempt: (fn) => raw2.attempt(fn),
594
615
  tables: makeTablesAccessor(() => reco),
595
616
  transaction(fn) {
596
617
  const builder = new TxPlanBuilder();
@@ -1573,6 +1594,9 @@ function buildModuleClients(cfg) {
1573
1594
  }
1574
1595
 
1575
1596
  // src/db/policy.ts
1597
+ function quote(name) {
1598
+ return `"${name.replace(/"/g, '""')}"`;
1599
+ }
1576
1600
  var PolicyBuilder = class {
1577
1601
  _def;
1578
1602
  constructor(name) {
@@ -1608,6 +1632,41 @@ var PolicyBuilder = class {
1608
1632
  this._def.using = sqlExpr;
1609
1633
  return this;
1610
1634
  }
1635
+ /**
1636
+ * "Rows of THIS table whose owner the caller is a member of" — the membership
1637
+ * pattern, written so it cannot recurse.
1638
+ *
1639
+ * THE TRAP IT EXISTS FOR. Written by hand, membership policies point at each
1640
+ * other: `channels` is visible to members, so its policy reads
1641
+ * `channel_members`; `channel_members` is visible to members, so its policy
1642
+ * reads `channels`. Postgres refuses the pair at query time with `infinite
1643
+ * recursion detected in policy for relation ...`, and the error names the
1644
+ * relation but not the cycle. The way out is asymmetry — the MEMBERSHIP table
1645
+ * is protected by `user_id = auth.uid()` and nothing else, and every other
1646
+ * table subqueries INTO it. That shape was in the platform's own schema and
1647
+ * written down nowhere; a customer recovered it by reading that schema.
1648
+ *
1649
+ * `(select auth.uid())` rather than a bare call: the scalar subquery is
1650
+ * evaluated ONCE per statement instead of per row.
1651
+ *
1652
+ * @example
1653
+ * // channels: visible to members. The membership table gets the simple one.
1654
+ * policy("member_read").for("select").to("authenticated")
1655
+ * .memberOf("channel_members", "channel_id")
1656
+ * // → id IN (SELECT "channel_id" FROM "channel_members"
1657
+ * // WHERE "user_id" = (select auth.uid()))
1658
+ */
1659
+ memberOf(membershipTable, foreignKey, options = {}) {
1660
+ if (this._def.using !== null) {
1661
+ throw new Error(
1662
+ `policy(${this._def.name}).memberOf(): this policy already has a using() expression. Write one or the other \u2014 memberOf IS the using expression.`
1663
+ );
1664
+ }
1665
+ const column = options.column ?? "id";
1666
+ const userColumn = options.userColumn ?? "user_id";
1667
+ this._def.using = `${quote(column)} IN (SELECT ${quote(foreignKey)} FROM ${quote(membershipTable)} WHERE ${quote(userColumn)} = (select auth.uid()))`;
1668
+ return this;
1669
+ }
1611
1670
  /** Set the `WITH CHECK (...)` write-validation expression (raw SQL). */
1612
1671
  withCheck(sqlExpr) {
1613
1672
  this._def.withCheck = sqlExpr;
@@ -2033,6 +2092,21 @@ var ColumnBuilder = class _ColumnBuilder {
2033
2092
  this._def.defaultNow = true;
2034
2093
  return new _ColumnBuilder(this._def.type, this._def);
2035
2094
  }
2095
+ /**
2096
+ * The DATABASE assigns this column's value — a trigger, a rule, an identity.
2097
+ *
2098
+ * The column becomes optional on INSERT (the author has nothing to send) while
2099
+ * the DDL stays free of a DEFAULT this schema would not honour. It is NOT
2100
+ * `default()`: that declares a value the schema promises to write.
2101
+ *
2102
+ * Naming: deliberately not `generated()`. Postgres has GENERATED columns and
2103
+ * they are a different thing; borrowing the word would send a reader — or a
2104
+ * model writing a schema — to the wrong feature.
2105
+ */
2106
+ dbAssigned() {
2107
+ this._def.dbAssigned = true;
2108
+ return new _ColumnBuilder(this._def.type, this._def);
2109
+ }
2036
2110
  /** Add a foreign key reference. */
2037
2111
  /**
2038
2112
  * Declares that this column used to be called `previous`.
@@ -2180,10 +2254,11 @@ var openai = {
2180
2254
  function makeTypedTable(name, raw2) {
2181
2255
  return {
2182
2256
  insert: (data) => raw2.insert(name, data),
2257
+ upsert: (data, opts) => raw2.upsert(name, data, opts),
2183
2258
  update: (id, data) => raw2.update(name, id, data),
2184
2259
  delete: (id) => raw2.delete(name, id),
2185
2260
  findById: (id) => raw2.findById(name, id),
2186
- findMany: (query) => raw2.findMany(name, query)
2261
+ findMany: (query, opts) => raw2.findMany(name, query, opts)
2187
2262
  };
2188
2263
  }
2189
2264
  function makeTypedDB(schema, raw2) {
@@ -2750,6 +2825,29 @@ function validateUploadConfigShape(c) {
2750
2825
  }
2751
2826
  }
2752
2827
 
2828
+ // src/decorators/sse.ts
2829
+ function Sse(subpath = "", config) {
2830
+ const { auth, rateLimit, ...sseConfig } = config;
2831
+ const options = {
2832
+ sseConfig,
2833
+ ...auth !== void 0 ? { auth } : {},
2834
+ ...rateLimit !== void 0 ? { rateLimit } : {}
2835
+ };
2836
+ return function(target, propertyKey) {
2837
+ recordRoute(target, String(propertyKey), "POST", subpath, options);
2838
+ };
2839
+ }
2840
+ function SseOut() {
2841
+ return function(target, propertyKey, parameterIndex) {
2842
+ recordParam(target, String(propertyKey), { index: parameterIndex, kind: "sseOut" });
2843
+ };
2844
+ }
2845
+ function Signal() {
2846
+ return function(target, propertyKey, parameterIndex) {
2847
+ recordParam(target, String(propertyKey), { index: parameterIndex, kind: "signal" });
2848
+ };
2849
+ }
2850
+
2753
2851
  // src/decorators/params.ts
2754
2852
  function makeParamDecorator(kind, extra) {
2755
2853
  return function(target, propertyKey, parameterIndex) {
@@ -3156,6 +3254,9 @@ var import_zod2 = require("zod");
3156
3254
  Req,
3157
3255
  RequestId,
3158
3256
  Secrets,
3257
+ Signal,
3258
+ Sse,
3259
+ SseOut,
3159
3260
  Storage,
3160
3261
  TooManyRequests,
3161
3262
  TraceId,