@palbase/backend 23.1.0 → 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/palbase-backend.cjs +389 -44
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -5
- package/dist/bin/palbase-backend.js.map +1 -1
- package/dist/{chunk-OHALWEOG.js → chunk-7Z6MGMXQ.js} +57 -2
- package/dist/chunk-7Z6MGMXQ.js.map +1 -0
- package/dist/{chunk-RCLNBJCM.js → chunk-H3JAISUY.js} +136 -1
- package/dist/chunk-H3JAISUY.js.map +1 -0
- package/dist/{chunk-M5MCBWJI.js → chunk-NXDH6VQJ.js} +264 -28
- package/dist/chunk-NXDH6VQJ.js.map +1 -0
- package/dist/{chunk-NS5V43YQ.js → chunk-P2Q27SGP.js} +19 -3
- package/dist/chunk-P2Q27SGP.js.map +1 -0
- package/dist/{chunk-R3KN6RHD.js → chunk-T5IOSOE5.js} +7 -2
- package/dist/chunk-T5IOSOE5.js.map +1 -0
- package/dist/{chunk-PY7YJDCT.js → chunk-ZUGY7RGS.js} +32 -3
- package/dist/chunk-ZUGY7RGS.js.map +1 -0
- package/dist/db/index.cjs +48 -3
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +2 -2
- package/dist/{endpoint-CVWXh6oG.d.ts → endpoint-0_DGBajf.d.ts} +100 -3
- package/dist/{endpoint-c9h5jriX.d.cts → endpoint-CcQ1a36a.d.cts} +100 -3
- package/dist/engine/index.cjs +378 -31
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +4 -4
- package/dist/engine/index.d.ts +4 -4
- package/dist/engine/index.js +4 -4
- package/dist/{index-CwAJ7HEe.d.ts → index-CJiJU9ux.d.ts} +125 -21
- package/dist/{index-By8Dle5U.d.cts → index-D-4-PNuQ.d.cts} +125 -21
- package/dist/{index-BZrJXnVh.d.ts → index-D17r-MKb.d.ts} +134 -9
- package/dist/{index-CxeQSfJP.d.cts → index-DRFxf07H.d.cts} +134 -9
- package/dist/index.cjs +166 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -12
- package/dist/index.d.ts +54 -12
- package/dist/index.js +28 -11
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.cjs +16 -1
- package/dist/openapi/index.cjs.map +1 -1
- package/dist/openapi/index.d.cts +6 -4
- package/dist/openapi/index.d.ts +6 -4
- package/dist/openapi/index.js +6 -7
- package/dist/openapi/index.js.map +1 -1
- package/dist/{registry-CqPK2Qby.d.cts → registry-1X-skBNu.d.cts} +1 -1
- package/dist/{registry-B3niOVYp.d.ts → registry-CEod_5sz.d.ts} +1 -1
- package/dist/test/index.cjs +27 -0
- package/dist/test/index.cjs.map +1 -1
- package/dist/test/index.d.cts +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +27 -0
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +4 -4
- package/docs/database.md +115 -11
- package/docs/getting-started.md +5 -4
- package/docs/llms-full.txt +385 -89
- package/docs/migrations.md +81 -59
- package/docs/schema.md +82 -2
- package/docs/services.md +98 -9
- package/package.json +2 -2
- package/template/AGENTS.md +121 -41
- package/template/controllers/notes.controller.ts +64 -0
- package/template/package.json +1 -1
- package/template/services/note.service.ts +74 -0
- package/template/tsconfig.json +11 -1
- package/dist/chunk-HQRJDARQ.js +0 -90
- package/dist/chunk-HQRJDARQ.js.map +0 -1
- package/dist/chunk-M5MCBWJI.js.map +0 -1
- package/dist/chunk-NS5V43YQ.js.map +0 -1
- package/dist/chunk-OHALWEOG.js.map +0 -1
- package/dist/chunk-PY7YJDCT.js.map +0 -1
- package/dist/chunk-R3KN6RHD.js.map +0 -1
- package/dist/chunk-RCLNBJCM.js.map +0 -1
package/dist/engine/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { A as App,
|
|
2
|
-
import '../endpoint-
|
|
1
|
+
export { A as App, m as AuthVerifier, B as BootRefused, n as CreateAppOptions, E as EgressPolicy, p as EngineConfig, M as ModuleClients, q as RateLimiter, r as RequestDatabase, s as RouteEntry, t as RuntimeHooks, u as ScrubResult, v as SqlDriver, w as SqlTx, x as buildRouteTable, y as createApp, z as createLazyTransaction, G as createOps, H as createRequestDatabase, I as effectiveAuth, J as hostAllowed, K as installEgressFence, O as loadConfig, P as makeMemoryCache, Q as matchRoute, T as quoteIdent, U as scrubSecrets, V as withTables } from '../index-DRFxf07H.cjs';
|
|
2
|
+
import '../endpoint-CcQ1a36a.cjs';
|
|
3
3
|
import '../stack.cjs';
|
|
4
4
|
import 'node:async_hooks';
|
|
5
|
-
import '../index-
|
|
5
|
+
import '../index-D-4-PNuQ.cjs';
|
|
6
6
|
import '../db/env.cjs';
|
|
7
|
-
import '../registry-
|
|
7
|
+
import '../registry-1X-skBNu.cjs';
|
|
8
8
|
import 'zod';
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { A as App,
|
|
2
|
-
import '../endpoint-
|
|
1
|
+
export { A as App, m as AuthVerifier, B as BootRefused, n as CreateAppOptions, E as EgressPolicy, p as EngineConfig, M as ModuleClients, q as RateLimiter, r as RequestDatabase, s as RouteEntry, t as RuntimeHooks, u as ScrubResult, v as SqlDriver, w as SqlTx, x as buildRouteTable, y as createApp, z as createLazyTransaction, G as createOps, H as createRequestDatabase, I as effectiveAuth, J as hostAllowed, K as installEgressFence, O as loadConfig, P as makeMemoryCache, Q as matchRoute, T as quoteIdent, U as scrubSecrets, V as withTables } from '../index-D17r-MKb.js';
|
|
2
|
+
import '../endpoint-0_DGBajf.js';
|
|
3
3
|
import '../stack.js';
|
|
4
4
|
import 'node:async_hooks';
|
|
5
|
-
import '../index-
|
|
5
|
+
import '../index-CJiJU9ux.js';
|
|
6
6
|
import '../db/env.js';
|
|
7
|
-
import '../registry-
|
|
7
|
+
import '../registry-CEod_5sz.js';
|
|
8
8
|
import 'zod';
|
package/dist/engine/index.js
CHANGED
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
quoteIdent,
|
|
17
17
|
scrubSecrets,
|
|
18
18
|
withTables
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
19
|
+
} from "../chunk-NXDH6VQJ.js";
|
|
20
|
+
import "../chunk-7Z6MGMXQ.js";
|
|
21
|
+
import "../chunk-P2Q27SGP.js";
|
|
22
|
+
import "../chunk-H3JAISUY.js";
|
|
23
23
|
import "../chunk-7D4SUZUM.js";
|
|
24
24
|
export {
|
|
25
25
|
AuthVerifier,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tables, TableTypes } from './db/env.js';
|
|
2
|
-
import { D as DBClient, b8 as TxPlanHandle, bh as TxTable, M as Materialized } from './endpoint-
|
|
2
|
+
import { D as DBClient, b8 as TxPlanHandle, bh as TxTable, M as Materialized } from './endpoint-0_DGBajf.js';
|
|
3
3
|
|
|
4
4
|
/** On delete action for foreign key references. */
|
|
5
5
|
type OnDeleteAction = 'cascade' | 'set null' | 'restrict' | 'no action';
|
|
@@ -50,12 +50,33 @@ interface ColumnDef {
|
|
|
50
50
|
/** vector(n): the declared dimension count — part of the TYPE (typmod), read
|
|
51
51
|
* by the wire serializer and the deploy's auto-index (FR-001). */
|
|
52
52
|
dimensions?: number;
|
|
53
|
+
/**
|
|
54
|
+
* How the stored value is projected in and out of this process (FR-009).
|
|
55
|
+
*
|
|
56
|
+
* NOT part of the DDL: the column's Postgres type is unchanged and this pair
|
|
57
|
+
* is never serialized into a migration. It exists so the row surface can hand
|
|
58
|
+
* back the type the application actually works with.
|
|
59
|
+
*/
|
|
60
|
+
transform?: ColumnTransform;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The read/write pair a column may declare (FR-009).
|
|
64
|
+
*
|
|
65
|
+
* `fromDb` takes whatever the driver produced for this column and returns the
|
|
66
|
+
* value the application sees; `toDb` is its inverse on the way out. Kept
|
|
67
|
+
* deliberately unexported — a column declares one inline, nobody needs to name
|
|
68
|
+
* the shape.
|
|
69
|
+
*/
|
|
70
|
+
interface ColumnTransform<T = unknown> {
|
|
71
|
+
fromDb: (value: unknown) => T;
|
|
72
|
+
toDb: (value: T) => unknown;
|
|
53
73
|
}
|
|
54
74
|
declare const __colKind: unique symbol;
|
|
55
75
|
declare const __colNullable: unique symbol;
|
|
56
76
|
declare const __colHasDefault: unique symbol;
|
|
57
77
|
declare const __colEnumValues: unique symbol;
|
|
58
78
|
declare const __colPayload: unique symbol;
|
|
79
|
+
declare const __colTransform: unique symbol;
|
|
59
80
|
/**
|
|
60
81
|
* Fluent column builder with phantom type params:
|
|
61
82
|
* K — ColumnType literal (e.g. "text", "integer")
|
|
@@ -63,34 +84,38 @@ declare const __colPayload: unique symbol;
|
|
|
63
84
|
* D — boolean: true when a default has been set
|
|
64
85
|
* E — enum value union (never for non-enum columns)
|
|
65
86
|
* P — jsonb payload shape (unknown unless jsonb<T>() supplied one)
|
|
87
|
+
* T — transform target type (`never` when the column declares no transform;
|
|
88
|
+
* `never` is the sentinel because it is the only type that survives
|
|
89
|
+
* `[T] extends [never]` and never collides with a real target type)
|
|
66
90
|
*
|
|
67
|
-
* All
|
|
91
|
+
* All six params have defaults so bare `ColumnBuilder` (no args) still
|
|
68
92
|
* satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.
|
|
69
93
|
*
|
|
70
|
-
* The
|
|
94
|
+
* The six `declare readonly` brand fields carry the phantom types into the
|
|
71
95
|
* structural shape so that conditional types like ColValue<C> can discriminate
|
|
72
96
|
* on K without requiring runtime values on those fields.
|
|
73
97
|
*/
|
|
74
|
-
declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean = boolean, D extends boolean = boolean, E = unknown, P = unknown> {
|
|
98
|
+
declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean = boolean, D extends boolean = boolean, E = unknown, P = unknown, T = never> {
|
|
75
99
|
readonly [__colKind]: K;
|
|
76
100
|
readonly [__colNullable]: N;
|
|
77
101
|
readonly [__colHasDefault]: D;
|
|
78
102
|
readonly [__colEnumValues]: E;
|
|
79
103
|
readonly [__colPayload]: P;
|
|
104
|
+
readonly [__colTransform]: T;
|
|
80
105
|
readonly _def: ColumnDef;
|
|
81
106
|
constructor(type: K, existingDef?: ColumnDef);
|
|
82
107
|
/** Mark this column as the primary key. */
|
|
83
|
-
primaryKey(): ColumnBuilder<K, N, D, E, P>;
|
|
108
|
+
primaryKey(): ColumnBuilder<K, N, D, E, P, T>;
|
|
84
109
|
/** Mark this column as NOT NULL (default). */
|
|
85
|
-
notNull(): ColumnBuilder<K, false, D, E, P>;
|
|
110
|
+
notNull(): ColumnBuilder<K, false, D, E, P, T>;
|
|
86
111
|
/** Allow NULL values. */
|
|
87
|
-
nullable(): ColumnBuilder<K, true, D, E, P>;
|
|
112
|
+
nullable(): ColumnBuilder<K, true, D, E, P, T>;
|
|
88
113
|
/** Set a default value. */
|
|
89
|
-
default(value: unknown): ColumnBuilder<K, N, true, E, P>;
|
|
114
|
+
default(value: unknown): ColumnBuilder<K, N, true, E, P, T>;
|
|
90
115
|
/** UUID: generate a random default (gen_random_uuid()). */
|
|
91
|
-
defaultRandom(): ColumnBuilder<K, N, true, E, P>;
|
|
116
|
+
defaultRandom(): ColumnBuilder<K, N, true, E, P, T>;
|
|
92
117
|
/** Timestamp: default to now(). */
|
|
93
|
-
defaultNow(): ColumnBuilder<K, N, true, E, P>;
|
|
118
|
+
defaultNow(): ColumnBuilder<K, N, true, E, P, T>;
|
|
94
119
|
/**
|
|
95
120
|
* The DATABASE assigns this column's value — a trigger, a rule, an identity.
|
|
96
121
|
*
|
|
@@ -102,7 +127,7 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
102
127
|
* they are a different thing; borrowing the word would send a reader — or a
|
|
103
128
|
* model writing a schema — to the wrong feature.
|
|
104
129
|
*/
|
|
105
|
-
dbAssigned(): ColumnBuilder<K, N, true, E, P>;
|
|
130
|
+
dbAssigned(): ColumnBuilder<K, N, true, E, P, T>;
|
|
106
131
|
/** Add a foreign key reference. */
|
|
107
132
|
/**
|
|
108
133
|
* Declares that this column used to be called `previous`.
|
|
@@ -115,8 +140,8 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
115
140
|
* Once the rename has been applied the annotation is inert (the old name is no
|
|
116
141
|
* longer there to rename), so it can be deleted at your leisure.
|
|
117
142
|
*/
|
|
118
|
-
renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P>;
|
|
119
|
-
references(table: string, column: string): ColumnBuilder<K, N, D, E, P>;
|
|
143
|
+
renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P, T>;
|
|
144
|
+
references(table: string, column: string): ColumnBuilder<K, N, D, E, P, T>;
|
|
120
145
|
/**
|
|
121
146
|
* Add a real DB-level foreign key to the built-in auth users
|
|
122
147
|
* (`REFERENCES auth.users(id)`), so a column like `user_id` gets true
|
|
@@ -137,7 +162,7 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
137
162
|
* express (referencing column is text, `set null` needs a nullable column) —
|
|
138
163
|
* as the real boundary; this signature is the compile-time DX mirror.
|
|
139
164
|
*/
|
|
140
|
-
referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P>;
|
|
165
|
+
referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T>;
|
|
141
166
|
/**
|
|
142
167
|
* Add a real DB-level foreign key to the canonical, server-minted installation
|
|
143
168
|
* anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device
|
|
@@ -156,11 +181,30 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
156
181
|
* blocked by a lingering FK. The server (validateAuthAnchorFK) is the real
|
|
157
182
|
* boundary; this signature is the compile-time DX mirror.
|
|
158
183
|
*/
|
|
159
|
-
referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P>;
|
|
184
|
+
referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T>;
|
|
160
185
|
/** Set the ON DELETE action for a foreign key reference. */
|
|
161
|
-
onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E, P>;
|
|
186
|
+
onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E, P, T>;
|
|
162
187
|
/** Add a single-column UNIQUE constraint. */
|
|
163
|
-
unique(): ColumnBuilder<K, N, D, E, P>;
|
|
188
|
+
unique(): ColumnBuilder<K, N, D, E, P, T>;
|
|
189
|
+
/**
|
|
190
|
+
* Declare how this column's value is projected in and out of the process.
|
|
191
|
+
*
|
|
192
|
+
* The DDL does not move: `numeric` stays `numeric`, and the driver still hands
|
|
193
|
+
* back what Postgres sent. What changes is the type the row surface exposes —
|
|
194
|
+
* it becomes `Target`:
|
|
195
|
+
*
|
|
196
|
+
* amount: numeric().transform<number>({ fromDb: Number, toDb: String })
|
|
197
|
+
*
|
|
198
|
+
* `numeric` surfacing as `string` is CORRECT (a JS number cannot hold
|
|
199
|
+
* arbitrary precision), and that is exactly why this exists: application code
|
|
200
|
+
* that does arithmetic on the column otherwise rewrites the same
|
|
201
|
+
* `Number(row.amount)` / `String(x)` pair in every controller that touches it,
|
|
202
|
+
* and each rewrite is a place the two directions can drift apart.
|
|
203
|
+
*
|
|
204
|
+
* A transform is a PROJECTION, never a constraint: it lives only in this
|
|
205
|
+
* process, so it can neither validate nor migrate what is stored.
|
|
206
|
+
*/
|
|
207
|
+
transform<Target>(fns: ColumnTransform<Target>): ColumnBuilder<K, N, D, E, P, Target>;
|
|
164
208
|
}
|
|
165
209
|
/**
|
|
166
210
|
* Extracts the TypeScript value type for a column, respecting nullability.
|
|
@@ -172,14 +216,22 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
172
216
|
* - "boolean" → boolean
|
|
173
217
|
* - "jsonb" → P (the dev-supplied payload shape from jsonb<T>(), else unknown)
|
|
174
218
|
* - "enum" → E (the union of literal values)
|
|
219
|
+
*
|
|
220
|
+
* A declared `.transform<T>()` OVERRIDES the table above: the column then
|
|
221
|
+
* surfaces as T (or T | null when nullable), because that is the value the
|
|
222
|
+
* application is handed. Nullability is still the column's, not the
|
|
223
|
+
* transform's — `fromDb` is not called for a NULL.
|
|
175
224
|
*/
|
|
176
|
-
type ColValue<C> = C extends ColumnBuilder<
|
|
225
|
+
type ColValue<C> = C extends ColumnBuilder<ColumnType, infer N, boolean, unknown, unknown, infer T> ? [T] extends [never] ? ColStoredValue<C> : N extends true ? T | null : T : never;
|
|
226
|
+
/** The value as the DATABASE hands it over — the branch table above, before any
|
|
227
|
+
* transform. This is what a column's `fromDb` receives. */
|
|
228
|
+
type ColStoredValue<C> = C extends ColumnBuilder<'uuid' | 'text' | 'timestamp' | 'bigint' | 'numeric', infer N, infer _D, infer _E, infer _P> ? N extends true ? string | null : string : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E, infer _P> ? N extends true ? number | null : number : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E, infer _P> ? N extends true ? boolean | null : boolean : C extends ColumnBuilder<'jsonb', infer N, infer _D, infer _E, infer P> ? N extends true ? P | null : P : C extends ColumnBuilder<'vector', infer N, infer _D, infer _E, infer _P> ? N extends true ? number[] | null : number[] : C extends ColumnBuilder<'enum', infer N, infer _D, infer E, infer _P> ? N extends true ? E | null : E : never;
|
|
177
229
|
/**
|
|
178
230
|
* True when a column is optional on INSERT:
|
|
179
231
|
* - nullable columns (N = true) — the DB allows NULL so the field may be omitted
|
|
180
232
|
* - columns with a default (D = true) — the DB fills in the value when absent
|
|
181
233
|
*/
|
|
182
|
-
type ColIsOptionalOnInsert<C> = C extends ColumnBuilder<
|
|
234
|
+
type ColIsOptionalOnInsert<C> = C extends ColumnBuilder<ColumnType, true, boolean, unknown, unknown, unknown> ? true : C extends ColumnBuilder<ColumnType, boolean, true, unknown, unknown, unknown> ? true : false;
|
|
183
235
|
/** Create a UUID column. */
|
|
184
236
|
declare function uuid(): ColumnBuilder<'uuid', false, false, never>;
|
|
185
237
|
/** Create a TEXT column. */
|
|
@@ -691,7 +743,15 @@ interface TypedTable<T extends TableDef> {
|
|
|
691
743
|
update(id: string, data: Partial<InsertShape<T>>): Promise<RowShape<T> | null>;
|
|
692
744
|
delete(id: string): Promise<void>;
|
|
693
745
|
findById(id: string): Promise<RowShape<T> | null>;
|
|
694
|
-
|
|
746
|
+
/** Rows matching the filter. Operators, ordering and paging are the ENGINE's
|
|
747
|
+
* surface — this declaration is what makes them callable. */
|
|
748
|
+
findMany(query?: WhereFilter<RowShape<T>>, opts?: FindManyOpts<RowShape<T>>): Promise<RowShape<T>[]>;
|
|
749
|
+
/** Update every matching row in one statement; an empty filter is refused. */
|
|
750
|
+
updateMany(where: WhereFilter<RowShape<T>>, set: Partial<InsertShape<T>>): Promise<RowShape<T>[]>;
|
|
751
|
+
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
752
|
+
deleteMany(where: WhereFilter<RowShape<T>>): Promise<number>;
|
|
753
|
+
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
754
|
+
count(where?: WhereFilter<RowShape<T>>): Promise<number>;
|
|
695
755
|
}
|
|
696
756
|
/** A typed DB facade covering all tables declared in schema `S`. */
|
|
697
757
|
interface TypedDB<S extends SchemaDef> {
|
|
@@ -730,6 +790,30 @@ type WhereOp<V> = V | {
|
|
|
730
790
|
neq?: V;
|
|
731
791
|
in?: V[];
|
|
732
792
|
};
|
|
793
|
+
/**
|
|
794
|
+
* A filter over a row: every field optional, each one a plain value (equality)
|
|
795
|
+
* or an operator object. THE filter language — `findMany`, `updateMany`,
|
|
796
|
+
* `deleteMany` and `count` all take this one, because two spellings of a filter
|
|
797
|
+
* is how the two come to disagree.
|
|
798
|
+
*/
|
|
799
|
+
type WhereFilter<Row> = {
|
|
800
|
+
[K in keyof Row]?: WhereOp<Row[K]>;
|
|
801
|
+
};
|
|
802
|
+
/**
|
|
803
|
+
* Ordering and paging for a read.
|
|
804
|
+
*
|
|
805
|
+
* `column` is `keyof Row`, not `string`: a mistyped column name is a compile
|
|
806
|
+
* error here rather than a runtime rejection three layers down. `offset`
|
|
807
|
+
* without `limit` is refused by the engine — a page with no size is not a page.
|
|
808
|
+
*/
|
|
809
|
+
type FindManyOpts<Row> = {
|
|
810
|
+
orderBy?: {
|
|
811
|
+
column: Extract<keyof Row, string>;
|
|
812
|
+
direction?: "asc" | "desc";
|
|
813
|
+
};
|
|
814
|
+
limit?: number;
|
|
815
|
+
offset?: number;
|
|
816
|
+
};
|
|
733
817
|
/** search() parametreleri, satır tipiyle koşullanmış (FR-013). `offset` BİLEREK yok (UD-013). */
|
|
734
818
|
interface SearchParamsTyped<T extends TableTypes> {
|
|
735
819
|
/** Metin sorgusu: FTS kolunu besler; embed beyanlıysa sorgu vektörü de bundan üretilir. */
|
|
@@ -809,7 +893,15 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
809
893
|
update(id: string, data: Partial<T["insert"]>): Promise<T["row"] | null>;
|
|
810
894
|
delete(id: string): Promise<void>;
|
|
811
895
|
findById(id: string): Promise<T["row"] | null>;
|
|
812
|
-
|
|
896
|
+
/** Rows matching the filter. See {@link WhereFilter} / {@link FindManyOpts} —
|
|
897
|
+
* this declaration is what makes the engine's operators callable. */
|
|
898
|
+
findMany(query?: WhereFilter<T["row"]>, opts?: FindManyOpts<T["row"]>): Promise<T["row"][]>;
|
|
899
|
+
/** Update every matching row in one statement; an empty filter is refused. */
|
|
900
|
+
updateMany(where: WhereFilter<T["row"]>, set: Partial<T["insert"]>): Promise<T["row"][]>;
|
|
901
|
+
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
902
|
+
deleteMany(where: WhereFilter<T["row"]>): Promise<number>;
|
|
903
|
+
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
904
|
+
count(where?: WhereFilter<T["row"]>): Promise<number>;
|
|
813
905
|
/** Validity'li tabloda satırın yeni versiyonu (FR-029, C-9): eski satır
|
|
814
906
|
* kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş
|
|
815
907
|
* yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı
|
|
@@ -832,6 +924,18 @@ type EnvTypedTable<T extends TableTypes> = EnvTypedTableBase<T> & (T extends {
|
|
|
832
924
|
similar(id: string, params?: SimilarParamsTyped<T>): Promise<Array<T["row"] & {
|
|
833
925
|
_score: number;
|
|
834
926
|
}>>;
|
|
927
|
+
/** D-021: sayaçlar bağımsız dönüşle — search'ün dizi-üstü _facets'i
|
|
928
|
+
* JSON.stringify'da kaybolur; ciddi sözleşme budur. */
|
|
929
|
+
facets(params: {
|
|
930
|
+
facets: Array<keyof T["row"] & string>;
|
|
931
|
+
where?: Partial<T["row"]>;
|
|
932
|
+
validity?: "all" | {
|
|
933
|
+
asOf: string;
|
|
934
|
+
};
|
|
935
|
+
}): Promise<Record<string, {
|
|
936
|
+
value: string | null;
|
|
937
|
+
count: number;
|
|
938
|
+
}[]>>;
|
|
835
939
|
/** positive/negative beğenilerden öneri (FR-023): hedef vektör DB-içi
|
|
836
940
|
* avg CTE'leriyle; kaynak id'ler sonuçta yoktur. */
|
|
837
941
|
recommend(params: RecommendParamsTyped<T>): Promise<Array<T["row"] & {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tables, TableTypes } from './db/env.cjs';
|
|
2
|
-
import { D as DBClient, b8 as TxPlanHandle, bh as TxTable, M as Materialized } from './endpoint-
|
|
2
|
+
import { D as DBClient, b8 as TxPlanHandle, bh as TxTable, M as Materialized } from './endpoint-CcQ1a36a.cjs';
|
|
3
3
|
|
|
4
4
|
/** On delete action for foreign key references. */
|
|
5
5
|
type OnDeleteAction = 'cascade' | 'set null' | 'restrict' | 'no action';
|
|
@@ -50,12 +50,33 @@ interface ColumnDef {
|
|
|
50
50
|
/** vector(n): the declared dimension count — part of the TYPE (typmod), read
|
|
51
51
|
* by the wire serializer and the deploy's auto-index (FR-001). */
|
|
52
52
|
dimensions?: number;
|
|
53
|
+
/**
|
|
54
|
+
* How the stored value is projected in and out of this process (FR-009).
|
|
55
|
+
*
|
|
56
|
+
* NOT part of the DDL: the column's Postgres type is unchanged and this pair
|
|
57
|
+
* is never serialized into a migration. It exists so the row surface can hand
|
|
58
|
+
* back the type the application actually works with.
|
|
59
|
+
*/
|
|
60
|
+
transform?: ColumnTransform;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The read/write pair a column may declare (FR-009).
|
|
64
|
+
*
|
|
65
|
+
* `fromDb` takes whatever the driver produced for this column and returns the
|
|
66
|
+
* value the application sees; `toDb` is its inverse on the way out. Kept
|
|
67
|
+
* deliberately unexported — a column declares one inline, nobody needs to name
|
|
68
|
+
* the shape.
|
|
69
|
+
*/
|
|
70
|
+
interface ColumnTransform<T = unknown> {
|
|
71
|
+
fromDb: (value: unknown) => T;
|
|
72
|
+
toDb: (value: T) => unknown;
|
|
53
73
|
}
|
|
54
74
|
declare const __colKind: unique symbol;
|
|
55
75
|
declare const __colNullable: unique symbol;
|
|
56
76
|
declare const __colHasDefault: unique symbol;
|
|
57
77
|
declare const __colEnumValues: unique symbol;
|
|
58
78
|
declare const __colPayload: unique symbol;
|
|
79
|
+
declare const __colTransform: unique symbol;
|
|
59
80
|
/**
|
|
60
81
|
* Fluent column builder with phantom type params:
|
|
61
82
|
* K — ColumnType literal (e.g. "text", "integer")
|
|
@@ -63,34 +84,38 @@ declare const __colPayload: unique symbol;
|
|
|
63
84
|
* D — boolean: true when a default has been set
|
|
64
85
|
* E — enum value union (never for non-enum columns)
|
|
65
86
|
* P — jsonb payload shape (unknown unless jsonb<T>() supplied one)
|
|
87
|
+
* T — transform target type (`never` when the column declares no transform;
|
|
88
|
+
* `never` is the sentinel because it is the only type that survives
|
|
89
|
+
* `[T] extends [never]` and never collides with a real target type)
|
|
66
90
|
*
|
|
67
|
-
* All
|
|
91
|
+
* All six params have defaults so bare `ColumnBuilder` (no args) still
|
|
68
92
|
* satisfies `Record<string, ColumnBuilder>` in schema.ts without modification.
|
|
69
93
|
*
|
|
70
|
-
* The
|
|
94
|
+
* The six `declare readonly` brand fields carry the phantom types into the
|
|
71
95
|
* structural shape so that conditional types like ColValue<C> can discriminate
|
|
72
96
|
* on K without requiring runtime values on those fields.
|
|
73
97
|
*/
|
|
74
|
-
declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean = boolean, D extends boolean = boolean, E = unknown, P = unknown> {
|
|
98
|
+
declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean = boolean, D extends boolean = boolean, E = unknown, P = unknown, T = never> {
|
|
75
99
|
readonly [__colKind]: K;
|
|
76
100
|
readonly [__colNullable]: N;
|
|
77
101
|
readonly [__colHasDefault]: D;
|
|
78
102
|
readonly [__colEnumValues]: E;
|
|
79
103
|
readonly [__colPayload]: P;
|
|
104
|
+
readonly [__colTransform]: T;
|
|
80
105
|
readonly _def: ColumnDef;
|
|
81
106
|
constructor(type: K, existingDef?: ColumnDef);
|
|
82
107
|
/** Mark this column as the primary key. */
|
|
83
|
-
primaryKey(): ColumnBuilder<K, N, D, E, P>;
|
|
108
|
+
primaryKey(): ColumnBuilder<K, N, D, E, P, T>;
|
|
84
109
|
/** Mark this column as NOT NULL (default). */
|
|
85
|
-
notNull(): ColumnBuilder<K, false, D, E, P>;
|
|
110
|
+
notNull(): ColumnBuilder<K, false, D, E, P, T>;
|
|
86
111
|
/** Allow NULL values. */
|
|
87
|
-
nullable(): ColumnBuilder<K, true, D, E, P>;
|
|
112
|
+
nullable(): ColumnBuilder<K, true, D, E, P, T>;
|
|
88
113
|
/** Set a default value. */
|
|
89
|
-
default(value: unknown): ColumnBuilder<K, N, true, E, P>;
|
|
114
|
+
default(value: unknown): ColumnBuilder<K, N, true, E, P, T>;
|
|
90
115
|
/** UUID: generate a random default (gen_random_uuid()). */
|
|
91
|
-
defaultRandom(): ColumnBuilder<K, N, true, E, P>;
|
|
116
|
+
defaultRandom(): ColumnBuilder<K, N, true, E, P, T>;
|
|
92
117
|
/** Timestamp: default to now(). */
|
|
93
|
-
defaultNow(): ColumnBuilder<K, N, true, E, P>;
|
|
118
|
+
defaultNow(): ColumnBuilder<K, N, true, E, P, T>;
|
|
94
119
|
/**
|
|
95
120
|
* The DATABASE assigns this column's value — a trigger, a rule, an identity.
|
|
96
121
|
*
|
|
@@ -102,7 +127,7 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
102
127
|
* they are a different thing; borrowing the word would send a reader — or a
|
|
103
128
|
* model writing a schema — to the wrong feature.
|
|
104
129
|
*/
|
|
105
|
-
dbAssigned(): ColumnBuilder<K, N, true, E, P>;
|
|
130
|
+
dbAssigned(): ColumnBuilder<K, N, true, E, P, T>;
|
|
106
131
|
/** Add a foreign key reference. */
|
|
107
132
|
/**
|
|
108
133
|
* Declares that this column used to be called `previous`.
|
|
@@ -115,8 +140,8 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
115
140
|
* Once the rename has been applied the annotation is inert (the old name is no
|
|
116
141
|
* longer there to rename), so it can be deleted at your leisure.
|
|
117
142
|
*/
|
|
118
|
-
renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P>;
|
|
119
|
-
references(table: string, column: string): ColumnBuilder<K, N, D, E, P>;
|
|
143
|
+
renamedFrom(previous: string): ColumnBuilder<K, N, D, E, P, T>;
|
|
144
|
+
references(table: string, column: string): ColumnBuilder<K, N, D, E, P, T>;
|
|
120
145
|
/**
|
|
121
146
|
* Add a real DB-level foreign key to the built-in auth users
|
|
122
147
|
* (`REFERENCES auth.users(id)`), so a column like `user_id` gets true
|
|
@@ -137,7 +162,7 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
137
162
|
* express (referencing column is text, `set null` needs a nullable column) —
|
|
138
163
|
* as the real boundary; this signature is the compile-time DX mirror.
|
|
139
164
|
*/
|
|
140
|
-
referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P>;
|
|
165
|
+
referencesAuthUser(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T>;
|
|
141
166
|
/**
|
|
142
167
|
* Add a real DB-level foreign key to the canonical, server-minted installation
|
|
143
168
|
* anchor (`REFERENCES auth.installations(id)`) — the app-scoped verified-device
|
|
@@ -156,11 +181,30 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
156
181
|
* blocked by a lingering FK. The server (validateAuthAnchorFK) is the real
|
|
157
182
|
* boundary; this signature is the compile-time DX mirror.
|
|
158
183
|
*/
|
|
159
|
-
referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P>;
|
|
184
|
+
referencesInstallation(onDelete: AuthUserOnDelete): ColumnBuilder<K, N, D, E, P, T>;
|
|
160
185
|
/** Set the ON DELETE action for a foreign key reference. */
|
|
161
|
-
onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E, P>;
|
|
186
|
+
onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E, P, T>;
|
|
162
187
|
/** Add a single-column UNIQUE constraint. */
|
|
163
|
-
unique(): ColumnBuilder<K, N, D, E, P>;
|
|
188
|
+
unique(): ColumnBuilder<K, N, D, E, P, T>;
|
|
189
|
+
/**
|
|
190
|
+
* Declare how this column's value is projected in and out of the process.
|
|
191
|
+
*
|
|
192
|
+
* The DDL does not move: `numeric` stays `numeric`, and the driver still hands
|
|
193
|
+
* back what Postgres sent. What changes is the type the row surface exposes —
|
|
194
|
+
* it becomes `Target`:
|
|
195
|
+
*
|
|
196
|
+
* amount: numeric().transform<number>({ fromDb: Number, toDb: String })
|
|
197
|
+
*
|
|
198
|
+
* `numeric` surfacing as `string` is CORRECT (a JS number cannot hold
|
|
199
|
+
* arbitrary precision), and that is exactly why this exists: application code
|
|
200
|
+
* that does arithmetic on the column otherwise rewrites the same
|
|
201
|
+
* `Number(row.amount)` / `String(x)` pair in every controller that touches it,
|
|
202
|
+
* and each rewrite is a place the two directions can drift apart.
|
|
203
|
+
*
|
|
204
|
+
* A transform is a PROJECTION, never a constraint: it lives only in this
|
|
205
|
+
* process, so it can neither validate nor migrate what is stored.
|
|
206
|
+
*/
|
|
207
|
+
transform<Target>(fns: ColumnTransform<Target>): ColumnBuilder<K, N, D, E, P, Target>;
|
|
164
208
|
}
|
|
165
209
|
/**
|
|
166
210
|
* Extracts the TypeScript value type for a column, respecting nullability.
|
|
@@ -172,14 +216,22 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
|
|
|
172
216
|
* - "boolean" → boolean
|
|
173
217
|
* - "jsonb" → P (the dev-supplied payload shape from jsonb<T>(), else unknown)
|
|
174
218
|
* - "enum" → E (the union of literal values)
|
|
219
|
+
*
|
|
220
|
+
* A declared `.transform<T>()` OVERRIDES the table above: the column then
|
|
221
|
+
* surfaces as T (or T | null when nullable), because that is the value the
|
|
222
|
+
* application is handed. Nullability is still the column's, not the
|
|
223
|
+
* transform's — `fromDb` is not called for a NULL.
|
|
175
224
|
*/
|
|
176
|
-
type ColValue<C> = C extends ColumnBuilder<
|
|
225
|
+
type ColValue<C> = C extends ColumnBuilder<ColumnType, infer N, boolean, unknown, unknown, infer T> ? [T] extends [never] ? ColStoredValue<C> : N extends true ? T | null : T : never;
|
|
226
|
+
/** The value as the DATABASE hands it over — the branch table above, before any
|
|
227
|
+
* transform. This is what a column's `fromDb` receives. */
|
|
228
|
+
type ColStoredValue<C> = C extends ColumnBuilder<'uuid' | 'text' | 'timestamp' | 'bigint' | 'numeric', infer N, infer _D, infer _E, infer _P> ? N extends true ? string | null : string : C extends ColumnBuilder<'integer', infer N, infer _D, infer _E, infer _P> ? N extends true ? number | null : number : C extends ColumnBuilder<'boolean', infer N, infer _D, infer _E, infer _P> ? N extends true ? boolean | null : boolean : C extends ColumnBuilder<'jsonb', infer N, infer _D, infer _E, infer P> ? N extends true ? P | null : P : C extends ColumnBuilder<'vector', infer N, infer _D, infer _E, infer _P> ? N extends true ? number[] | null : number[] : C extends ColumnBuilder<'enum', infer N, infer _D, infer E, infer _P> ? N extends true ? E | null : E : never;
|
|
177
229
|
/**
|
|
178
230
|
* True when a column is optional on INSERT:
|
|
179
231
|
* - nullable columns (N = true) — the DB allows NULL so the field may be omitted
|
|
180
232
|
* - columns with a default (D = true) — the DB fills in the value when absent
|
|
181
233
|
*/
|
|
182
|
-
type ColIsOptionalOnInsert<C> = C extends ColumnBuilder<
|
|
234
|
+
type ColIsOptionalOnInsert<C> = C extends ColumnBuilder<ColumnType, true, boolean, unknown, unknown, unknown> ? true : C extends ColumnBuilder<ColumnType, boolean, true, unknown, unknown, unknown> ? true : false;
|
|
183
235
|
/** Create a UUID column. */
|
|
184
236
|
declare function uuid(): ColumnBuilder<'uuid', false, false, never>;
|
|
185
237
|
/** Create a TEXT column. */
|
|
@@ -691,7 +743,15 @@ interface TypedTable<T extends TableDef> {
|
|
|
691
743
|
update(id: string, data: Partial<InsertShape<T>>): Promise<RowShape<T> | null>;
|
|
692
744
|
delete(id: string): Promise<void>;
|
|
693
745
|
findById(id: string): Promise<RowShape<T> | null>;
|
|
694
|
-
|
|
746
|
+
/** Rows matching the filter. Operators, ordering and paging are the ENGINE's
|
|
747
|
+
* surface — this declaration is what makes them callable. */
|
|
748
|
+
findMany(query?: WhereFilter<RowShape<T>>, opts?: FindManyOpts<RowShape<T>>): Promise<RowShape<T>[]>;
|
|
749
|
+
/** Update every matching row in one statement; an empty filter is refused. */
|
|
750
|
+
updateMany(where: WhereFilter<RowShape<T>>, set: Partial<InsertShape<T>>): Promise<RowShape<T>[]>;
|
|
751
|
+
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
752
|
+
deleteMany(where: WhereFilter<RowShape<T>>): Promise<number>;
|
|
753
|
+
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
754
|
+
count(where?: WhereFilter<RowShape<T>>): Promise<number>;
|
|
695
755
|
}
|
|
696
756
|
/** A typed DB facade covering all tables declared in schema `S`. */
|
|
697
757
|
interface TypedDB<S extends SchemaDef> {
|
|
@@ -730,6 +790,30 @@ type WhereOp<V> = V | {
|
|
|
730
790
|
neq?: V;
|
|
731
791
|
in?: V[];
|
|
732
792
|
};
|
|
793
|
+
/**
|
|
794
|
+
* A filter over a row: every field optional, each one a plain value (equality)
|
|
795
|
+
* or an operator object. THE filter language — `findMany`, `updateMany`,
|
|
796
|
+
* `deleteMany` and `count` all take this one, because two spellings of a filter
|
|
797
|
+
* is how the two come to disagree.
|
|
798
|
+
*/
|
|
799
|
+
type WhereFilter<Row> = {
|
|
800
|
+
[K in keyof Row]?: WhereOp<Row[K]>;
|
|
801
|
+
};
|
|
802
|
+
/**
|
|
803
|
+
* Ordering and paging for a read.
|
|
804
|
+
*
|
|
805
|
+
* `column` is `keyof Row`, not `string`: a mistyped column name is a compile
|
|
806
|
+
* error here rather than a runtime rejection three layers down. `offset`
|
|
807
|
+
* without `limit` is refused by the engine — a page with no size is not a page.
|
|
808
|
+
*/
|
|
809
|
+
type FindManyOpts<Row> = {
|
|
810
|
+
orderBy?: {
|
|
811
|
+
column: Extract<keyof Row, string>;
|
|
812
|
+
direction?: "asc" | "desc";
|
|
813
|
+
};
|
|
814
|
+
limit?: number;
|
|
815
|
+
offset?: number;
|
|
816
|
+
};
|
|
733
817
|
/** search() parametreleri, satır tipiyle koşullanmış (FR-013). `offset` BİLEREK yok (UD-013). */
|
|
734
818
|
interface SearchParamsTyped<T extends TableTypes> {
|
|
735
819
|
/** Metin sorgusu: FTS kolunu besler; embed beyanlıysa sorgu vektörü de bundan üretilir. */
|
|
@@ -809,7 +893,15 @@ interface EnvTypedTableBase<T extends TableTypes> {
|
|
|
809
893
|
update(id: string, data: Partial<T["insert"]>): Promise<T["row"] | null>;
|
|
810
894
|
delete(id: string): Promise<void>;
|
|
811
895
|
findById(id: string): Promise<T["row"] | null>;
|
|
812
|
-
|
|
896
|
+
/** Rows matching the filter. See {@link WhereFilter} / {@link FindManyOpts} —
|
|
897
|
+
* this declaration is what makes the engine's operators callable. */
|
|
898
|
+
findMany(query?: WhereFilter<T["row"]>, opts?: FindManyOpts<T["row"]>): Promise<T["row"][]>;
|
|
899
|
+
/** Update every matching row in one statement; an empty filter is refused. */
|
|
900
|
+
updateMany(where: WhereFilter<T["row"]>, set: Partial<T["insert"]>): Promise<T["row"][]>;
|
|
901
|
+
/** Delete every matching row; resolves to how many. Empty filter refused. */
|
|
902
|
+
deleteMany(where: WhereFilter<T["row"]>): Promise<number>;
|
|
903
|
+
/** How many rows match. An empty filter is legitimate: counting is a read. */
|
|
904
|
+
count(where?: WhereFilter<T["row"]>): Promise<number>;
|
|
813
905
|
/** Validity'li tabloda satırın yeni versiyonu (FR-029, C-9): eski satır
|
|
814
906
|
* kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş
|
|
815
907
|
* yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı
|
|
@@ -832,6 +924,18 @@ type EnvTypedTable<T extends TableTypes> = EnvTypedTableBase<T> & (T extends {
|
|
|
832
924
|
similar(id: string, params?: SimilarParamsTyped<T>): Promise<Array<T["row"] & {
|
|
833
925
|
_score: number;
|
|
834
926
|
}>>;
|
|
927
|
+
/** D-021: sayaçlar bağımsız dönüşle — search'ün dizi-üstü _facets'i
|
|
928
|
+
* JSON.stringify'da kaybolur; ciddi sözleşme budur. */
|
|
929
|
+
facets(params: {
|
|
930
|
+
facets: Array<keyof T["row"] & string>;
|
|
931
|
+
where?: Partial<T["row"]>;
|
|
932
|
+
validity?: "all" | {
|
|
933
|
+
asOf: string;
|
|
934
|
+
};
|
|
935
|
+
}): Promise<Record<string, {
|
|
936
|
+
value: string | null;
|
|
937
|
+
count: number;
|
|
938
|
+
}[]>>;
|
|
835
939
|
/** positive/negative beğenilerden öneri (FR-023): hedef vektör DB-içi
|
|
836
940
|
* avg CTE'leriyle; kaynak id'ler sonuçta yoktur. */
|
|
837
941
|
recommend(params: RecommendParamsTyped<T>): Promise<Array<T["row"] & {
|