@palbase/backend 27.0.0 → 28.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.
Files changed (52) hide show
  1. package/dist/bin/palbase-backend.cjs +165 -39
  2. package/dist/bin/palbase-backend.cjs.map +1 -1
  3. package/dist/bin/palbase-backend.js +4 -4
  4. package/dist/{chunk-GYK6QYS4.js → chunk-3TUJWHC2.js} +28 -3
  5. package/dist/chunk-3TUJWHC2.js.map +1 -0
  6. package/dist/{chunk-OO7R25AI.js → chunk-75YROPRZ.js} +118 -39
  7. package/dist/chunk-75YROPRZ.js.map +1 -0
  8. package/dist/{chunk-TS4U7NBD.js → chunk-IVZERLTM.js} +2 -2
  9. package/dist/{chunk-I3C4PFIW.js → chunk-RVP6BTEZ.js} +63 -6
  10. package/dist/chunk-RVP6BTEZ.js.map +1 -0
  11. package/dist/{chunk-DRZFQRJI.js → chunk-SNDXY565.js} +3 -2
  12. package/dist/chunk-SNDXY565.js.map +1 -0
  13. package/dist/db/index.cjs +30 -1
  14. package/dist/db/index.cjs.map +1 -1
  15. package/dist/db/index.d.cts +1 -1
  16. package/dist/db/index.d.ts +1 -1
  17. package/dist/db/index.js +3 -3
  18. package/dist/engine/index.cjs +175 -39
  19. package/dist/engine/index.cjs.map +1 -1
  20. package/dist/engine/index.d.cts +3 -3
  21. package/dist/engine/index.d.ts +3 -3
  22. package/dist/engine/index.js +11 -4
  23. package/dist/{index-VtToZmUm.d.cts → index-9C3JHxg-.d.cts} +112 -5
  24. package/dist/{index-NuzRCuxe.d.ts → index-BbvOoZFr.d.ts} +112 -5
  25. package/dist/{index-Bve7BBTL.d.cts → index-DtISj9QX.d.cts} +125 -22
  26. package/dist/{index-BrvvxSpn.d.ts → index-dTTLlHIn.d.ts} +125 -22
  27. package/dist/index.cjs +93 -4
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +6 -22
  30. package/dist/index.d.ts +6 -22
  31. package/dist/index.js +10 -4
  32. package/dist/index.js.map +1 -1
  33. package/dist/openapi/index.d.cts +2 -2
  34. package/dist/openapi/index.d.ts +2 -2
  35. package/dist/{registry-B0eyOF9x.d.ts → registry-JQNIX-eA.d.ts} +1 -1
  36. package/dist/{registry-Bk9_rbNd.d.cts → registry-qIPM5BQe.d.cts} +1 -1
  37. package/dist/test/index.cjs +100 -6
  38. package/dist/test/index.cjs.map +1 -1
  39. package/dist/test/index.d.cts +1 -1
  40. package/dist/test/index.d.ts +1 -1
  41. package/dist/test/index.js +88 -6
  42. package/dist/test/index.js.map +1 -1
  43. package/docs/README.md +1 -1
  44. package/docs/database.md +103 -1
  45. package/docs/llms-full.txt +104 -2
  46. package/package.json +1 -1
  47. package/template/package.json +1 -1
  48. package/dist/chunk-DRZFQRJI.js.map +0 -1
  49. package/dist/chunk-GYK6QYS4.js.map +0 -1
  50. package/dist/chunk-I3C4PFIW.js.map +0 -1
  51. package/dist/chunk-OO7R25AI.js.map +0 -1
  52. /package/dist/{chunk-TS4U7NBD.js.map → chunk-IVZERLTM.js.map} +0 -0
@@ -2825,7 +2825,12 @@ type RowShape<T extends TableDef> = {
2825
2825
  };
2826
2826
  /** A typed table accessor that mirrors the runtime DBClient surface. */
2827
2827
  interface TypedTable<T extends TableDef> {
2828
- insert(data: InsertShape<T>): Promise<RowShape<T>>;
2828
+ insert(data: InsertValues<InsertShape<T>>): Promise<RowShape<T>>;
2829
+ /** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı. */
2830
+ insertMany(rows: readonly InsertValues<InsertShape<T>>[], opts?: {
2831
+ onConflict: readonly string[];
2832
+ action?: "ignore" | "update";
2833
+ }): Promise<RowShape<T>[]>;
2829
2834
  put(q: {
2830
2835
  data: InsertShape<T>;
2831
2836
  onConflict: readonly string[];
@@ -2837,7 +2842,7 @@ interface TypedTable<T extends TableDef> {
2837
2842
  where: {
2838
2843
  id: string;
2839
2844
  };
2840
- set: Partial<InsertShape<T>>;
2845
+ set: SetShape<InsertShape<T>>;
2841
2846
  }): Promise<RowShape<T> | null>;
2842
2847
  delete(id: string): Promise<void>;
2843
2848
  findById(id: string): Promise<RowShape<T> | null>;
@@ -2974,9 +2979,39 @@ declare function col<const N extends string>(name: N): ColRef<N>;
2974
2979
  * kabul, `numeric ↔ text` ret olur ve ikisi de DOĞRU olur. Defterde teklif.
2975
2980
  */
2976
2981
  type PgFamily<V> = [NonNullable<V>] extends [boolean] ? "bool" : [NonNullable<V>] extends [readonly (number | string)[]] ? "array" : [NonNullable<V>] extends [Date] ? "date" : [NonNullable<V>] extends [string | number] ? "scalar" : "opaque";
2977
- /** `Row`'un `V` ile karşılaştırılabilir kolonları — aynı aileden olanlar. */
2982
+ /**
2983
+ * Kolonun BİLDİRİLMİŞ Postgres tipi — `env-gen`'in bastığı markadan.
2984
+ *
2985
+ * Marka yoksa `"?"`: elle yazılmış bir `Tables` (testler) ya da yeniden
2986
+ * üretilmemiş bir `palbase-env.d.ts`. O durumda eski TS-tipi sezgiseline
2987
+ * düşülüyor, çünkü marka olmadan söylenebilecek daha doğru bir şey yok.
2988
+ */
2989
+ type PgTag<V> = [NonNullable<V>] extends [{
2990
+ readonly __pg?: infer N;
2991
+ }] ? [N] extends [string] ? N : "?" : "?";
2992
+ /**
2993
+ * Postgres'te birbirleriyle karşılaştırılabilen tipler tek "cins".
2994
+ *
2995
+ * `integer`, `bigint` ve `numeric` örtük sayısal dönüşümle karşılaştırılır;
2996
+ * geri kalan her tip yalnız kendisiyle. `uuid ↔ text` ve `enum ↔ text`
2997
+ * Postgres'te `operator does not exist` verir — D-021'de CANLI ölçülmüştü ve
2998
+ * tip bunu göremediği için kabul ediyordu.
2999
+ */
3000
+ type PgKind<P> = P extends "integer" | "bigint" | "numeric" ? "num" : P;
3001
+ /** İki tarafın da markası var mı — yoksa sezgisele düşülür. */
3002
+ type BothBranded<A, B> = "?" extends PgTag<A> ? false : "?" extends PgTag<B> ? false : true;
3003
+ type PgSameKind<A, B> = [PgKind<PgTag<A>>] extends [PgKind<PgTag<B>>] ? [PgKind<PgTag<B>>] extends [PgKind<PgTag<A>>] ? true : false : false;
3004
+ /**
3005
+ * `A` kolonu `B` ile karşılaştırılabilir mi.
3006
+ *
3007
+ * Marka varsa CEVAP KESİN: ne yanlış ret ne yanlış kabul. D-021 bu kuralı
3008
+ * "doğru olamaz" diye kaydetmişti çünkü tipte ayırt edecek bilgi yoktu; bilgi
3009
+ * artık tipte.
3010
+ */
3011
+ type ColComparable<A, B> = BothBranded<A, B> extends true ? PgSameKind<A, B> : [PgFamily<A>] extends [PgFamily<B>] ? true : false;
3012
+ /** `Row`'un `V` ile karşılaştırılabilir kolonları. */
2978
3013
  type ColumnsComparableTo<Row, V> = {
2979
- [K in keyof Row]-?: PgFamily<Row[K]> extends PgFamily<V> ? K : never;
3014
+ [K in keyof Row]-?: ColComparable<Row[K], V> extends true ? K : never;
2980
3015
  }[keyof Row];
2981
3016
  /**
2982
3017
  * Bu satırın kolonlarından birine referans. `Row` bilinmiyorsa hiçbiri.
@@ -3052,12 +3087,24 @@ type TextOps<V> = V extends string ? {
3052
3087
  * `C` bir parametre, çünkü `ColRefOf<Row, V>` aksi hâlde altı operatör
3053
3088
  * konumunda AYRI AYRI instantiate edilirdi — kolon başına altı mapped type.
3054
3089
  * Böyle kolon başına BİR tane (N-2). */
3090
+ /**
3091
+ * `now()` HANGİ kolonlarda karşılaştırma değeri olabilir.
3092
+ *
3093
+ * `timestamp` TypeScript'e `string` olarak geliyor — `text` ile aynı tip. Yani
3094
+ * "yalnız zaman kolonları" tip düzeyinde İFADE EDİLEMEZ (D-021'in tam olarak
3095
+ * kaydettiği sınır: TS numeric/bigint/text/uuid/timestamp'ı `string`'e
3096
+ * çöktürüyor). İki seçenekten yanlış KABUL, yanlış RET'e tercih ediliyor:
3097
+ * `now()`'ı bir metin kolonunda yazmak Postgres hatası verir, ama zaman
3098
+ * kolonunda YASAKLAMAK yazarı bu yüzden `sqlFragment`e düşürürdü — ve bu
3099
+ * özelliğin var olma nedeni tam olarak o düşüşü kaldırmak.
3100
+ */
3101
+ type NowComparable<V> = "?" extends PgTag<V> ? [NonNullable<V>] extends [string | Date] ? TxNow : never : PgTag<V> extends "timestamp" ? TxNow : never;
3055
3102
  type WhereOpBody<V, C> = {
3056
- gt?: V | C;
3057
- gte?: V | C;
3058
- lt?: V | C;
3059
- lte?: V | C;
3060
- neq?: V | C;
3103
+ gt?: V | C | NowComparable<V>;
3104
+ gte?: V | C | NowComparable<V>;
3105
+ lt?: V | C | NowComparable<V>;
3106
+ lte?: V | C | NowComparable<V>;
3107
+ neq?: V | C | NowComparable<V>;
3061
3108
  in?: V[];
3062
3109
  /** `IS NULL` / `IS NOT NULL` (FR-006) — `= NULL` SQL'de her zaman UNKNOWN'dır. */
3063
3110
  isNull?: boolean;
@@ -3072,7 +3119,7 @@ type WhereOp<V, Row = unknown> = WhereOpWith<V, ColRefOf<Row, V>>;
3072
3119
  * `TextOps<V>` `V extends string` diye soruyor ve `string | Ref<string>` o
3073
3120
  * soruya HAYIR der, yani `contains`/`startsWith` sessizce KAYBOLURDU.
3074
3121
  */
3075
- type WhereOpWith<V, C> = V | C | WhereOpBody<V, C>;
3122
+ type WhereOpWith<V, C> = V | C | NowComparable<V> | WhereOpBody<V, C>;
3076
3123
  /**
3077
3124
  * A filter over a row: every field optional, each one a plain value (equality)
3078
3125
  * or an operator object. THE filter language — `findMany`, `updateMany`,
@@ -3089,10 +3136,18 @@ type WhereFilter<Row> = {
3089
3136
  * Kysely'nin TS7'de 9,8M instantiation üreten vakası derin generic
3090
3137
  * özyinelemeydi. Burada derinlik yazarın filtresi kadardır ve pratikte
3091
3138
  * bir-iki seviyedir; tip maliyeti T001'in tavanına karşı ölçülür.
3139
+ *
3140
+ * Dal bir `sqlFragment` DE olabilir. Motor bunu zaten derliyordu — parantezli
3141
+ * ve parametreli (`… AND (((expires_at > now())) AND (t."city" = $2))`) —
3142
+ * ama tip yalnız üst düzey `where`'de fragment'e izin veriyordu. Yani
3143
+ * "fragment sorgudan KAÇMAK için değil, sorgunun İÇİNE girmek için" sözü tam
3144
+ * da bileşim anında kırılıyordu: bir koşulu bir fragment'le birleştirmek
3145
+ * isteyen yazar SORGUNUN TAMAMINI ham SQL'e taşımak zorunda kalıyordu.
3146
+ * Ölçüldü: bir müşteri sorgusunda tam olarak bu oldu.
3092
3147
  */
3093
- OR?: WhereFilter<Row>[];
3094
- AND?: WhereFilter<Row>[];
3095
- NOT?: WhereFilter<Row>;
3148
+ OR?: (WhereFilter<Row> | SqlFragment)[];
3149
+ AND?: (WhereFilter<Row> | SqlFragment)[];
3150
+ NOT?: WhereFilter<Row> | SqlFragment;
3096
3151
  };
3097
3152
  /**
3098
3153
  * Ordering and paging for a read.
@@ -3237,7 +3292,25 @@ type MutateInput<Row, Insert, Rels = unknown> = {
3237
3292
  * string de sayısal sayılır; ayrımı burada yapamayız, ama D-007 zaten miktarın
3238
3293
  * JS `number`'a hiç uğramamasını istiyor.
3239
3294
  */
3240
- type SetValue<V> = V | (NonNullable<V> extends number | string ? TxColumnExpr : never) | (NonNullable<V> extends Date ? TxNow : never);
3295
+ /** `increment()`/`decrement()` HANGİ kolonlarda anlamlı bildirilmiş PG tipine
3296
+ * göre. Marka yoksa eski sezgisel (`number | string`), ki o `text` kolonda da
3297
+ * izin veriyordu: Postgres `text + 1` demez. */
3298
+ type NumericCol<V> = "?" extends PgTag<V> ? NonNullable<V> extends number | string ? TxColumnExpr : never : PgKind<PgTag<V>> extends "num" ? TxColumnExpr : never;
3299
+ /**
3300
+ * Bir EKLEME yolunda yazılabilecek değer.
3301
+ *
3302
+ * Kolonun kendi tipi ya da — zaman kolonlarında — sunucu saati. `increment()`
3303
+ * burada YOK ve olamaz: satır henüz yokken "kolonun şu anki değeri" diye bir
3304
+ * şey yok, motor da bunu adıyla reddediyor.
3305
+ *
3306
+ * Var olma nedeni ölçülmüş: introspect edilmiş şemalarda zaman kolonlarının
3307
+ * çoğu varsayılansız (`timestamp()`), yani "eklerken sunucu saatini yaz"ın tek
3308
+ * karşılığı istemci saatiydi — 33 tablolu bir projede 12 yerde.
3309
+ */
3310
+ type InsertValues<Insert> = {
3311
+ [K in keyof Insert]: Insert[K] | NowComparable<Insert[K]>;
3312
+ };
3313
+ type SetValue<V> = V | NumericCol<V> | NowComparable<V>;
3241
3314
  /** Bir update'in `set`'i: insert şeklinin herhangi bir alt kümesi, ifadelerle. */
3242
3315
  type SetShape<Insert> = {
3243
3316
  [K in keyof Insert]?: SetValue<Insert[K]>;
@@ -3320,7 +3393,30 @@ type RelsOf<T> = T extends {
3320
3393
  } ? R : unknown;
3321
3394
  /** Temel tablo erişimcisi — search'süz beş op. */
3322
3395
  interface EnvTypedTableBase<T extends TableTypes> {
3323
- insert(data: T["insert"]): Promise<T["row"]>;
3396
+ insert(data: InsertValues<T["insert"]>): Promise<T["row"]>;
3397
+ /**
3398
+ * Çok satırı TEK statement'la ekle (tek gidiş-dönüş).
3399
+ *
3400
+ * ```ts
3401
+ * await Database.public.journey_stops.insertMany(
3402
+ * stops.map((s, i) => ({ journey_id, name: s.name, sort_order: i })),
3403
+ * );
3404
+ * ```
3405
+ *
3406
+ * Satırların anahtar kümesi AYNI olmalı: tek statement kolon listesini
3407
+ * paylaşır, yani farklı şekilli bir satırın fazla kolonu sessizce yazılmaz
3408
+ * ve eksiği yanlış sütuna kayardı. Eksik alan için `null` yazın.
3409
+ *
3410
+ * Boş dizi boş sonuç döner — hata değil: "eklenecek bir şey yoktu".
3411
+ */
3412
+ insertMany(rows: readonly InsertValues<T["insert"]>[], opts?: {
3413
+ /** Çakışmanın ARANDIĞI kolonlar — benzersiz bir kısıt ya da index taşımalı. */
3414
+ onConflict: readonly Extract<keyof T["row"], string>[];
3415
+ /** `"ignore"` (VARSAYILAN, plan yoluyla aynı) çakışanı atlar ve o satır
3416
+ * SONUÇTA DÖNMEZ — Postgres yalnız yazdıklarını döndürür; `"update"`
3417
+ * üzerine yazar. */
3418
+ action?: "ignore" | "update";
3419
+ }): Promise<T["row"][]>;
3324
3420
  /**
3325
3421
  * Bir idempotency anahtarını sahiplen (FR-033).
3326
3422
  *
@@ -3336,7 +3432,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
3336
3432
  * İlk argüman satırı BULAN alanlar, ikincisi yalnız yazılanlar — ikinci çağrı
3337
3433
  * farklı bir yük gönderse bile satır anahtarla bulunur.
3338
3434
  */
3339
- claim(unique: Partial<T["insert"]>, extra?: Partial<T["insert"]>): Promise<{
3435
+ claim(unique: Partial<T["insert"]>, extra?: Partial<InsertValues<T["insert"]>>): Promise<{
3340
3436
  inserted: boolean;
3341
3437
  row: T["row"];
3342
3438
  }>;
@@ -3361,7 +3457,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
3361
3457
  * seçmeyi kolay yapıyordu.
3362
3458
  */
3363
3459
  put(q: {
3364
- data: T["insert"];
3460
+ data: InsertValues<T["insert"]>;
3365
3461
  onConflict: readonly Extract<keyof T["row"], string>[];
3366
3462
  }): Promise<T["row"]>;
3367
3463
  /** Update the row by id; resolves to the updated row, or `null` if no row
@@ -3371,7 +3467,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
3371
3467
  where: {
3372
3468
  id: string;
3373
3469
  };
3374
- set: Partial<T["insert"]>;
3470
+ set: SetShape<T["insert"]>;
3375
3471
  }): Promise<T["row"] | null>;
3376
3472
  delete(id: string): Promise<void>;
3377
3473
  findById(id: string): Promise<T["row"] | null>;
@@ -3406,7 +3502,7 @@ interface EnvTypedTableBase<T extends TableTypes> {
3406
3502
  * kapanır (valid_to/superseded_by), yenisi TEK savepoint'te eklenir; dönüş
3407
3503
  * yeni satır. Validity beyanı olmayan tabloda adlandırılmış çalışma-zamanı
3408
3504
  * hatası — tip düzeyinde ayrım env `Tables` bayrağı taşımadığından yapılamaz. */
3409
- supersede(id: string, row: T["insert"]): Promise<T["row"]>;
3505
+ supersede(id: string, row: InsertValues<T["insert"]>): Promise<T["row"]>;
3410
3506
  }
3411
3507
  /** Tablo erişimcisi: env girdisi `searchable: true` taşıyorsa (vector kolonu ya da
3412
3508
  * search beyanı — env-gen üretir) `search()` üyesi VARDIR; yoksa üye hiç yoktur ve
@@ -3960,9 +4056,9 @@ type TxWhereField<Row, K extends keyof Row> = WhereOpWith<Row[K], ColRefOf<Row,
3960
4056
  type TxWhere<Row, Rels = unknown> = {
3961
4057
  [K in keyof Row]?: TxWhereField<Row, K>;
3962
4058
  } & {
3963
- OR?: TxWhere<Row, Rels>[];
3964
- AND?: TxWhere<Row, Rels>[];
3965
- NOT?: TxWhere<Row, Rels>;
4059
+ OR?: (TxWhere<Row, Rels> | SqlFragment)[];
4060
+ AND?: (TxWhere<Row, Rels> | SqlFragment)[];
4061
+ NOT?: TxWhere<Row, Rels> | SqlFragment;
3966
4062
  } & HasOnly<Rels>;
3967
4063
  /** Options for a plan `select`. */
3968
4064
  interface TxSelectOptions {
@@ -4342,6 +4438,13 @@ interface DBOps {
4342
4438
  */
4343
4439
  query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
4344
4440
  insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
4441
+ /** Çok satır, TEK statement. Satırların anahtar kümesi aynı olmalı — kolon
4442
+ * listesi paylaşıldığı için farklı şekilli bir satırın kolonu sessizce
4443
+ * yazılmazdı. */
4444
+ insertMany(table: string, rows: readonly Record<string, unknown>[], opts?: {
4445
+ onConflict: readonly string[];
4446
+ action?: "ignore" | "update";
4447
+ }): Promise<Record<string, unknown>[]>;
4345
4448
  /**
4346
4449
  * Insert the row, or update it when it collides on `onConflict` — one
4347
4450
  * statement, so two concurrent callers cannot both lose.
package/dist/index.cjs CHANGED
@@ -27,8 +27,10 @@ __export(src_exports, {
27
27
  Client: () => Client,
28
28
  Conflict: () => Conflict,
29
29
  Controller: () => Controller,
30
+ DECLARATION_REFUSAL: () => DECLARATION_REFUSAL,
30
31
  Database: () => Database,
31
32
  DeadlockDetected: () => DeadlockDetected,
33
+ DeclarationRefused: () => DeclarationRefused,
32
34
  Delete: () => Delete,
33
35
  Deny: () => Deny,
34
36
  DiError: () => DiError,
@@ -130,6 +132,7 @@ __export(src_exports, {
130
132
  index: () => index,
131
133
  installationRef: () => installationRef,
132
134
  integer: () => integer,
135
+ isDeclarationRefused: () => isDeclarationRefused,
133
136
  isPalbaseExtension: () => isPalbaseExtension,
134
137
  isRetryable: () => isRetryable,
135
138
  jobsOf: () => jobsOf,
@@ -192,6 +195,27 @@ function isSqlFragment(v) {
192
195
  return f !== void 0 && Array.isArray(f.text) && Array.isArray(f.values);
193
196
  }
194
197
  __name(isSqlFragment, "isSqlFragment");
198
+ var TX_EXPR = /* @__PURE__ */ Symbol.for("palbase.tx.expr");
199
+ function isNowExpr(v) {
200
+ if (!isColumnExpr(v)) return false;
201
+ try {
202
+ const e = v[TX_EXPR];
203
+ return typeof e === "object" && e !== null && e.fn === "now";
204
+ } catch {
205
+ return false;
206
+ }
207
+ }
208
+ __name(isNowExpr, "isNowExpr");
209
+ function isColumnExpr(v) {
210
+ if (typeof v !== "object" && typeof v !== "function") return false;
211
+ if (v === null) return false;
212
+ try {
213
+ return v[TX_EXPR] !== void 0;
214
+ } catch {
215
+ return false;
216
+ }
217
+ }
218
+ __name(isColumnExpr, "isColumnExpr");
195
219
 
196
220
  // src/db/tx-plan.ts
197
221
  var TxRefError = class extends Error {
@@ -349,6 +373,11 @@ function encodeValue(value, column, allowColumnExpr) {
349
373
  field: ref.field
350
374
  }
351
375
  }, "ref");
376
+ if (isNowExpr(value)) return {
377
+ $expr: {
378
+ fn: "now"
379
+ }
380
+ };
352
381
  const expr = exprOf(value);
353
382
  if (expr) {
354
383
  if (expr.fn !== "now" && !allowColumnExpr) {
@@ -426,7 +455,9 @@ function encodeMap(map, allowColumnExpr) {
426
455
  const out = {};
427
456
  for (const key of Object.keys(map).sort()) {
428
457
  const value = map[key];
429
- if (value === void 0) continue;
458
+ if (value === void 0) {
459
+ throw new TxPlanError(`${key} de\u011Feri undefined \u2014 bu bir yazma de\u011Feri de\u011Fil. Anahtar duruyor ama de\u011Feri yok, yani kolon sessizce YAZILMAZDI (istek g\xF6vdesinden gelen bir alan\u0131n eksik olmas\u0131 bu \u015Fekilde g\xF6r\xFCn\xFCr). Kolon varsay\u0131lan\u0131n\u0131 istiyorsan\u0131z anahtar\u0131 hi\xE7 koymay\u0131n; NULL yazmak istiyorsan\u0131z a\xE7\u0131k\xE7a null yaz\u0131n.`);
460
+ }
430
461
  out[key] = encodeValue(value, key, allowColumnExpr);
431
462
  }
432
463
  return out;
@@ -887,6 +918,7 @@ var TooManyRequests = class extends NamedHttpError {
887
918
  function makeTypedTable(name, raw2) {
888
919
  return {
889
920
  insert: /* @__PURE__ */ __name((data) => raw2.insert(name, data), "insert"),
921
+ insertMany: /* @__PURE__ */ __name((rows, opts) => raw2.insertMany(name, rows, opts), "insertMany"),
890
922
  put: /* @__PURE__ */ __name((q) => raw2.put(name, q.data, {
891
923
  onConflict: q.onConflict
892
924
  }), "put"),
@@ -1338,6 +1370,10 @@ function makeTableProxy(ops, prefix) {
1338
1370
  const name = `${prefix}${prop}`;
1339
1371
  return {
1340
1372
  insert: /* @__PURE__ */ __name((data) => ops().insert(name, data), "insert"),
1373
+ // DÖRDÜNCÜ FİİL, aynı gerekçeyle: tip söz veriyor, ops katmanı
1374
+ // uyguluyor, ve bir handler'ın gerçekten dokunduğu yer BURASI.
1375
+ // `runtime-table-verbs` kapısı bunu adıyla saydı.
1376
+ insertMany: /* @__PURE__ */ __name((rows, opts) => ops().insertMany(name, rows, opts), "insertMany"),
1341
1377
  update: /* @__PURE__ */ __name((q) => ops().update(name, q.where.id, q.set), "update"),
1342
1378
  delete: /* @__PURE__ */ __name((id) => ops().delete(name, id), "delete"),
1343
1379
  findById: /* @__PURE__ */ __name((id) => ops().findById(name, id), "findById"),
@@ -1394,6 +1430,7 @@ function makeTypedSurface(raw2) {
1394
1430
  $claim: /* @__PURE__ */ __name((table, unique, extra) => reco.claim(table, unique, extra), "$claim"),
1395
1431
  $lockRows: /* @__PURE__ */ __name((table, ids) => reco.lockRows(table, ids), "$lockRows"),
1396
1432
  $advisoryXactLock: /* @__PURE__ */ __name((key) => reco.advisoryXactLock(key), "$advisoryXactLock"),
1433
+ $insertMany: /* @__PURE__ */ __name((table, rows, opts) => raw2.insertMany(table, rows, opts), "$insertMany"),
1397
1434
  $supersede: /* @__PURE__ */ __name((table, id, row) => raw2.supersede(table, id, row), "$supersede")
1398
1435
  };
1399
1436
  const base = Object.assign(ops, {
@@ -3532,6 +3569,24 @@ var openai = {
3532
3569
  }
3533
3570
  };
3534
3571
 
3572
+ // src/refusals.ts
3573
+ var DECLARATION_REFUSAL = /* @__PURE__ */ Symbol.for("palbase.backend.declarationRefusal");
3574
+ var DeclarationRefused = class extends Error {
3575
+ static {
3576
+ __name(this, "DeclarationRefused");
3577
+ }
3578
+ /** @see DECLARATION_REFUSAL — realm-safe, unlike `instanceof`. */
3579
+ [DECLARATION_REFUSAL] = true;
3580
+ constructor(message) {
3581
+ super(message);
3582
+ this.name = "DeclarationRefused";
3583
+ }
3584
+ };
3585
+ function isDeclarationRefused(e) {
3586
+ return typeof e === "object" && e !== null && e[DECLARATION_REFUSAL] === true;
3587
+ }
3588
+ __name(isDeclarationRefused, "isDeclarationRefused");
3589
+
3535
3590
  // src/db/env-gen.ts
3536
3591
  function baseTsType(def) {
3537
3592
  switch (def.type) {
@@ -3568,9 +3623,21 @@ function baseTsType(def) {
3568
3623
  }
3569
3624
  }
3570
3625
  __name(baseTsType, "baseTsType");
3626
+ function pgBrand(def) {
3627
+ if (def.type === "enum") {
3628
+ const values = [
3629
+ ...def.enumValues ?? []
3630
+ ].sort();
3631
+ return values.length === 0 ? "enum" : `enum:${values.join("|")}`;
3632
+ }
3633
+ return def.type;
3634
+ }
3635
+ __name(pgBrand, "pgBrand");
3571
3636
  function rowType(def) {
3572
3637
  const base = baseTsType(def);
3573
- return def.nullable ? `${base} | null` : base;
3638
+ if (base === "unknown") return def.nullable ? `${base} | null` : base;
3639
+ const branded = `Pg<${base}, ${JSON.stringify(pgBrand(def))}>`;
3640
+ return def.nullable ? `${branded} | null` : branded;
3574
3641
  }
3575
3642
  __name(rowType, "rowType");
3576
3643
  function optionalOnInsert(def) {
@@ -3613,12 +3680,12 @@ function buildRelations(schemas) {
3613
3680
  const held = names.get(name);
3614
3681
  if (held !== void 0) {
3615
3682
  if (held.def.owns === true && origin.def.owns === true) {
3616
- throw new Error(`table "${tableKey}" declares TWO owner columns (${held.column}, ${origin.column}) \u2014 a table has at most ONE ownedByUser(). If the other column only POINTS at a user, declare it userRef({ onDelete: \u2026 }) instead.`);
3683
+ throw new DeclarationRefused(`table "${tableKey}" declares TWO owner columns (${held.column}, ${origin.column}) \u2014 a table has at most ONE ownedByUser(). If the other column only POINTS at a user, declare it userRef({ onDelete: \u2026 }) instead.`);
3617
3684
  }
3618
3685
  const heldFix = renameCall(held);
3619
3686
  const originFix = renameCall(origin);
3620
3687
  const remedy = heldFix === originFix ? `rename one of them: ${heldFix}` : `rename one of them \u2014 "${held.table}.${held.column}": ${heldFix}; "${origin.table}.${origin.column}": ${originFix}`;
3621
- throw new Error(`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`);
3688
+ throw new DeclarationRefused(`table "${tableKey}": ${describeOrigin(held)} and ${describeOrigin(origin)} both resolve to the relation name "${name}" \u2014 ${remedy}.`);
3622
3689
  }
3623
3690
  names.set(name, origin);
3624
3691
  out.get(tableKey)?.push(edge);
@@ -3721,6 +3788,17 @@ ${schemaBlocks.join("\n")}
3721
3788
  // is typed with no import and no generic. Schemas other than \`public\` land
3722
3789
  // under \`Schemas\`, reached with \`Database.schema("<name>").tables.*\`.
3723
3790
 
3791
+ /**
3792
+ * Kolonun POSTGRES tipini tipte tasiyan marka.
3793
+ *
3794
+ * __pg ISTEGE BAGLI oldugu icin satir hala duz string/number gibi okunur ve duz
3795
+ * bir degerle yazilir \u2014 marka yalniz col() ve now() karsilastirma kurallarinin
3796
+ * gordugu bir bilgidir. TypeScript numeric, bigint, text, uuid ve timestamp'i
3797
+ * tek string'e dusurdugu icin bu bilgi olmadan integer<->numeric (gecerli) ile
3798
+ * integer<->text (gecersiz) ayirt edilemiyordu.
3799
+ */
3800
+ type Pg<T, N extends string> = T & { readonly __pg?: N };
3801
+
3724
3802
  declare module "@palbase/backend/env" {
3725
3803
  interface Tables {${body}}
3726
3804
  interface Schemas {${schemasBody}}
@@ -4685,6 +4763,14 @@ var DiError = class extends Error {
4685
4763
  path;
4686
4764
  at;
4687
4765
  fixes;
4766
+ /**
4767
+ * EVERY `DiKind` IS A FACT ABOUT THE AUTHOR'S DECLARATIONS — an unresolvable
4768
+ * dependency, a cycle, a class no module owns. Not one of them is something
4769
+ * the environment could change, so restarting re-reads the same bytes and
4770
+ * fails identically. The cure is a new artifact, and the tag is how the
4771
+ * runtime learns that without matching on wording.
4772
+ */
4773
+ [DECLARATION_REFUSAL] = true;
4688
4774
  constructor(kind, path, at, detail, fixes) {
4689
4775
  super(`
4690
4776
  Kind: ${kind}
@@ -5188,8 +5274,10 @@ var import_zod2 = require("zod");
5188
5274
  Client,
5189
5275
  Conflict,
5190
5276
  Controller,
5277
+ DECLARATION_REFUSAL,
5191
5278
  Database,
5192
5279
  DeadlockDetected,
5280
+ DeclarationRefused,
5193
5281
  Delete,
5194
5282
  Deny,
5195
5283
  DiError,
@@ -5291,6 +5379,7 @@ var import_zod2 = require("zod");
5291
5379
  index,
5292
5380
  installationRef,
5293
5381
  integer,
5382
+ isDeclarationRefused,
5294
5383
  isPalbaseExtension,
5295
5384
  isRetryable,
5296
5385
  jobsOf,