@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
@@ -1,4 +1,5 @@
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-vwHoS0l2.js';
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, f as TxPlanResponse, bb as TxRefError, bc as TxRow, bd as TxRows, be as TxSelectOptions, bf as TxSetShape, bh as TxTable, bi as TxWhere, br as dec, bt as inc, bu as now } from '../endpoint-BVT6jcVW.js';
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-CwAJ7HEe.js';
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, br as dec, bt as inc, bu as now } from '../endpoint-CVWXh6oG.js';
3
3
  import './env.js';
4
+ import '../stack.js';
4
5
  import 'zod';
package/dist/db/index.js CHANGED
@@ -17,14 +17,14 @@ import {
17
17
  timestamp,
18
18
  uuid,
19
19
  vector
20
- } from "../chunk-I3ON7MYF.js";
20
+ } from "../chunk-PY7YJDCT.js";
21
21
  import {
22
22
  TxPlanError,
23
23
  TxRefError,
24
24
  dec,
25
25
  inc,
26
26
  now
27
- } from "../chunk-W5ODXPY3.js";
27
+ } from "../chunk-NS5V43YQ.js";
28
28
  import "../chunk-7D4SUZUM.js";
29
29
  export {
30
30
  EXTENSION_DEPENDENCIES,
@@ -1,4 +1,5 @@
1
1
  import { ZodSchema, z } from 'zod';
2
+ import { PalbaseFlagKey, PalbaseSecretName } from './stack.js';
2
3
 
3
4
  /** Supported HTTP methods for endpoints. */
4
5
  type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
@@ -141,7 +142,7 @@ declare function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler;
141
142
  * # Wire contract
142
143
  *
143
144
  * The JSON this file emits is consumed by
144
- * `modules/backend/internal/management/tx_program.go`. That decoder rejects
145
+ * the plan executor in `engine/db.ts`. That executor rejects
145
146
  * unknown fields at every level, so an op carries EXACTLY the fields its kind
146
147
  * takes. Everything here that looks like a needless restriction is one of the
147
148
  * server's rules made visible early:
@@ -205,7 +206,9 @@ interface TxWireGuard {
205
206
  /** One operation in the wire plan. Fields are omitted, never null: the decoder
206
207
  * rejects a field that does not belong to the op's kind. */
207
208
  interface TxWireOp {
208
- op: "insert" | "insertMany" | "update" | "delete" | "select";
209
+ /** upsert only: the columns Postgres matches on. */
210
+ onConflict?: readonly string[];
211
+ op: "insert" | "insertMany" | "upsert" | "update" | "delete" | "select";
209
212
  table: string;
210
213
  values?: Record<string, TxWireValue>;
211
214
  rows?: Record<string, TxWireValue>[];
@@ -387,6 +390,17 @@ interface TxTable<Row, Insert> {
387
390
  * An empty list writes nothing and sends nothing.
388
391
  */
389
392
  insertMany(rows: readonly TxInsertShape<Insert>[]): TxRows<Row>;
393
+ /**
394
+ * Insert the row, or update it when it collides on `onConflict` — inside the
395
+ * plan's savepoint, with the same meaning `tables.<t>.upsert()` has outside it.
396
+ *
397
+ * It is an operation because the alternative is not writable here: a failed
398
+ * insert aborts the whole transaction, so "try, then fall back" cannot be two
399
+ * plan steps.
400
+ */
401
+ upsert(values: TxInsertShape<Insert>, options: {
402
+ onConflict: readonly Extract<keyof Row, string>[];
403
+ }): TxRows<Row>;
390
404
  /**
391
405
  * Update every row matching `where`. The filter comes first because it is the
392
406
  * dangerous half: an update whose `where` you got wrong rewrites rows you
@@ -1471,11 +1485,11 @@ interface PalbaseFlagsServiceClient {
1471
1485
  * Set (or replace) a single feature-flag override for one user. The override
1472
1486
  * shadows the project (system) default for that user until cleared.
1473
1487
  */
1474
- setOverrideForUser(userId: string, key: string, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1488
+ setOverrideForUser(userId: string, key: PalbaseFlagKey, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1475
1489
  /** Set multiple overrides for one user in a single call. */
1476
1490
  setOverridesForUser(userId: string, values: Record<string, PalbaseFlagValue>): Promise<PalbaseResult<PalbaseSetOverridesResult>>;
1477
1491
  /** Clear one override for a user, restoring the project (system) default. */
1478
- clearOverrideForUser(userId: string, key: string): Promise<PalbaseResult<PalbaseClearOverrideResult>>;
1492
+ clearOverrideForUser(userId: string, key: PalbaseFlagKey): Promise<PalbaseResult<PalbaseClearOverrideResult>>;
1479
1493
  /** Clear all overrides for a user, restoring project (system) defaults. */
1480
1494
  clearAllOverridesForUser(userId: string): Promise<PalbaseResult<PalbaseClearAllOverridesResult>>;
1481
1495
  /** Apply override writes across many users in one request (max 1000 ops). */
@@ -1499,9 +1513,9 @@ interface PalbaseFlagsServiceClient {
1499
1513
  */
1500
1514
  interface PalbaseFlagsClient {
1501
1515
  /** Is a flag enabled for the given context? */
1502
- isEnabled(flagName: string, context?: PalbaseFlagContext): Promise<PalbaseResult<boolean>>;
1516
+ isEnabled(flagName: PalbaseFlagKey, context?: PalbaseFlagContext): Promise<PalbaseResult<boolean>>;
1503
1517
  /** Get the active variant of a multivariate flag. */
1504
- getVariant(flagName: string, context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagVariant>>;
1518
+ getVariant(flagName: PalbaseFlagKey, context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagVariant>>;
1505
1519
  /** Get all flags for the project. */
1506
1520
  getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>>;
1507
1521
  /**
@@ -1518,7 +1532,7 @@ interface PalbaseFlagsClient {
1518
1532
  * `Documents.doc(...)` — declared and never implemented — seen from the other
1519
1533
  * side, and moving the implementation into this package is what surfaced it.
1520
1534
  */
1521
- get(flagName: string, defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext, maybeContext?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagValue>>;
1535
+ get(flagName: PalbaseFlagKey, defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext, maybeContext?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagValue>>;
1522
1536
  /**
1523
1537
  * Set (or replace) a single feature-flag override for the CURRENT REQUEST
1524
1538
  * USER. No userId argument — the override is bound to the signed-in user the
@@ -1533,7 +1547,7 @@ interface PalbaseFlagsClient {
1533
1547
  * @example
1534
1548
  * await Flags.setOverride("new_checkout", true);
1535
1549
  */
1536
- setOverride(key: string, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1550
+ setOverride(key: PalbaseFlagKey, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1537
1551
  /**
1538
1552
  * Return the cross-user admin write surface ({@link PalbaseFlagsServiceClient}).
1539
1553
  * Use sparingly and explicitly — the default `Flags.setOverride(...)` path is
@@ -1545,6 +1559,13 @@ interface PalbaseFlagsClient {
1545
1559
  /**
1546
1560
  * Realtime broadcast surface (backend handler → subscribed clients).
1547
1561
  *
1562
+ * **Every channel must be DECLARED, or the join is refused.** Channel names are
1563
+ * not free text: `channels.ts` at the project root publishes which names exist
1564
+ * and who may subscribe, publish, or write state, and a client joining a name no
1565
+ * declaration matches is rejected without ever reaching your code. Declare with
1566
+ * `ownerOnly()`, `publicChannel()`, or a custom `authorize(ctx)` — see
1567
+ * {@link defineChannels}. Broadcasting to an undeclared channel reaches nobody.
1568
+ *
1548
1569
  * Backend-side this is BROADCAST-ONLY: a handler pushes an event to a channel
1549
1570
  * and every client subscribed to that channel (via the client SDK's
1550
1571
  * `pb.realtime.channel(...).on(...)`) receives it. There is no `subscribe()` on
@@ -1553,9 +1574,10 @@ interface PalbaseFlagsClient {
1553
1574
  * once the broadcast is accepted (or with an `error` if it could not be sent),
1554
1575
  * but it never blocks the handler waiting on subscribers.
1555
1576
  *
1556
- * Channel naming is app-defined and arbitrary (e.g. `"room:42"`, `"orders"`).
1557
- * The Palbase-managed `flags:<ref>` channels are internal author channels for
1558
- * your own features.
1577
+ * Channel names are yours to choose (e.g. `"room:42"`, `"orders"`) but not yours
1578
+ * to leave undeclared: each must match a pattern in `channels.ts`, which is where
1579
+ * `"room:{roomId}"` is authorized. The Palbase-managed `flags:<ref>` channels are
1580
+ * internal — author channels for your own features.
1559
1581
  *
1560
1582
  * @example
1561
1583
  * // Notify everyone in a chat room that a message landed:
@@ -1815,9 +1837,36 @@ interface RateLimitConfig {
1815
1837
  /** The six raw string-keyed DB operations shared by `DBClient` and the
1816
1838
  * transaction-scoped client. */
1817
1839
  interface DBOps {
1818
- /** Run a read-only SQL query (executes in a READ ONLY transaction). */
1840
+ /**
1841
+ * Run SQL on the REQUEST'S OWN transaction.
1842
+ *
1843
+ * This is **not** read-only. Nothing marks that transaction `READ ONLY`, so a
1844
+ * write passed here executes and commits with the request — a plain `UPDATE`, a
1845
+ * write hidden in a CTE, or a function that writes. What stands between a
1846
+ * statement and your data is RLS and the role the request runs as, exactly as
1847
+ * for every other operation on this client.
1848
+ *
1849
+ * `INSERT … ON CONFLICT DO UPDATE` therefore works here; `tables.<t>.upsert()`
1850
+ * is the same thing with types. Array parameters are encoded as Postgres array
1851
+ * literals, so `= ANY($1::uuid[])` takes a plain JS array.
1852
+ *
1853
+ * This comment used to claim a `READ ONLY` transaction. It was wrong, and the
1854
+ * cost was measured: a tenant read it, concluded an upsert was impossible from
1855
+ * here, abandoned `ON CONFLICT` and wrote a database trigger instead.
1856
+ */
1819
1857
  query(sql: string, params?: unknown[]): Promise<Record<string, unknown>[]>;
1820
1858
  insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
1859
+ /**
1860
+ * Insert the row, or update it when it collides on `onConflict` — one
1861
+ * statement, so two concurrent callers cannot both lose.
1862
+ *
1863
+ * Read-then-write cannot be made safe here by catching the unique violation: a
1864
+ * request runs in one transaction, so the failed insert aborts it and every
1865
+ * later statement answers `current transaction is aborted`.
1866
+ */
1867
+ upsert(table: string, data: Record<string, unknown>, opts: {
1868
+ onConflict: readonly string[];
1869
+ }): Promise<Record<string, unknown>>;
1821
1870
  /**
1822
1871
  * Update the row with the given id and resolve to the updated row, or `null`
1823
1872
  * if no row matched (the id is absent, or the row is hidden by RLS). This is
@@ -1835,8 +1884,70 @@ interface DBOps {
1835
1884
  limit?: number;
1836
1885
  using?: string;
1837
1886
  mode?: "hybrid" | "text" | "vector";
1887
+ /** Nihai (RRF-sonrası) skor alt eşiği (FR-001). */
1888
+ minScore?: number;
1889
+ /** RRF-sonrası üstel tazelik çürümesi (FR-004; feed/haber düğmesi). */
1890
+ recency?: {
1891
+ field: string;
1892
+ halfLife: string;
1893
+ };
1894
+ /** Chunk-modunda satır başına en iyi blok sayısı (FR-015). */
1895
+ blocksPerRow?: number;
1896
+ /** Kolon başına top-20 değer sayacı — dönüş dizisinin `_facets` özelliği (FR-027). */
1897
+ facets?: string[];
1898
+ /** Satır-modunda ts_headline vurgusu: satırlara `_highlight` (FR-025; chunk-modda no-op). */
1899
+ highlight?: boolean;
1900
+ /** Validity'li tabloda zaman penceresi: vars. yalnız güncel; "all" tümü; {asOf} o an (FR-029). */
1901
+ validity?: "all" | {
1902
+ asOf: string;
1903
+ };
1904
+ /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sınırlı çarpan, dış servissiz. */
1905
+ boost?: {
1906
+ field: string;
1907
+ weight: number;
1908
+ };
1909
+ }): Promise<Record<string, unknown>[]>;
1910
+ /** Validity'li tabloda satırın yeni versiyonu — eski kapanır (valid_to/superseded_by),
1911
+ * yenisi eklenir; TEK savepoint, dönüş yeni satır (FR-029, C-9). */
1912
+ supersede(table: string, id: string, row: Record<string, unknown>): Promise<Record<string, unknown>>;
1913
+ findMany(table: string, query?: Record<string, unknown>, opts?: {
1914
+ orderBy?: {
1915
+ column: string;
1916
+ direction?: "asc" | "desc";
1917
+ };
1918
+ limit?: number;
1919
+ }): Promise<Record<string, unknown>[]>;
1920
+ /** "Bu satıra benzer satırlar" (FR-022) — satır-modunda kolon vektörüyle,
1921
+ * chunk-modunda chunk-ortalamasıyla; kendisi hariç. */
1922
+ similar(table: string, id: string, opts?: {
1923
+ limit?: number;
1924
+ where?: Record<string, unknown>;
1925
+ minScore?: number;
1926
+ blocksPerRow?: number;
1927
+ validity?: "all" | {
1928
+ asOf: string;
1929
+ };
1930
+ boost?: {
1931
+ field: string;
1932
+ weight: number;
1933
+ };
1934
+ }): Promise<Record<string, unknown>[]>;
1935
+ /** Çok-örnekli öneri (FR-023): avg(pos) + (avg(pos) − avg(neg)); positive'ler sonuç dışı. */
1936
+ recommend(table: string, opts: {
1937
+ positive: string[];
1938
+ negative?: string[];
1939
+ limit?: number;
1940
+ where?: Record<string, unknown>;
1941
+ minScore?: number;
1942
+ blocksPerRow?: number;
1943
+ validity?: "all" | {
1944
+ asOf: string;
1945
+ };
1946
+ boost?: {
1947
+ field: string;
1948
+ weight: number;
1949
+ };
1838
1950
  }): Promise<Record<string, unknown>[]>;
1839
- findMany(table: string, query?: Record<string, unknown>): Promise<Record<string, unknown>[]>;
1840
1951
  }
1841
1952
  /** Database client interface injected into endpoint context. */
1842
1953
  interface DBClient extends DBOps {
@@ -1856,6 +1967,14 @@ interface DBClient extends DBOps {
1856
1967
  * `.expectOne(…)`; without it a declared expectation degrades to a generic 409.
1857
1968
  */
1858
1969
  txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;
1970
+ /**
1971
+ * Run `fn` inside a SAVEPOINT on this request's transaction, so a failure in
1972
+ * it rolls back only what `fn`'s handle wrote.
1973
+ *
1974
+ * The handle is a PARAMETER on purpose: an ambient swap would capture writes
1975
+ * a concurrent `Promise.all` branch made outside the boundary.
1976
+ */
1977
+ attempt<T>(fn: (tx: DBOps) => Promise<T>): Promise<T>;
1859
1978
  /**
1860
1979
  * Return a sibling DB client that bypasses Row-Level Security by running as
1861
1980
  * the `service_role` (BYPASSRLS). Use sparingly and explicitly — the default
@@ -1893,7 +2012,20 @@ interface Logger {
1893
2012
  * a restart and a hot path pays a map lookup.
1894
2013
  */
1895
2014
  interface SecretsService {
1896
- get(name: string): Promise<string | null>;
2015
+ /**
2016
+ * A secret's value, or `null` when this backend's vault holds no value under
2017
+ * that name.
2018
+ *
2019
+ * The name is a `PalbaseSecretName`, not a `string`: it comes from the
2020
+ * generated `palbase-stack.d.ts`, so a secret the stack does not hold cannot
2021
+ * be spelled here at all. THE GATE IS THE COMPILER.
2022
+ *
2023
+ * That gate replaced a declaration. `config/secrets.ts` used to restate, in
2024
+ * the repo, names the vault already held, and the push compared the two lists
2025
+ * — a check that only ran at deploy, and only if the author remembered to
2026
+ * declare. The type runs on every keystroke and cannot be forgotten.
2027
+ */
2028
+ get(name: PalbaseSecretName): Promise<string | null>;
1897
2029
  }
1898
2030
  interface CacheClient {
1899
2031
  /** Read a value. Returns `null` on a cache miss. */
@@ -2143,4 +2275,4 @@ type Middleware = (ctx: MiddlewareContext, next: () => Promise<void>) => Promise
2143
2275
  */
2144
2276
  type AuthSpec = boolean | Partial<AuthConfig>;
2145
2277
 
2146
- export { type PalbaseCreateLinkParams as $, type AuthSpec as A, BadRequest as B, type CacheClient as C, type DBClient as D, type ErrorDef as E, type FileContext as F, type PalbaseAttestiOSParams as G, HttpError as H, type PalbaseAttestiOSResult as I, type PalbaseAuthClient as J, type PalbaseBatchOverrideOperation as K, type Logger as L, type Materialized as M, NotFound as N, type PalbaseBatchSetOverridesResult as O, type PalbaseDocsClient as P, type PalbaseBindDeviceParams as Q, type RateLimitConfig as R, type SecretsService as S, type TxPlanBody as T, type PalbaseClearAllOverridesResult as U, type PalbaseClearOverrideResult as V, type PalbaseCohortQueryInput as W, type PalbaseCohortResult as X, type PalbaseCollectionRef as Y, type PalbaseCountQueryInput as Z, type PalbaseCountResult as _, type PalbaseFlagsClient as a, type PalbaseVerifyRequestSignatureParams as a$, type PalbaseDeviceInfo as a0, type PalbaseDeviceTokenView as a1, type PalbaseDocumentRef as a2, type PalbaseDocumentSnapshot as a3, type PalbaseEmailClient as a4, type PalbaseEmailSendParams as a5, type PalbaseEmailSendResponse as a6, type PalbaseEventNamesResult as a7, type PalbaseEventsQueryInput as a8, type PalbaseEventsResult as a9, type PalbaseMatchParams as aA, type PalbaseMultiChannelResponse as aB, type PalbaseOverviewResult as aC, type PalbasePreferences as aD, type PalbasePreferencesClient as aE, type PalbasePushClient as aF, type PalbasePushSendParams as aG, type PalbasePushSendResponse as aH, type PalbaseQrCodeOptions as aI, type PalbaseQuerySnapshot as aJ, type PalbaseRegisterDeviceParams as aK, type PalbaseRetentionQueryInput as aL, type PalbaseRetentionResult as aM, type PalbaseSession as aN, type PalbaseSetOverrideResult as aO, type PalbaseSetOverridesResult as aP, type PalbaseSignedUrlResponse as aQ, type PalbaseSmsClient as aR, type PalbaseSmsSendParams as aS, type PalbaseSmsSendResponse as aT, type PalbaseTransformOptions as aU, type PalbaseUpdateLinkParams as aV, type PalbaseUploadOptions as aW, type PalbaseUser as aX, type PalbaseUserDetailResult as aY, type PalbaseUsersQueryInput as aZ, type PalbaseUsersResult as a_, type PalbaseFileObject as aa, type PalbaseFlag as ab, type PalbaseFlagContext as ac, type PalbaseFlagSource as ad, type PalbaseFlagValue as ae, type PalbaseFlagVariant as af, type PalbaseFlagsServiceClient as ag, type PalbaseFunctionsClient as ah, type PalbaseFunnelQueryInput as ai, type PalbaseFunnelResult as aj, type PalbaseIdentifyTraits as ak, type PalbaseInboxClient as al, type PalbaseInboxListOptions as am, type PalbaseInboxListResult as an, type PalbaseInboxMessage as ao, type PalbaseInboxSendParams as ap, type PalbaseInboxSendResponse as aq, type PalbaseInitialLink as ar, type PalbaseInvokeOptions as as, type PalbaseLink as at, type PalbaseLinkAnalytics as au, type PalbaseLinkDetails as av, type PalbaseLinksClient as aw, type PalbaseListLinksOptions as ax, type PalbaseListLinksResult as ay, type PalbaseListOptions as az, type PalbaseNotificationsClient as b, type PalbaseWhereOperator as b0, type Ref as b1, TooManyRequests as b2, type TxColumnExpr as b3, type TxInsertShape as b4, type TxInsertValue as b5, type TxNow as b6, TxPlanError as b7, type TxPlanHandle as b8, type TxPlanOpResult as b9, type TxPlanRejection as ba, TxRefError as bb, type TxRow as bc, type TxRows as bd, type TxSelectOptions as be, type TxSetShape as bf, type TxSetValue as bg, type TxTable as bh, type TxWhere as bi, type TxWireExpr as bj, type TxWireGuard as bk, type TxWireOp as bl, type TxWireRef as bm, type TxWireValue as bn, Unauthorized as bo, type User as bp, type VerifiedDevice as bq, dec as br, defineMiddleware as bs, inc as bt, now as bu, type PalbaseRealtimeClient as c, type PalbaseStorageClient as d, type PalbaseBucketClient as e, type TxPlanResponse as f, type PalbaseResult as g, type AuthConfig as h, type ClientInfo as i, Conflict as j, type DBOps as k, type ErrorMap as l, type ErrorThrowers as m, Forbidden as n, type HttpMethod as o, type Middleware as p, type MiddlewareContext as q, type MiddlewareHandler as r, type PBRequest as s, PalError as t, type PalbaseAnalyticsClient as u, type PalbaseAnalyticsManagementNamespace as v, type PalbaseAnalyticsProperties as w, type PalbaseAnalyticsQueryNamespace as x, type PalbaseAttestAndroidParams as y, type PalbaseAttestAndroidResult as z };
2278
+ export { type PalbaseCreateLinkParams as $, type AuthSpec as A, BadRequest as B, type CacheClient as C, type DBClient as D, type ErrorDef as E, type FileContext as F, type PalbaseAttestiOSParams as G, HttpError as H, type PalbaseAttestiOSResult as I, type PalbaseAuthClient as J, type PalbaseBatchOverrideOperation as K, type Logger as L, type Materialized as M, NotFound as N, type PalbaseBatchSetOverridesResult as O, type PalbaseDocsClient as P, type PalbaseBindDeviceParams as Q, type RateLimitConfig as R, type SecretsService as S, type TxPlanBody as T, type PalbaseClearAllOverridesResult as U, type PalbaseClearOverrideResult as V, type PalbaseCohortQueryInput as W, type PalbaseCohortResult as X, type PalbaseCollectionRef as Y, type PalbaseCountQueryInput as Z, type PalbaseCountResult as _, type PalbaseFlagsClient as a, type PalbaseVerifyRequestSignatureParams as a$, type PalbaseDeviceInfo as a0, type PalbaseDeviceTokenView as a1, type PalbaseDocumentRef as a2, type PalbaseDocumentSnapshot as a3, type PalbaseEmailClient as a4, type PalbaseEmailSendParams as a5, type PalbaseEmailSendResponse as a6, type PalbaseEventNamesResult as a7, type PalbaseEventsQueryInput as a8, type PalbaseEventsResult as a9, type PalbaseMatchParams as aA, type PalbaseMultiChannelResponse as aB, type PalbaseOverviewResult as aC, type PalbasePreferences as aD, type PalbasePreferencesClient as aE, type PalbasePushClient as aF, type PalbasePushSendParams as aG, type PalbasePushSendResponse as aH, type PalbaseQrCodeOptions as aI, type PalbaseQuerySnapshot as aJ, type PalbaseRegisterDeviceParams as aK, type PalbaseRetentionQueryInput as aL, type PalbaseRetentionResult as aM, type PalbaseSession as aN, type PalbaseSetOverrideResult as aO, type PalbaseSetOverridesResult as aP, type PalbaseSignedUrlResponse as aQ, type PalbaseSmsClient as aR, type PalbaseSmsSendParams as aS, type PalbaseSmsSendResponse as aT, type PalbaseTransformOptions as aU, type PalbaseUpdateLinkParams as aV, type PalbaseUploadOptions as aW, type PalbaseUser as aX, type PalbaseUserDetailResult as aY, type PalbaseUsersQueryInput as aZ, type PalbaseUsersResult as a_, type PalbaseFileObject as aa, type PalbaseFlag as ab, type PalbaseFlagContext as ac, type PalbaseFlagSource as ad, type PalbaseFlagValue as ae, type PalbaseFlagVariant as af, type PalbaseFlagsServiceClient as ag, type PalbaseFunctionsClient as ah, type PalbaseFunnelQueryInput as ai, type PalbaseFunnelResult as aj, type PalbaseIdentifyTraits as ak, type PalbaseInboxClient as al, type PalbaseInboxListOptions as am, type PalbaseInboxListResult as an, type PalbaseInboxMessage as ao, type PalbaseInboxSendParams as ap, type PalbaseInboxSendResponse as aq, type PalbaseInitialLink as ar, type PalbaseInvokeOptions as as, type PalbaseLink as at, type PalbaseLinkAnalytics as au, type PalbaseLinkDetails as av, type PalbaseLinksClient as aw, type PalbaseListLinksOptions as ax, type PalbaseListLinksResult as ay, type PalbaseListOptions as az, type PalbaseNotificationsClient as b, type PalbaseWhereOperator as b0, type Ref as b1, TooManyRequests as b2, type TxColumnExpr as b3, type TxInsertShape as b4, type TxInsertValue as b5, type TxNow as b6, TxPlanError as b7, type TxPlanHandle as b8, type TxPlanOpResult as b9, type TxPlanRejection as ba, TxRefError as bb, type TxRow as bc, type TxRows as bd, type TxSelectOptions as be, type TxSetShape as bf, type TxSetValue as bg, type TxTable as bh, type TxWhere as bi, type TxWireExpr as bj, type TxWireGuard as bk, type TxWireOp as bl, type TxWireRef as bm, type TxWireValue as bn, Unauthorized as bo, type User as bp, type VerifiedDevice as bq, dec as br, defineMiddleware as bs, inc as bt, now as bu, type PalbaseRealtimeClient as c, type PalbaseStorageClient as d, type PalbaseBucketClient as e, type DBOps as f, type TxPlanResponse as g, type PalbaseResult as h, type AuthConfig as i, type ClientInfo as j, Conflict as k, type ErrorMap as l, type ErrorThrowers as m, Forbidden as n, type HttpMethod as o, type Middleware as p, type MiddlewareContext as q, type MiddlewareHandler as r, type PBRequest as s, PalError as t, type PalbaseAnalyticsClient as u, type PalbaseAnalyticsManagementNamespace as v, type PalbaseAnalyticsProperties as w, type PalbaseAnalyticsQueryNamespace as x, type PalbaseAttestAndroidParams as y, type PalbaseAttestAndroidResult as z };
@@ -1,4 +1,5 @@
1
1
  import { ZodSchema, z } from 'zod';
2
+ import { PalbaseFlagKey, PalbaseSecretName } from './stack.cjs';
2
3
 
3
4
  /** Supported HTTP methods for endpoints. */
4
5
  type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
@@ -141,7 +142,7 @@ declare function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler;
141
142
  * # Wire contract
142
143
  *
143
144
  * The JSON this file emits is consumed by
144
- * `modules/backend/internal/management/tx_program.go`. That decoder rejects
145
+ * the plan executor in `engine/db.ts`. That executor rejects
145
146
  * unknown fields at every level, so an op carries EXACTLY the fields its kind
146
147
  * takes. Everything here that looks like a needless restriction is one of the
147
148
  * server's rules made visible early:
@@ -205,7 +206,9 @@ interface TxWireGuard {
205
206
  /** One operation in the wire plan. Fields are omitted, never null: the decoder
206
207
  * rejects a field that does not belong to the op's kind. */
207
208
  interface TxWireOp {
208
- op: "insert" | "insertMany" | "update" | "delete" | "select";
209
+ /** upsert only: the columns Postgres matches on. */
210
+ onConflict?: readonly string[];
211
+ op: "insert" | "insertMany" | "upsert" | "update" | "delete" | "select";
209
212
  table: string;
210
213
  values?: Record<string, TxWireValue>;
211
214
  rows?: Record<string, TxWireValue>[];
@@ -387,6 +390,17 @@ interface TxTable<Row, Insert> {
387
390
  * An empty list writes nothing and sends nothing.
388
391
  */
389
392
  insertMany(rows: readonly TxInsertShape<Insert>[]): TxRows<Row>;
393
+ /**
394
+ * Insert the row, or update it when it collides on `onConflict` — inside the
395
+ * plan's savepoint, with the same meaning `tables.<t>.upsert()` has outside it.
396
+ *
397
+ * It is an operation because the alternative is not writable here: a failed
398
+ * insert aborts the whole transaction, so "try, then fall back" cannot be two
399
+ * plan steps.
400
+ */
401
+ upsert(values: TxInsertShape<Insert>, options: {
402
+ onConflict: readonly Extract<keyof Row, string>[];
403
+ }): TxRows<Row>;
390
404
  /**
391
405
  * Update every row matching `where`. The filter comes first because it is the
392
406
  * dangerous half: an update whose `where` you got wrong rewrites rows you
@@ -1471,11 +1485,11 @@ interface PalbaseFlagsServiceClient {
1471
1485
  * Set (or replace) a single feature-flag override for one user. The override
1472
1486
  * shadows the project (system) default for that user until cleared.
1473
1487
  */
1474
- setOverrideForUser(userId: string, key: string, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1488
+ setOverrideForUser(userId: string, key: PalbaseFlagKey, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1475
1489
  /** Set multiple overrides for one user in a single call. */
1476
1490
  setOverridesForUser(userId: string, values: Record<string, PalbaseFlagValue>): Promise<PalbaseResult<PalbaseSetOverridesResult>>;
1477
1491
  /** Clear one override for a user, restoring the project (system) default. */
1478
- clearOverrideForUser(userId: string, key: string): Promise<PalbaseResult<PalbaseClearOverrideResult>>;
1492
+ clearOverrideForUser(userId: string, key: PalbaseFlagKey): Promise<PalbaseResult<PalbaseClearOverrideResult>>;
1479
1493
  /** Clear all overrides for a user, restoring project (system) defaults. */
1480
1494
  clearAllOverridesForUser(userId: string): Promise<PalbaseResult<PalbaseClearAllOverridesResult>>;
1481
1495
  /** Apply override writes across many users in one request (max 1000 ops). */
@@ -1499,9 +1513,9 @@ interface PalbaseFlagsServiceClient {
1499
1513
  */
1500
1514
  interface PalbaseFlagsClient {
1501
1515
  /** Is a flag enabled for the given context? */
1502
- isEnabled(flagName: string, context?: PalbaseFlagContext): Promise<PalbaseResult<boolean>>;
1516
+ isEnabled(flagName: PalbaseFlagKey, context?: PalbaseFlagContext): Promise<PalbaseResult<boolean>>;
1503
1517
  /** Get the active variant of a multivariate flag. */
1504
- getVariant(flagName: string, context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagVariant>>;
1518
+ getVariant(flagName: PalbaseFlagKey, context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagVariant>>;
1505
1519
  /** Get all flags for the project. */
1506
1520
  getAll(context?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlag[]>>;
1507
1521
  /**
@@ -1518,7 +1532,7 @@ interface PalbaseFlagsClient {
1518
1532
  * `Documents.doc(...)` — declared and never implemented — seen from the other
1519
1533
  * side, and moving the implementation into this package is what surfaced it.
1520
1534
  */
1521
- get(flagName: string, defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext, maybeContext?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagValue>>;
1535
+ get(flagName: PalbaseFlagKey, defaultOrContext?: PalbaseFlagValue | PalbaseFlagContext, maybeContext?: PalbaseFlagContext): Promise<PalbaseResult<PalbaseFlagValue>>;
1522
1536
  /**
1523
1537
  * Set (or replace) a single feature-flag override for the CURRENT REQUEST
1524
1538
  * USER. No userId argument — the override is bound to the signed-in user the
@@ -1533,7 +1547,7 @@ interface PalbaseFlagsClient {
1533
1547
  * @example
1534
1548
  * await Flags.setOverride("new_checkout", true);
1535
1549
  */
1536
- setOverride(key: string, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1550
+ setOverride(key: PalbaseFlagKey, value: PalbaseFlagValue): Promise<PalbaseResult<PalbaseSetOverrideResult>>;
1537
1551
  /**
1538
1552
  * Return the cross-user admin write surface ({@link PalbaseFlagsServiceClient}).
1539
1553
  * Use sparingly and explicitly — the default `Flags.setOverride(...)` path is
@@ -1545,6 +1559,13 @@ interface PalbaseFlagsClient {
1545
1559
  /**
1546
1560
  * Realtime broadcast surface (backend handler → subscribed clients).
1547
1561
  *
1562
+ * **Every channel must be DECLARED, or the join is refused.** Channel names are
1563
+ * not free text: `channels.ts` at the project root publishes which names exist
1564
+ * and who may subscribe, publish, or write state, and a client joining a name no
1565
+ * declaration matches is rejected without ever reaching your code. Declare with
1566
+ * `ownerOnly()`, `publicChannel()`, or a custom `authorize(ctx)` — see
1567
+ * {@link defineChannels}. Broadcasting to an undeclared channel reaches nobody.
1568
+ *
1548
1569
  * Backend-side this is BROADCAST-ONLY: a handler pushes an event to a channel
1549
1570
  * and every client subscribed to that channel (via the client SDK's
1550
1571
  * `pb.realtime.channel(...).on(...)`) receives it. There is no `subscribe()` on
@@ -1553,9 +1574,10 @@ interface PalbaseFlagsClient {
1553
1574
  * once the broadcast is accepted (or with an `error` if it could not be sent),
1554
1575
  * but it never blocks the handler waiting on subscribers.
1555
1576
  *
1556
- * Channel naming is app-defined and arbitrary (e.g. `"room:42"`, `"orders"`).
1557
- * The Palbase-managed `flags:<ref>` channels are internal author channels for
1558
- * your own features.
1577
+ * Channel names are yours to choose (e.g. `"room:42"`, `"orders"`) but not yours
1578
+ * to leave undeclared: each must match a pattern in `channels.ts`, which is where
1579
+ * `"room:{roomId}"` is authorized. The Palbase-managed `flags:<ref>` channels are
1580
+ * internal — author channels for your own features.
1559
1581
  *
1560
1582
  * @example
1561
1583
  * // Notify everyone in a chat room that a message landed:
@@ -1815,9 +1837,36 @@ interface RateLimitConfig {
1815
1837
  /** The six raw string-keyed DB operations shared by `DBClient` and the
1816
1838
  * transaction-scoped client. */
1817
1839
  interface DBOps {
1818
- /** Run a read-only SQL query (executes in a READ ONLY transaction). */
1840
+ /**
1841
+ * Run SQL on the REQUEST'S OWN transaction.
1842
+ *
1843
+ * This is **not** read-only. Nothing marks that transaction `READ ONLY`, so a
1844
+ * write passed here executes and commits with the request — a plain `UPDATE`, a
1845
+ * write hidden in a CTE, or a function that writes. What stands between a
1846
+ * statement and your data is RLS and the role the request runs as, exactly as
1847
+ * for every other operation on this client.
1848
+ *
1849
+ * `INSERT … ON CONFLICT DO UPDATE` therefore works here; `tables.<t>.upsert()`
1850
+ * is the same thing with types. Array parameters are encoded as Postgres array
1851
+ * literals, so `= ANY($1::uuid[])` takes a plain JS array.
1852
+ *
1853
+ * This comment used to claim a `READ ONLY` transaction. It was wrong, and the
1854
+ * cost was measured: a tenant read it, concluded an upsert was impossible from
1855
+ * here, abandoned `ON CONFLICT` and wrote a database trigger instead.
1856
+ */
1819
1857
  query(sql: string, params?: unknown[]): Promise<Record<string, unknown>[]>;
1820
1858
  insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
1859
+ /**
1860
+ * Insert the row, or update it when it collides on `onConflict` — one
1861
+ * statement, so two concurrent callers cannot both lose.
1862
+ *
1863
+ * Read-then-write cannot be made safe here by catching the unique violation: a
1864
+ * request runs in one transaction, so the failed insert aborts it and every
1865
+ * later statement answers `current transaction is aborted`.
1866
+ */
1867
+ upsert(table: string, data: Record<string, unknown>, opts: {
1868
+ onConflict: readonly string[];
1869
+ }): Promise<Record<string, unknown>>;
1821
1870
  /**
1822
1871
  * Update the row with the given id and resolve to the updated row, or `null`
1823
1872
  * if no row matched (the id is absent, or the row is hidden by RLS). This is
@@ -1835,8 +1884,70 @@ interface DBOps {
1835
1884
  limit?: number;
1836
1885
  using?: string;
1837
1886
  mode?: "hybrid" | "text" | "vector";
1887
+ /** Nihai (RRF-sonrası) skor alt eşiği (FR-001). */
1888
+ minScore?: number;
1889
+ /** RRF-sonrası üstel tazelik çürümesi (FR-004; feed/haber düğmesi). */
1890
+ recency?: {
1891
+ field: string;
1892
+ halfLife: string;
1893
+ };
1894
+ /** Chunk-modunda satır başına en iyi blok sayısı (FR-015). */
1895
+ blocksPerRow?: number;
1896
+ /** Kolon başına top-20 değer sayacı — dönüş dizisinin `_facets` özelliği (FR-027). */
1897
+ facets?: string[];
1898
+ /** Satır-modunda ts_headline vurgusu: satırlara `_highlight` (FR-025; chunk-modda no-op). */
1899
+ highlight?: boolean;
1900
+ /** Validity'li tabloda zaman penceresi: vars. yalnız güncel; "all" tümü; {asOf} o an (FR-029). */
1901
+ validity?: "all" | {
1902
+ asOf: string;
1903
+ };
1904
+ /** Alan-boost (FR-030): skor * (1 + w·x/(1+x)) — sınırlı çarpan, dış servissiz. */
1905
+ boost?: {
1906
+ field: string;
1907
+ weight: number;
1908
+ };
1909
+ }): Promise<Record<string, unknown>[]>;
1910
+ /** Validity'li tabloda satırın yeni versiyonu — eski kapanır (valid_to/superseded_by),
1911
+ * yenisi eklenir; TEK savepoint, dönüş yeni satır (FR-029, C-9). */
1912
+ supersede(table: string, id: string, row: Record<string, unknown>): Promise<Record<string, unknown>>;
1913
+ findMany(table: string, query?: Record<string, unknown>, opts?: {
1914
+ orderBy?: {
1915
+ column: string;
1916
+ direction?: "asc" | "desc";
1917
+ };
1918
+ limit?: number;
1919
+ }): Promise<Record<string, unknown>[]>;
1920
+ /** "Bu satıra benzer satırlar" (FR-022) — satır-modunda kolon vektörüyle,
1921
+ * chunk-modunda chunk-ortalamasıyla; kendisi hariç. */
1922
+ similar(table: string, id: string, opts?: {
1923
+ limit?: number;
1924
+ where?: Record<string, unknown>;
1925
+ minScore?: number;
1926
+ blocksPerRow?: number;
1927
+ validity?: "all" | {
1928
+ asOf: string;
1929
+ };
1930
+ boost?: {
1931
+ field: string;
1932
+ weight: number;
1933
+ };
1934
+ }): Promise<Record<string, unknown>[]>;
1935
+ /** Çok-örnekli öneri (FR-023): avg(pos) + (avg(pos) − avg(neg)); positive'ler sonuç dışı. */
1936
+ recommend(table: string, opts: {
1937
+ positive: string[];
1938
+ negative?: string[];
1939
+ limit?: number;
1940
+ where?: Record<string, unknown>;
1941
+ minScore?: number;
1942
+ blocksPerRow?: number;
1943
+ validity?: "all" | {
1944
+ asOf: string;
1945
+ };
1946
+ boost?: {
1947
+ field: string;
1948
+ weight: number;
1949
+ };
1838
1950
  }): Promise<Record<string, unknown>[]>;
1839
- findMany(table: string, query?: Record<string, unknown>): Promise<Record<string, unknown>[]>;
1840
1951
  }
1841
1952
  /** Database client interface injected into endpoint context. */
1842
1953
  interface DBClient extends DBOps {
@@ -1856,6 +1967,14 @@ interface DBClient extends DBOps {
1856
1967
  * `.expectOne(…)`; without it a declared expectation degrades to a generic 409.
1857
1968
  */
1858
1969
  txPlan(plan: TxPlanBody): Promise<TxPlanResponse>;
1970
+ /**
1971
+ * Run `fn` inside a SAVEPOINT on this request's transaction, so a failure in
1972
+ * it rolls back only what `fn`'s handle wrote.
1973
+ *
1974
+ * The handle is a PARAMETER on purpose: an ambient swap would capture writes
1975
+ * a concurrent `Promise.all` branch made outside the boundary.
1976
+ */
1977
+ attempt<T>(fn: (tx: DBOps) => Promise<T>): Promise<T>;
1859
1978
  /**
1860
1979
  * Return a sibling DB client that bypasses Row-Level Security by running as
1861
1980
  * the `service_role` (BYPASSRLS). Use sparingly and explicitly — the default
@@ -1893,7 +2012,20 @@ interface Logger {
1893
2012
  * a restart and a hot path pays a map lookup.
1894
2013
  */
1895
2014
  interface SecretsService {
1896
- get(name: string): Promise<string | null>;
2015
+ /**
2016
+ * A secret's value, or `null` when this backend's vault holds no value under
2017
+ * that name.
2018
+ *
2019
+ * The name is a `PalbaseSecretName`, not a `string`: it comes from the
2020
+ * generated `palbase-stack.d.ts`, so a secret the stack does not hold cannot
2021
+ * be spelled here at all. THE GATE IS THE COMPILER.
2022
+ *
2023
+ * That gate replaced a declaration. `config/secrets.ts` used to restate, in
2024
+ * the repo, names the vault already held, and the push compared the two lists
2025
+ * — a check that only ran at deploy, and only if the author remembered to
2026
+ * declare. The type runs on every keystroke and cannot be forgotten.
2027
+ */
2028
+ get(name: PalbaseSecretName): Promise<string | null>;
1897
2029
  }
1898
2030
  interface CacheClient {
1899
2031
  /** Read a value. Returns `null` on a cache miss. */
@@ -2143,4 +2275,4 @@ type Middleware = (ctx: MiddlewareContext, next: () => Promise<void>) => Promise
2143
2275
  */
2144
2276
  type AuthSpec = boolean | Partial<AuthConfig>;
2145
2277
 
2146
- export { type PalbaseCreateLinkParams as $, type AuthSpec as A, BadRequest as B, type CacheClient as C, type DBClient as D, type ErrorDef as E, type FileContext as F, type PalbaseAttestiOSParams as G, HttpError as H, type PalbaseAttestiOSResult as I, type PalbaseAuthClient as J, type PalbaseBatchOverrideOperation as K, type Logger as L, type Materialized as M, NotFound as N, type PalbaseBatchSetOverridesResult as O, type PalbaseDocsClient as P, type PalbaseBindDeviceParams as Q, type RateLimitConfig as R, type SecretsService as S, type TxPlanBody as T, type PalbaseClearAllOverridesResult as U, type PalbaseClearOverrideResult as V, type PalbaseCohortQueryInput as W, type PalbaseCohortResult as X, type PalbaseCollectionRef as Y, type PalbaseCountQueryInput as Z, type PalbaseCountResult as _, type PalbaseFlagsClient as a, type PalbaseVerifyRequestSignatureParams as a$, type PalbaseDeviceInfo as a0, type PalbaseDeviceTokenView as a1, type PalbaseDocumentRef as a2, type PalbaseDocumentSnapshot as a3, type PalbaseEmailClient as a4, type PalbaseEmailSendParams as a5, type PalbaseEmailSendResponse as a6, type PalbaseEventNamesResult as a7, type PalbaseEventsQueryInput as a8, type PalbaseEventsResult as a9, type PalbaseMatchParams as aA, type PalbaseMultiChannelResponse as aB, type PalbaseOverviewResult as aC, type PalbasePreferences as aD, type PalbasePreferencesClient as aE, type PalbasePushClient as aF, type PalbasePushSendParams as aG, type PalbasePushSendResponse as aH, type PalbaseQrCodeOptions as aI, type PalbaseQuerySnapshot as aJ, type PalbaseRegisterDeviceParams as aK, type PalbaseRetentionQueryInput as aL, type PalbaseRetentionResult as aM, type PalbaseSession as aN, type PalbaseSetOverrideResult as aO, type PalbaseSetOverridesResult as aP, type PalbaseSignedUrlResponse as aQ, type PalbaseSmsClient as aR, type PalbaseSmsSendParams as aS, type PalbaseSmsSendResponse as aT, type PalbaseTransformOptions as aU, type PalbaseUpdateLinkParams as aV, type PalbaseUploadOptions as aW, type PalbaseUser as aX, type PalbaseUserDetailResult as aY, type PalbaseUsersQueryInput as aZ, type PalbaseUsersResult as a_, type PalbaseFileObject as aa, type PalbaseFlag as ab, type PalbaseFlagContext as ac, type PalbaseFlagSource as ad, type PalbaseFlagValue as ae, type PalbaseFlagVariant as af, type PalbaseFlagsServiceClient as ag, type PalbaseFunctionsClient as ah, type PalbaseFunnelQueryInput as ai, type PalbaseFunnelResult as aj, type PalbaseIdentifyTraits as ak, type PalbaseInboxClient as al, type PalbaseInboxListOptions as am, type PalbaseInboxListResult as an, type PalbaseInboxMessage as ao, type PalbaseInboxSendParams as ap, type PalbaseInboxSendResponse as aq, type PalbaseInitialLink as ar, type PalbaseInvokeOptions as as, type PalbaseLink as at, type PalbaseLinkAnalytics as au, type PalbaseLinkDetails as av, type PalbaseLinksClient as aw, type PalbaseListLinksOptions as ax, type PalbaseListLinksResult as ay, type PalbaseListOptions as az, type PalbaseNotificationsClient as b, type PalbaseWhereOperator as b0, type Ref as b1, TooManyRequests as b2, type TxColumnExpr as b3, type TxInsertShape as b4, type TxInsertValue as b5, type TxNow as b6, TxPlanError as b7, type TxPlanHandle as b8, type TxPlanOpResult as b9, type TxPlanRejection as ba, TxRefError as bb, type TxRow as bc, type TxRows as bd, type TxSelectOptions as be, type TxSetShape as bf, type TxSetValue as bg, type TxTable as bh, type TxWhere as bi, type TxWireExpr as bj, type TxWireGuard as bk, type TxWireOp as bl, type TxWireRef as bm, type TxWireValue as bn, Unauthorized as bo, type User as bp, type VerifiedDevice as bq, dec as br, defineMiddleware as bs, inc as bt, now as bu, type PalbaseRealtimeClient as c, type PalbaseStorageClient as d, type PalbaseBucketClient as e, type TxPlanResponse as f, type PalbaseResult as g, type AuthConfig as h, type ClientInfo as i, Conflict as j, type DBOps as k, type ErrorMap as l, type ErrorThrowers as m, Forbidden as n, type HttpMethod as o, type Middleware as p, type MiddlewareContext as q, type MiddlewareHandler as r, type PBRequest as s, PalError as t, type PalbaseAnalyticsClient as u, type PalbaseAnalyticsManagementNamespace as v, type PalbaseAnalyticsProperties as w, type PalbaseAnalyticsQueryNamespace as x, type PalbaseAttestAndroidParams as y, type PalbaseAttestAndroidResult as z };
2278
+ export { type PalbaseCreateLinkParams as $, type AuthSpec as A, BadRequest as B, type CacheClient as C, type DBClient as D, type ErrorDef as E, type FileContext as F, type PalbaseAttestiOSParams as G, HttpError as H, type PalbaseAttestiOSResult as I, type PalbaseAuthClient as J, type PalbaseBatchOverrideOperation as K, type Logger as L, type Materialized as M, NotFound as N, type PalbaseBatchSetOverridesResult as O, type PalbaseDocsClient as P, type PalbaseBindDeviceParams as Q, type RateLimitConfig as R, type SecretsService as S, type TxPlanBody as T, type PalbaseClearAllOverridesResult as U, type PalbaseClearOverrideResult as V, type PalbaseCohortQueryInput as W, type PalbaseCohortResult as X, type PalbaseCollectionRef as Y, type PalbaseCountQueryInput as Z, type PalbaseCountResult as _, type PalbaseFlagsClient as a, type PalbaseVerifyRequestSignatureParams as a$, type PalbaseDeviceInfo as a0, type PalbaseDeviceTokenView as a1, type PalbaseDocumentRef as a2, type PalbaseDocumentSnapshot as a3, type PalbaseEmailClient as a4, type PalbaseEmailSendParams as a5, type PalbaseEmailSendResponse as a6, type PalbaseEventNamesResult as a7, type PalbaseEventsQueryInput as a8, type PalbaseEventsResult as a9, type PalbaseMatchParams as aA, type PalbaseMultiChannelResponse as aB, type PalbaseOverviewResult as aC, type PalbasePreferences as aD, type PalbasePreferencesClient as aE, type PalbasePushClient as aF, type PalbasePushSendParams as aG, type PalbasePushSendResponse as aH, type PalbaseQrCodeOptions as aI, type PalbaseQuerySnapshot as aJ, type PalbaseRegisterDeviceParams as aK, type PalbaseRetentionQueryInput as aL, type PalbaseRetentionResult as aM, type PalbaseSession as aN, type PalbaseSetOverrideResult as aO, type PalbaseSetOverridesResult as aP, type PalbaseSignedUrlResponse as aQ, type PalbaseSmsClient as aR, type PalbaseSmsSendParams as aS, type PalbaseSmsSendResponse as aT, type PalbaseTransformOptions as aU, type PalbaseUpdateLinkParams as aV, type PalbaseUploadOptions as aW, type PalbaseUser as aX, type PalbaseUserDetailResult as aY, type PalbaseUsersQueryInput as aZ, type PalbaseUsersResult as a_, type PalbaseFileObject as aa, type PalbaseFlag as ab, type PalbaseFlagContext as ac, type PalbaseFlagSource as ad, type PalbaseFlagValue as ae, type PalbaseFlagVariant as af, type PalbaseFlagsServiceClient as ag, type PalbaseFunctionsClient as ah, type PalbaseFunnelQueryInput as ai, type PalbaseFunnelResult as aj, type PalbaseIdentifyTraits as ak, type PalbaseInboxClient as al, type PalbaseInboxListOptions as am, type PalbaseInboxListResult as an, type PalbaseInboxMessage as ao, type PalbaseInboxSendParams as ap, type PalbaseInboxSendResponse as aq, type PalbaseInitialLink as ar, type PalbaseInvokeOptions as as, type PalbaseLink as at, type PalbaseLinkAnalytics as au, type PalbaseLinkDetails as av, type PalbaseLinksClient as aw, type PalbaseListLinksOptions as ax, type PalbaseListLinksResult as ay, type PalbaseListOptions as az, type PalbaseNotificationsClient as b, type PalbaseWhereOperator as b0, type Ref as b1, TooManyRequests as b2, type TxColumnExpr as b3, type TxInsertShape as b4, type TxInsertValue as b5, type TxNow as b6, TxPlanError as b7, type TxPlanHandle as b8, type TxPlanOpResult as b9, type TxPlanRejection as ba, TxRefError as bb, type TxRow as bc, type TxRows as bd, type TxSelectOptions as be, type TxSetShape as bf, type TxSetValue as bg, type TxTable as bh, type TxWhere as bi, type TxWireExpr as bj, type TxWireGuard as bk, type TxWireOp as bl, type TxWireRef as bm, type TxWireValue as bn, Unauthorized as bo, type User as bp, type VerifiedDevice as bq, dec as br, defineMiddleware as bs, inc as bt, now as bu, type PalbaseRealtimeClient as c, type PalbaseStorageClient as d, type PalbaseBucketClient as e, type DBOps as f, type TxPlanResponse as g, type PalbaseResult as h, type AuthConfig as i, type ClientInfo as j, Conflict as k, type ErrorMap as l, type ErrorThrowers as m, Forbidden as n, type HttpMethod as o, type Middleware as p, type MiddlewareContext as q, type MiddlewareHandler as r, type PBRequest as s, PalError as t, type PalbaseAnalyticsClient as u, type PalbaseAnalyticsManagementNamespace as v, type PalbaseAnalyticsProperties as w, type PalbaseAnalyticsQueryNamespace as x, type PalbaseAttestAndroidParams as y, type PalbaseAttestAndroidResult as z };