@palbase/backend 24.3.0 → 25.0.1

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 +103 -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-34I4GB7D.js} +82 -49
  6. package/dist/chunk-34I4GB7D.js.map +1 -0
  7. package/dist/{chunk-UWSYTUGM.js → chunk-35PNTIRN.js} +48 -1
  8. package/dist/chunk-35PNTIRN.js.map +1 -0
  9. package/dist/chunk-HBOJLP2Z.js +840 -0
  10. package/dist/chunk-HBOJLP2Z.js.map +1 -0
  11. package/dist/{chunk-7Z6MGMXQ.js → chunk-XJ2RSHEU.js} +11 -5
  12. package/dist/chunk-XJ2RSHEU.js.map +1 -0
  13. package/dist/{chunk-ERDL5VAE.js → chunk-YOY5DFQS.js} +2 -2
  14. package/dist/db/env.cjs.map +1 -1
  15. package/dist/db/env.d.cts +31 -14
  16. package/dist/db/env.d.ts +31 -14
  17. package/dist/db/index.cjs +226 -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 +89 -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-BTMYod_l.d.ts → index-B4CcpqLb.d.ts} +224 -75
  28. package/dist/{index-DEneI8Mn.d.ts → index-B8v6hVyU.d.ts} +5 -2
  29. package/dist/{index-BLAbr9ZH.d.cts → index-DmVyY6N7.d.cts} +224 -75
  30. package/dist/{index-C-ALG22n.d.cts → index-VsjBQ4Kw.d.cts} +5 -2
  31. package/dist/index.cjs +580 -301
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +125 -22
  34. package/dist/index.d.ts +125 -22
  35. package/dist/index.js +173 -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 +430 -153
  44. package/docs/schema.md +303 -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-YOY5DFQS.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, f as EnvServiceDatabase, E as EnvTypedDatabase, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, S as SchemaDef, o as SchemaInput, T as TableDef, p as TableInput, q as TxPlan, r as TxTables, s as TypedDB, t as TypedTable, u as TypedTx, v as bigint, w as boolean, x as defineSchema, y as enumType, z as integer, A as isPalbaseExtension, B as jsonb, D as makeTypedDB, G as openai, H as policy, J as raw, K as text, L as timestamp, M as uuid, N as vector } from '../index-BLAbr9ZH.cjs';
1
+ export { A as AnyColumn, C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, g as EnvServiceDatabase, E as EnvTypedDatabase, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, j as PalbaseExtension, k as PolicyBuilder, l as PolicyCommand, m as PolicyDef, n as PolicyMode, R as RawConstraintDef, o as RowShape, S as SchemaDef, T as TABLE_META, p as TableDef, q as TableHandle, r as TableInput, s as TxPlan, t as TxTables, u as TypedDB, v as TypedTable, w as TypedTx, x as bigint, y as boolean, z as defineSchema, B as defineTable, D as enumType, F as installationRef, G as integer, H as isPalbaseExtension, J as jsonb, K as makeTypedDB, M as openai, N as ownedByUser, Q as policy, U as raw, V as text, W as timestamp, X as userRef, Y as uuid, Z as vector } from '../index-DmVyY6N7.cjs';
2
2
  export { M as Materialized, b1 as Ref, b3 as TxColumnExpr, b4 as TxInsertShape, b6 as TxNow, T as TxPlanBody, b7 as TxPlanError, b8 as TxPlanHandle, b9 as TxPlanOpResult, ba as TxPlanRejection, g as TxPlanResponse, bb as TxRefError, bc as TxRow, bd as TxRows, be as TxSelectOptions, bf as TxSetShape, bh as TxTable, bi as TxWhere, bs as dec, bu as inc, bv as now } from '../endpoint-BSGw1pTu.cjs';
3
3
  import './env.cjs';
4
4
  import '../stack.cjs';
@@ -1,4 +1,4 @@
1
- export { C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, f as EnvServiceDatabase, E as EnvTypedDatabase, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, i as PalbaseExtension, j as PolicyBuilder, k as PolicyCommand, l as PolicyDef, m as PolicyMode, R as RawConstraintDef, n as RowShape, S as SchemaDef, o as SchemaInput, T as TableDef, p as TableInput, q as TxPlan, r as TxTables, s as TypedDB, t as TypedTable, u as TypedTx, v as bigint, w as boolean, x as defineSchema, y as enumType, z as integer, A as isPalbaseExtension, B as jsonb, D as makeTypedDB, G as openai, H as policy, J as raw, K as text, L as timestamp, M as uuid, N as vector } from '../index-BTMYod_l.js';
1
+ export { A as AnyColumn, C as ColumnBuilder, a as ColumnDef, b as ColumnMap, c as ColumnType, d as EXTENSION_DEPENDENCIES, e as EmbeddingModelRef, g as EnvServiceDatabase, E as EnvTypedDatabase, I as InsertShape, O as OnDeleteAction, P as PALBASE_EXTENSIONS, j as PalbaseExtension, k as PolicyBuilder, l as PolicyCommand, m as PolicyDef, n as PolicyMode, R as RawConstraintDef, o as RowShape, S as SchemaDef, T as TABLE_META, p as TableDef, q as TableHandle, r as TableInput, s as TxPlan, t as TxTables, u as TypedDB, v as TypedTable, w as TypedTx, x as bigint, y as boolean, z as defineSchema, B as defineTable, D as enumType, F as installationRef, G as integer, H as isPalbaseExtension, J as jsonb, K as makeTypedDB, M as openai, N as ownedByUser, Q as policy, U as raw, V as text, W as timestamp, X as userRef, Y as uuid, Z as vector } from '../index-B4CcpqLb.js';
2
2
  export { M as Materialized, b1 as Ref, b3 as TxColumnExpr, b4 as TxInsertShape, b6 as TxNow, T as TxPlanBody, b7 as TxPlanError, b8 as TxPlanHandle, b9 as TxPlanOpResult, ba as TxPlanRejection, g as TxPlanResponse, bb as TxRefError, bc as TxRow, bd as TxRows, be as TxSelectOptions, bf as TxSetShape, bh as TxTable, bi as TxWhere, bs as dec, bu as inc, bv as now } from '../endpoint-DMwJjEHQ.js';
3
3
  import './env.js';
4
4
  import '../stack.js';
package/dist/db/index.js CHANGED
@@ -2,22 +2,27 @@ import {
2
2
  EXTENSION_DEPENDENCIES,
3
3
  PALBASE_EXTENSIONS,
4
4
  PolicyBuilder,
5
+ TABLE_META,
5
6
  bigint,
6
7
  boolean,
7
8
  defineSchema,
9
+ defineTable,
8
10
  enumType,
11
+ installationRef,
9
12
  integer,
10
13
  isPalbaseExtension,
11
14
  jsonb,
12
15
  makeTypedDB,
13
16
  openai,
17
+ ownedByUser,
14
18
  policy,
15
19
  raw,
16
20
  text,
17
21
  timestamp,
22
+ userRef,
18
23
  uuid,
19
24
  vector
20
- } from "../chunk-D5CQES25.js";
25
+ } from "../chunk-HBOJLP2Z.js";
21
26
  import {
22
27
  TxPlanError,
23
28
  TxRefError,
@@ -30,24 +35,29 @@ export {
30
35
  EXTENSION_DEPENDENCIES,
31
36
  PALBASE_EXTENSIONS,
32
37
  PolicyBuilder,
38
+ TABLE_META,
33
39
  TxPlanError,
34
40
  TxRefError,
35
41
  bigint,
36
42
  boolean,
37
43
  dec,
38
44
  defineSchema,
45
+ defineTable,
39
46
  enumType,
40
47
  inc,
48
+ installationRef,
41
49
  integer,
42
50
  isPalbaseExtension,
43
51
  jsonb,
44
52
  makeTypedDB,
45
53
  now,
46
54
  openai,
55
+ ownedByUser,
47
56
  policy,
48
57
  raw,
49
58
  text,
50
59
  timestamp,
60
+ userRef,
51
61
  uuid,
52
62
  vector
53
63
  };
@@ -512,13 +512,13 @@ function makeServiceProxy(key) {
512
512
  };
513
513
  return new Proxy({}, handler);
514
514
  }
515
- function makeTablesAccessor(ops) {
516
- const tablesProxy = new Proxy(
515
+ function makeTableProxy(ops, prefix) {
516
+ return new Proxy(
517
517
  {},
518
518
  {
519
519
  get(_t, prop) {
520
520
  if (typeof prop !== "string") return void 0;
521
- const name = prop;
521
+ const name = `${prefix}${prop}`;
522
522
  return {
523
523
  insert: (data) => ops().insert(name, data),
524
524
  update: (id, data) => ops().update(name, id, data),
@@ -535,7 +535,12 @@ function makeTablesAccessor(ops) {
535
535
  }
536
536
  }
537
537
  );
538
- return tablesProxy;
538
+ }
539
+ function makeTablesAccessor(ops) {
540
+ return makeTableProxy(ops, "");
541
+ }
542
+ function makeSchemaAccessor(ops, schema) {
543
+ return { tables: makeTableProxy(ops, `${String(schema)}.`) };
539
544
  }
540
545
  var rawDatabase = makeServiceProxy("Database");
541
546
  function makeTypedSurface(raw) {
@@ -562,6 +567,7 @@ function makeTypedSurface(raw) {
562
567
  // as one on the request's, and each is bound to its own connection.
563
568
  attempt: (fn) => raw.attempt(fn),
564
569
  tables: makeTablesAccessor(() => reco),
570
+ schema: (name) => makeSchemaAccessor(() => reco, name),
565
571
  transaction(fn) {
566
572
  const builder = new TxPlanBuilder();
567
573
  return runTxPlan(raw, makeTxTablesAccessor(builder), builder, fn);
@@ -1125,6 +1131,11 @@ function assertUsableWriteValues(caller, table, cols, data) {
1125
1131
  function quoteIdent(name) {
1126
1132
  return `"${name.replace(/"/g, '""')}"`;
1127
1133
  }
1134
+ function quoteTable(key) {
1135
+ const dot = key.indexOf(".");
1136
+ if (dot === -1) return quoteIdent(key);
1137
+ return `${quoteIdent(key.slice(0, dot))}.${quoteIdent(key.slice(dot + 1))}`;
1138
+ }
1128
1139
  function encodePgArray(value) {
1129
1140
  const element = (x) => {
1130
1141
  if (x === null || x === void 0) return "NULL";
@@ -1197,8 +1208,8 @@ function toVectorLiteral(v) {
1197
1208
  }
1198
1209
  function vectorColumnsOf(schema, table) {
1199
1210
  const out = /* @__PURE__ */ new Set();
1200
- for (const [key, def] of Object.entries(schema.tables ?? {})) {
1201
- if ((def.name ?? key) !== table) continue;
1211
+ const def = tableDefOf(table, schema);
1212
+ if (def) {
1202
1213
  for (const [col, c] of Object.entries(def.columns ?? {})) {
1203
1214
  const d = c !== null && typeof c === "object" && "_def" in c ? c._def : c;
1204
1215
  if (d !== null && typeof d === "object" && d.type === "vector") out.add(col);
@@ -1206,6 +1217,9 @@ function vectorColumnsOf(schema, table) {
1206
1217
  }
1207
1218
  return out;
1208
1219
  }
1220
+ function tableDefOf(key, schema = currentSchema) {
1221
+ return schema.tables?.[key] ?? null;
1222
+ }
1209
1223
  function reviveVectors(row, vectorCols) {
1210
1224
  if (row === null || typeof row !== "object" || vectorCols.size === 0) return row;
1211
1225
  const out = row;
@@ -1217,8 +1231,8 @@ function reviveVectors(row, vectorCols) {
1217
1231
  }
1218
1232
  function transformsOf(schema, table) {
1219
1233
  const out = /* @__PURE__ */ new Map();
1220
- for (const [key, def] of Object.entries(schema.tables ?? {})) {
1221
- if ((def.name ?? key) !== table) continue;
1234
+ const def = tableDefOf(table, schema);
1235
+ if (def) {
1222
1236
  for (const [col, c] of Object.entries(def.columns ?? {})) {
1223
1237
  const d = c !== null && typeof c === "object" && "_def" in c ? c._def : c;
1224
1238
  const t = d?.transform;
@@ -1267,7 +1281,7 @@ var METRIC_OPERATOR = {
1267
1281
  inner_product: "<#>"
1268
1282
  };
1269
1283
  function searchConfigFor(table) {
1270
- const t = currentSchema.tables?.[table];
1284
+ const t = tableDefOf(table);
1271
1285
  if (!t) return null;
1272
1286
  const columns = t.columns ?? {};
1273
1287
  const defOf = (c) => c !== null && typeof c === "object" && "_def" in c ? c._def : c ?? {};
@@ -1404,7 +1418,7 @@ async function fetchFacets(live, table, colSet, facets, where, extraWhere = () =
1404
1418
  };
1405
1419
  const whereSql = compileWhere(table, colSet, where, add) + extraWhere(add);
1406
1420
  const parts = facets.map(
1407
- (col) => `(SELECT '${col.replace(/'/g, "''")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n FROM ${quoteIdent(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`
1421
+ (col) => `(SELECT '${col.replace(/'/g, "''")}' AS f, t.${quoteIdent(col)}::text AS v, count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql} GROUP BY 2 ORDER BY 3 DESC LIMIT 20)`
1408
1422
  );
1409
1423
  const rows = await live.unsafe(parts.join(" UNION ALL "), bind);
1410
1424
  const out = {};
@@ -1430,7 +1444,7 @@ function excludeSql(pk, ids, add) {
1430
1444
  return ` AND t.${quoteIdent(pk)}::text <> ALL(ARRAY[${ids.map((x) => add(x)).join(", ")}])`;
1431
1445
  }
1432
1446
  function schemaColumns(table) {
1433
- const t = Object.values(currentSchema.tables ?? {}).find((x) => x?.name === table);
1447
+ const t = tableDefOf(table);
1434
1448
  const cols = t?.columns ? Object.keys(t.columns) : [];
1435
1449
  return cols.length > 0 ? new Set(cols) : null;
1436
1450
  }
@@ -1591,7 +1605,7 @@ function createOps(tx) {
1591
1605
  const cols = Object.keys(data);
1592
1606
  if (cols.length === 0) throw new Error(`insert into ${table}: no columns given`);
1593
1607
  const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
1594
- const sql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`;
1608
+ const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`;
1595
1609
  const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "insert"));
1596
1610
  const inserted = rows[0];
1597
1611
  if (!inserted) {
@@ -1624,7 +1638,7 @@ function createOps(tx) {
1624
1638
  if (cols.length === 0) throw new Error(`upsert into ${table}: no columns given`);
1625
1639
  if (searchConfigFor(table)?.validity) {
1626
1640
  const ph = cols.map((_, i) => `$${i + 1}`).join(", ");
1627
- const insertSql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${ph}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) WHERE "valid_to" IS NULL DO NOTHING RETURNING *`;
1641
+ const insertSql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${ph}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) WHERE "valid_to" IS NULL DO NOTHING RETURNING *`;
1628
1642
  const live = await at();
1629
1643
  const bindData = asBindParams(table, cols, data, "upsert");
1630
1644
  const first = await live.unsafe(insertSql, bindData);
@@ -1632,7 +1646,7 @@ function createOps(tx) {
1632
1646
  const condSql = conflict.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(" AND ");
1633
1647
  const condBind = conflict.map((c) => data[c]);
1634
1648
  const cur = await live.unsafe(
1635
- `SELECT * FROM ${quoteIdent(table)} WHERE ${condSql} AND "valid_to" IS NULL`,
1649
+ `SELECT * FROM ${quoteTable(table)} WHERE ${condSql} AND "valid_to" IS NULL`,
1636
1650
  condBind
1637
1651
  );
1638
1652
  const old = cur[0];
@@ -1641,7 +1655,7 @@ function createOps(tx) {
1641
1655
  }
1642
1656
  const pk = Object.keys(old).includes("id") ? "id" : Object.keys(old)[0];
1643
1657
  await live.unsafe(
1644
- `UPDATE ${quoteIdent(table)} SET "valid_to" = now() WHERE ${quoteIdent(pk)} = $1 AND "valid_to" IS NULL`,
1658
+ `UPDATE ${quoteTable(table)} SET "valid_to" = now() WHERE ${quoteIdent(pk)} = $1 AND "valid_to" IS NULL`,
1645
1659
  [old[pk]]
1646
1660
  );
1647
1661
  const second = await live.unsafe(insertSql, bindData);
@@ -1650,7 +1664,7 @@ function createOps(tx) {
1650
1664
  }
1651
1665
  const fresh = second[0];
1652
1666
  await live.unsafe(
1653
- `UPDATE ${quoteIdent(table)} SET "superseded_by" = $2 WHERE ${quoteIdent(pk)} = $1`,
1667
+ `UPDATE ${quoteTable(table)} SET "superseded_by" = $2 WHERE ${quoteIdent(pk)} = $1`,
1654
1668
  [old[pk], fresh[pk]]
1655
1669
  );
1656
1670
  return asTableRow(table, second[0]);
@@ -1659,7 +1673,7 @@ function createOps(tx) {
1659
1673
  const conflictSet = new Set(conflict);
1660
1674
  const assignments = cols.filter((c) => !conflictSet.has(c)).map((c) => `${quoteIdent(c)} = EXCLUDED.${quoteIdent(c)}`);
1661
1675
  const action = assignments.length ? `DO UPDATE SET ${assignments.join(", ")}` : `DO UPDATE SET ${quoteIdent(conflict[0])} = EXCLUDED.${quoteIdent(conflict[0])}`;
1662
- const sql = `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
1676
+ const sql = `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) ON CONFLICT (${conflict.map(quoteIdent).join(", ")}) ${action} RETURNING *`;
1663
1677
  const rows = await (await at()).unsafe(sql, asBindParams(table, cols, data, "upsert"));
1664
1678
  const row = rows[0];
1665
1679
  if (!row) {
@@ -1673,12 +1687,12 @@ function createOps(tx) {
1673
1687
  const cols = Object.keys(data);
1674
1688
  if (cols.length === 0) return ops.findById(table, id);
1675
1689
  const assignments = cols.map((c, i) => `${quoteIdent(c)} = $${i + 1}`).join(", ");
1676
- const sql = `UPDATE ${quoteIdent(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;
1690
+ const sql = `UPDATE ${quoteTable(table)} SET ${assignments} WHERE id = $${cols.length + 1} RETURNING *`;
1677
1691
  const rows = await (await at()).unsafe(sql, [...asBindParams(table, cols, data, "update"), id]);
1678
1692
  return rows[0] ? asTableRow(table, rows[0]) : null;
1679
1693
  },
1680
1694
  async delete(table, id) {
1681
- await (await at()).unsafe(`DELETE FROM ${quoteIdent(table)} WHERE id = $1`, [id]);
1695
+ await (await at()).unsafe(`DELETE FROM ${quoteTable(table)} WHERE id = $1`, [id]);
1682
1696
  },
1683
1697
  /**
1684
1698
  * Update every row the filter matches, in ONE statement.
@@ -1721,7 +1735,7 @@ function createOps(tx) {
1721
1735
  const assignments = cols.map((c) => `${quoteIdent(c)} = ${add(asBindParams(table, [c], set, "updateMany")[0])}`).join(", ");
1722
1736
  const whereSql = compileWhere(table, known, where, add, "updateMany");
1723
1737
  assertHasPredicate(whereSql, "updateMany", table);
1724
- const sql = `UPDATE ${quoteIdent(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
1738
+ const sql = `UPDATE ${quoteTable(table)} AS t SET ${assignments} WHERE true${whereSql} RETURNING *`;
1725
1739
  return asTableRows(table, await (await at()).unsafe(sql, params));
1726
1740
  },
1727
1741
  /**
@@ -1738,7 +1752,7 @@ function createOps(tx) {
1738
1752
  const known = schemaColumns(table);
1739
1753
  const whereSql = compileWhere(table, known, where, add, "deleteMany");
1740
1754
  assertHasPredicate(whereSql, "deleteMany", table);
1741
- const sql = `DELETE FROM ${quoteIdent(table)} AS t WHERE true${whereSql} RETURNING 1`;
1755
+ const sql = `DELETE FROM ${quoteTable(table)} AS t WHERE true${whereSql} RETURNING 1`;
1742
1756
  const rows = await (await at()).unsafe(sql, params);
1743
1757
  return rows.length;
1744
1758
  },
@@ -1759,13 +1773,13 @@ function createOps(tx) {
1759
1773
  };
1760
1774
  const known = schemaColumns(table);
1761
1775
  const whereSql = compileWhere(table, known, where, add, "count");
1762
- const sql = `SELECT count(*) AS n FROM ${quoteIdent(table)} t WHERE true${whereSql}`;
1776
+ const sql = `SELECT count(*) AS n FROM ${quoteTable(table)} t WHERE true${whereSql}`;
1763
1777
  const rows = await (await at()).unsafe(sql, params);
1764
1778
  return Number(rows[0]?.n ?? 0);
1765
1779
  },
1766
1780
  async findById(table, id) {
1767
1781
  const rows = await (await at()).unsafe(
1768
- `SELECT * FROM ${quoteIdent(table)} WHERE id = $1`,
1782
+ `SELECT * FROM ${quoteTable(table)} WHERE id = $1`,
1769
1783
  [id]
1770
1784
  );
1771
1785
  return rows[0] ? asTableRow(table, rows[0]) : null;
@@ -1781,7 +1795,7 @@ function createOps(tx) {
1781
1795
  const order = orderClause(table, known, opts.orderBy);
1782
1796
  const limit = limitClause(opts.limit);
1783
1797
  const offset = offsetClause(opts.offset, opts.limit);
1784
- const sql = `SELECT * FROM ${quoteIdent(table)} t WHERE true${whereSql}${order}${limit}${offset}`;
1798
+ const sql = `SELECT * FROM ${quoteTable(table)} t WHERE true${whereSql}${order}${limit}${offset}`;
1785
1799
  return asTableRows(table, await (await at()).unsafe(sql, params));
1786
1800
  },
1787
1801
  /**
@@ -1866,7 +1880,7 @@ function createOps(tx) {
1866
1880
  };
1867
1881
  const userWhereC = compileWhere(table, cfg.colSet, params.where ?? {}, addC);
1868
1882
  const whereC = userWhereC + excludeSql(cfg.pk, excl, addC) + validityFor(addC);
1869
- const parentJoinC = ` JOIN ${quoteIdent(table)} t ON t.${quoteIdent(cfg.pk)} = c.${pidQ} WHERE true${whereC} AND `;
1883
+ const parentJoinC = ` JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = c.${pidQ} WHERE true${whereC} AND `;
1870
1884
  const liveC = await at();
1871
1885
  const K2 = 50;
1872
1886
  const cpool = Math.max(limit * 9, 90);
@@ -1910,7 +1924,7 @@ function createOps(tx) {
1910
1924
  } else {
1911
1925
  fusedSrc = `WITH kw AS (${kwIn}), fused AS (SELECT kw.pid, kw.chunk_seq, (1.0/(${K2} + kw.r))::float8 AS cscore FROM kw)`;
1912
1926
  }
1913
- const inner = `${fusedSrc}, ranked AS (SELECT f.pid, f.chunk_seq, f.cscore, ROW_NUMBER() OVER (PARTITION BY f.pid ORDER BY f.cscore DESC, f.chunk_seq) AS rn FROM fused f), grouped AS (SELECT r.pid, MAX(r.cscore) AS _score, json_agg(json_build_object('content', c.content, 'score', r.cscore, 'chunkSeq', r.chunk_seq, 'charStart', c.char_start) ORDER BY r.cscore DESC, r.chunk_seq) FILTER (WHERE r.rn <= ${bpr}) AS blocks FROM ranked r JOIN ${quoteIdent(ck.table)} c ON c.${pidQ} = r.pid AND c.chunk_seq = r.chunk_seq GROUP BY r.pid) SELECT ${colListC}, ${scoreC}::float8 AS _score, g.blocks AS blocks${kwnCol} FROM grouped g JOIN ${quoteIdent(table)} t ON t.${quoteIdent(cfg.pk)} = g.pid`;
1927
+ const inner = `${fusedSrc}, ranked AS (SELECT f.pid, f.chunk_seq, f.cscore, ROW_NUMBER() OVER (PARTITION BY f.pid ORDER BY f.cscore DESC, f.chunk_seq) AS rn FROM fused f), grouped AS (SELECT r.pid, MAX(r.cscore) AS _score, json_agg(json_build_object('content', c.content, 'score', r.cscore, 'chunkSeq', r.chunk_seq, 'charStart', c.char_start) ORDER BY r.cscore DESC, r.chunk_seq) FILTER (WHERE r.rn <= ${bpr}) AS blocks FROM ranked r JOIN ${quoteIdent(ck.table)} c ON c.${pidQ} = r.pid AND c.chunk_seq = r.chunk_seq GROUP BY r.pid) SELECT ${colListC}, ${scoreC}::float8 AS _score, g.blocks AS blocks${kwnCol} FROM grouped g JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = g.pid`;
1914
1928
  return msC === "" ? `SELECT * FROM (${inner}) q ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}` : `SELECT * FROM (${inner}) q WHERE q._score >= ${msC} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;
1915
1929
  };
1916
1930
  let rowsC = await liveC.unsafe(assembleC(kwC, kwC !== ""), bindC);
@@ -1967,7 +1981,7 @@ function createOps(tx) {
1967
1981
  let exactOrder = "";
1968
1982
  if (userWhere !== "") {
1969
1983
  const probeRows = await live.unsafe(
1970
- `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteIdent(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,
1984
+ `SELECT count(*)::int AS n FROM (SELECT 1 FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} LIMIT ${SELECTIVITY_EXACT_THRESHOLD + 1}) s`,
1971
1985
  bind.slice()
1972
1986
  );
1973
1987
  const n = probeRows?.[0]?.n;
@@ -1976,7 +1990,7 @@ function createOps(tx) {
1976
1990
  }
1977
1991
  }
1978
1992
  const vp = add(toVectorLiteral(qv));
1979
- semSql = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY (t.${quoteIdent(leg.column)} OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrder}) AS r FROM ${quoteIdent(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} ORDER BY r LIMIT ${pool}`;
1993
+ semSql = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY (t.${quoteIdent(leg.column)} OPERATOR(${quoteIdent(sch)}.${op}) ${vp}::${quoteIdent(sch)}.vector)${exactOrder}) AS r FROM ${quoteTable(table)} t WHERE t.${quoteIdent(leg.column)} IS NOT NULL${whereSql} ORDER BY r LIMIT ${pool}`;
1980
1994
  }
1981
1995
  let qpRef = "";
1982
1996
  let qpIdx = -1;
@@ -1985,7 +1999,7 @@ function createOps(tx) {
1985
1999
  const qp = add(qText);
1986
2000
  qpIdx = bind.length - 1;
1987
2001
  qpRef = qp;
1988
- kwSql = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(t.palbase_fts, websearch_to_tsquery('simple', ${qp})) DESC) AS r FROM ${quoteIdent(table)} t WHERE t.palbase_fts @@ websearch_to_tsquery('simple', ${qp})${whereSql} ORDER BY r LIMIT ${pool}`;
2002
+ kwSql = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ts_rank_cd(t.palbase_fts, websearch_to_tsquery('simple', ${qp})) DESC) AS r FROM ${quoteTable(table)} t WHERE t.palbase_fts @@ websearch_to_tsquery('simple', ${qp})${whereSql} ORDER BY r LIMIT ${pool}`;
1989
2003
  }
1990
2004
  const colList = cfg.cols.map((c) => `t.${quoteIdent(c)}`).join(", ");
1991
2005
  const msP = params.minScore === void 0 ? "" : add(params.minScore);
@@ -1996,14 +2010,14 @@ function createOps(tx) {
1996
2010
  let orderScore;
1997
2011
  if (semSql !== "" && kwIn !== "") {
1998
2012
  const score = scoreMul === "" ? "fused._score" : `(fused._score)${scoreMul}`;
1999
- inner = `WITH sem AS (${semSql}), kw AS (${kwIn}), fused AS (SELECT COALESCE(sem.id, kw.id) AS id, (COALESCE(1.0/(${K} + sem.r), 0) + COALESCE(1.0/(${K} + kw.r), 0))::float8 AS _score FROM sem FULL OUTER JOIN kw ON sem.id = kw.id) SELECT ${colList}, ${score} AS _score${hlCol}${kwnCol} FROM fused JOIN ${quoteIdent(table)} t ON t.${quoteIdent(cfg.pk)} = fused.id`;
2013
+ inner = `WITH sem AS (${semSql}), kw AS (${kwIn}), fused AS (SELECT COALESCE(sem.id, kw.id) AS id, (COALESCE(1.0/(${K} + sem.r), 0) + COALESCE(1.0/(${K} + kw.r), 0))::float8 AS _score FROM sem FULL OUTER JOIN kw ON sem.id = kw.id) SELECT ${colList}, ${score} AS _score${hlCol}${kwnCol} FROM fused JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = fused.id`;
2000
2014
  orderScore = scoreMul === "" ? "fused._score" : "_score";
2001
2015
  } else {
2002
2016
  const single = semSql !== "" ? `sem AS (${semSql})` : `kw AS (${kwIn})`;
2003
2017
  const alias = semSql !== "" ? "sem" : "kw";
2004
2018
  const base = `(1.0/(${K} + ${alias}.r))::float8`;
2005
2019
  const score = scoreMul === "" ? base : `(${base})${scoreMul}`;
2006
- inner = `WITH ${single} SELECT ${colList}, ${score} AS _score${hlCol}${semSql !== "" ? "" : kwnCol} FROM ${alias} JOIN ${quoteIdent(table)} t ON t.${quoteIdent(cfg.pk)} = ${alias}.id`;
2020
+ inner = `WITH ${single} SELECT ${colList}, ${score} AS _score${hlCol}${semSql !== "" ? "" : kwnCol} FROM ${alias} JOIN ${quoteTable(table)} t ON t.${quoteIdent(cfg.pk)} = ${alias}.id`;
2007
2021
  orderScore = "_score";
2008
2022
  }
2009
2023
  return msP === "" ? `${inner} ORDER BY ${orderScore} DESC, t.${quoteIdent(cfg.pk)} LIMIT ${limit}` : `SELECT * FROM (${inner}) q WHERE q._score >= ${msP} ORDER BY q._score DESC, q.${quoteIdent(cfg.pk)} LIMIT ${limit}`;
@@ -2012,7 +2026,7 @@ function createOps(tx) {
2012
2026
  if (wantText && kwSql !== "" && (rows.length === 0 || rows[0]._kwn === 0)) {
2013
2027
  const tsch = await trgmSchemaOf(live);
2014
2028
  const expr = ftsExprOf(cfg.ftsCols);
2015
- const trgmKw = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) DESC) AS r FROM ${quoteIdent(table)} t WHERE ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) > 0.3${whereSql} ORDER BY r LIMIT ${pool}`;
2029
+ const trgmKw = `SELECT t.${quoteIdent(cfg.pk)} AS id, ROW_NUMBER() OVER (ORDER BY ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) DESC) AS r FROM ${quoteTable(table)} t WHERE ${quoteIdent(tsch)}.word_similarity(${qpRef}, ${expr}) > 0.3${whereSql} ORDER BY r LIMIT ${pool}`;
2016
2030
  const retryBind = bind.slice();
2017
2031
  if (qpIdx >= 0) retryBind[qpIdx] = params.query;
2018
2032
  rows = await live.unsafe(assemble(trgmKw, false), retryBind);
@@ -2074,7 +2088,7 @@ function createOps(tx) {
2074
2088
  throw new Error(`similar(${table}): tabloda vekt\xF6r kolonu yok \u2014 benzerlik semantik vekt\xF6r ister (FR-022)`);
2075
2089
  }
2076
2090
  const rows = await live.unsafe(
2077
- `SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteIdent(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`,
2091
+ `SELECT t.${quoteIdent(leg.column)} AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} = $1`,
2078
2092
  [id]
2079
2093
  );
2080
2094
  v = rows?.[0]?.v;
@@ -2131,7 +2145,7 @@ function createOps(tx) {
2131
2145
  };
2132
2146
  const avgSel = (ids) => {
2133
2147
  const inList = ids.map((x) => add(x)).join(", ");
2134
- return cfg.chunk !== void 0 ? `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteIdent(cfg.chunk.table)} c WHERE c.${quoteIdent(`parent_${cfg.pk}`)} IN (${inList}) AND c.embedding IS NOT NULL` : `SELECT ${quoteIdent(sch)}.avg(t.${quoteIdent(leg.column)}) AS v FROM ${quoteIdent(table)} t WHERE t.${quoteIdent(cfg.pk)} IN (${inList}) AND t.${quoteIdent(leg.column)} IS NOT NULL`;
2148
+ return cfg.chunk !== void 0 ? `SELECT ${quoteIdent(sch)}.avg(c.embedding) AS v FROM ${quoteIdent(cfg.chunk.table)} c WHERE c.${quoteIdent(`parent_${cfg.pk}`)} IN (${inList}) AND c.embedding IS NOT NULL` : `SELECT ${quoteIdent(sch)}.avg(t.${quoteIdent(leg.column)}) AS v FROM ${quoteTable(table)} t WHERE t.${quoteIdent(cfg.pk)} IN (${inList}) AND t.${quoteIdent(leg.column)} IS NOT NULL`;
2135
2149
  };
2136
2150
  const targetSql = negative.length === 0 ? `WITH pos AS (${avgSel(positive)}) SELECT pos.v AS v, (pos.v IS NULL) AS pos_missing FROM pos` : `WITH pos AS (${avgSel(positive)}), neg AS (${avgSel(negative)}) SELECT (pos.v OPERATOR(${quoteIdent(sch)}.+) (pos.v OPERATOR(${quoteIdent(sch)}.-) neg.v)) AS v, (pos.v IS NULL) AS pos_missing, (neg.v IS NULL) AS neg_missing FROM pos, neg`;
2137
2151
  const rows = await live.unsafe(targetSql, bind);
@@ -2179,7 +2193,7 @@ function createOps(tx) {
2179
2193
  return live.savepoint(async (sp) => {
2180
2194
  const newId = row[cfg.pk] ?? crypto.randomUUID();
2181
2195
  const closed = await sp.unsafe(
2182
- `UPDATE ${quoteIdent(table)} SET "valid_to" = now(), "superseded_by" = $1 WHERE ${quoteIdent(cfg.pk)} = $2 AND "valid_to" IS NULL RETURNING ${quoteIdent(cfg.pk)}`,
2196
+ `UPDATE ${quoteTable(table)} SET "valid_to" = now(), "superseded_by" = $1 WHERE ${quoteIdent(cfg.pk)} = $2 AND "valid_to" IS NULL RETURNING ${quoteIdent(cfg.pk)}`,
2183
2197
  [newId, id]
2184
2198
  );
2185
2199
  if (closed.length === 0) {
@@ -2189,7 +2203,7 @@ function createOps(tx) {
2189
2203
  const cols = Object.keys(data);
2190
2204
  const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
2191
2205
  const rows = await sp.unsafe(
2192
- `INSERT INTO ${quoteIdent(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`,
2206
+ `INSERT INTO ${quoteTable(table)} (${cols.map(quoteIdent).join(", ")}) VALUES (${placeholders}) RETURNING *`,
2193
2207
  asBindParams(table, cols, data, "supersede")
2194
2208
  );
2195
2209
  if (!rows[0]) {
@@ -2261,27 +2275,50 @@ function createOps(tx) {
2261
2275
  return ops;
2262
2276
  }
2263
2277
  var currentSchema = {};
2264
- function setSchema(schema) {
2278
+ function setSchema(schemas) {
2265
2279
  cachedVectorSchema = null;
2266
2280
  cachedTrgmSchema = null;
2267
- const s = schema;
2268
- currentSchema = (s && "default" in s ? s.default : s) ?? {};
2281
+ const tables = {};
2282
+ for (const entry of schemas) {
2283
+ const mod = entry;
2284
+ const def = (mod && "default" in mod ? mod.default : mod) ?? {};
2285
+ const schemaName = def.name ?? "public";
2286
+ for (const [key, table] of Object.entries(def.tables ?? {})) {
2287
+ tables[qualifiedTableKey(schemaName, table.name ?? key)] = table;
2288
+ }
2289
+ }
2290
+ currentSchema = { tables };
2291
+ }
2292
+ function qualifiedTableKey(schema, table) {
2293
+ return schema === "" || schema === "public" ? table : `${schema}.${table}`;
2269
2294
  }
2270
2295
  function withTables(ops, schema = currentSchema) {
2296
+ const bind = (key) => ({
2297
+ insert: (data) => ops.insert(key, data),
2298
+ update: (id, data) => ops.update(key, id, data),
2299
+ delete: (id) => ops.delete(key, id),
2300
+ findById: (id) => ops.findById(key, id),
2301
+ findMany: (query, opts) => ops.findMany(key, query ?? {}, opts),
2302
+ upsert: (data, opts) => ops.upsert(key, data, opts)
2303
+ });
2271
2304
  const tables = {};
2272
2305
  for (const key of Object.keys(schema.tables ?? {})) {
2273
- const name = schema.tables?.[key]?.name ?? key;
2274
- tables[key] = {
2275
- insert: (data) => ops.insert(name, data),
2276
- update: (id, data) => ops.update(name, id, data),
2277
- delete: (id) => ops.delete(name, id),
2278
- findById: (id) => ops.findById(name, id),
2279
- findMany: (query, opts) => ops.findMany(name, query ?? {}, opts),
2280
- upsert: (data, opts) => ops.upsert(name, data, opts)
2281
- };
2306
+ if (!key.includes(".")) tables[key] = bind(key);
2282
2307
  }
2308
+ const schemaOf = (name) => {
2309
+ const out = {};
2310
+ const prefix = `${name}.`;
2311
+ for (const key of Object.keys(schema.tables ?? {})) {
2312
+ if (name === "public") {
2313
+ if (!key.includes(".")) out[key] = bind(key);
2314
+ } else if (key.startsWith(prefix)) {
2315
+ out[key.slice(prefix.length)] = bind(key);
2316
+ }
2317
+ }
2318
+ return { tables: out };
2319
+ };
2283
2320
  const base = /* @__PURE__ */ Object.create(null);
2284
- return Object.assign(base, ops, { tables });
2321
+ return Object.assign(base, ops, { tables, schema: schemaOf });
2285
2322
  }
2286
2323
  var SERVICE_LOCK_TIMEOUT = "5s";
2287
2324
  function isAbortedTransaction(e) {
@@ -2573,6 +2610,7 @@ function assertZeroArgConstructor(Ctrl, kind) {
2573
2610
  }
2574
2611
 
2575
2612
  // src/engine/router.ts
2613
+ var ROOM_META = /* @__PURE__ */ Symbol.for("palbase.backend.room");
2576
2614
  var CONTROLLER_META = /* @__PURE__ */ Symbol.for("palbase.backend.controllerMeta");
2577
2615
  function toSegments(path) {
2578
2616
  return path.split("/").filter(Boolean).map((s) => s.startsWith("{") && s.endsWith("}") ? `:${s.slice(1, -1)}` : s);
@@ -2580,6 +2618,7 @@ function toSegments(path) {
2580
2618
  function buildRouteTable(controllers) {
2581
2619
  const table = [];
2582
2620
  for (const Ctrl of controllers) {
2621
+ if (Ctrl[ROOM_META] !== void 0) continue;
2583
2622
  const ctor = Ctrl;
2584
2623
  const meta = ctor[CONTROLLER_META];
2585
2624
  const basePath = meta?.basePath ?? "";
@@ -2838,7 +2877,7 @@ async function defaultSqlDriver(config) {
2838
2877
  var AUTHOR_ANSWERED = /* @__PURE__ */ new Set([400, 401, 403, 404, 409, 429]);
2839
2878
  async function createApp(opts) {
2840
2879
  const { config, controllers } = opts;
2841
- setSchema(opts.schema ?? {});
2880
+ setSchema(opts.schemas ?? []);
2842
2881
  setSecretReader(opts.secretReader ?? null);
2843
2882
  const routes = buildRouteTable(controllers);
2844
2883
  if (routes.length === 0) {