@palbase/backend 27.1.0 → 29.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 +284 -50
- package/dist/bin/palbase-backend.cjs.map +1 -1
- package/dist/bin/palbase-backend.js +4 -4
- package/dist/{chunk-JVZQCC77.js → chunk-3TUJWHC2.js} +8 -3
- package/dist/chunk-3TUJWHC2.js.map +1 -0
- package/dist/{chunk-EB3TUX5J.js → chunk-DHJ3SYAE.js} +251 -50
- package/dist/chunk-DHJ3SYAE.js.map +1 -0
- package/dist/{chunk-XABHGMUT.js → chunk-ENZ2RFFJ.js} +2 -2
- package/dist/{chunk-BQN723PL.js → chunk-ESSQ3YML.js} +73 -7
- package/dist/chunk-ESSQ3YML.js.map +1 -0
- package/dist/{chunk-OZKSM3JW.js → chunk-SG4UTNOP.js} +7 -3
- package/dist/chunk-SG4UTNOP.js.map +1 -0
- package/dist/db/index.cjs +8 -2
- package/dist/db/index.cjs.map +1 -1
- package/dist/db/index.d.cts +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +3 -3
- package/dist/engine/index.cjs +294 -50
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +3 -3
- package/dist/engine/index.d.ts +3 -3
- package/dist/engine/index.js +11 -4
- package/dist/{index-V7QRh1wg.d.ts → index-BOe82fsK.d.ts} +256 -19
- package/dist/{index-CAKOgAlP.d.ts → index-BYDUKexK.d.ts} +139 -10
- package/dist/{index-H-0qv5d4.d.cts → index-BZfmdRmh.d.cts} +139 -10
- package/dist/{index-CgE4sVhg.d.cts → index-ChvoVczS.d.cts} +256 -19
- package/dist/index.cjs +81 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -22
- package/dist/index.d.ts +6 -22
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/openapi/index.d.cts +2 -2
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{registry-DHsPDY0_.d.cts → registry-B2KfKWv1.d.cts} +1 -1
- package/dist/{registry-4EI8aaFs.d.ts → registry-DaqHsOq8.d.ts} +1 -1
- package/dist/test/index.cjs +129 -6
- 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 +126 -6
- package/dist/test/index.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/database.md +118 -1
- package/docs/llms-full.txt +119 -2
- package/package.json +1 -1
- package/template/package.json +1 -1
- package/dist/chunk-BQN723PL.js.map +0 -1
- package/dist/chunk-EB3TUX5J.js.map +0 -1
- package/dist/chunk-JVZQCC77.js.map +0 -1
- package/dist/chunk-OZKSM3JW.js.map +0 -1
- /package/dist/{chunk-XABHGMUT.js.map → chunk-ENZ2RFFJ.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-
|
|
1
|
+
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-BOe82fsK.js';
|
|
2
2
|
import { T as Token } from './module-Dl1KFVtc.js';
|
|
3
|
-
import { R as RouteMeta } from './registry-
|
|
3
|
+
import { R as RouteMeta } from './registry-DaqHsOq8.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* engine/config.ts — settings from the environment, and the gate that refuses
|
|
@@ -66,7 +66,15 @@ interface EngineConfig {
|
|
|
66
66
|
dbServiceRole: string;
|
|
67
67
|
poolMax: number;
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* THE ENVIRONMENT THIS STACK WAS HANDED IS UNUSABLE. Carries the missing names.
|
|
71
|
+
*
|
|
72
|
+
* ONLY the environment. A refusal about the author's own declarations is
|
|
73
|
+
* `DeclarationRefused` (see `src/refusals.ts`) and the difference is not
|
|
74
|
+
* severity, it is the CURE: no push fixes a missing DATABASE_URL, so the
|
|
75
|
+
* runtime must keep treating this one as fatal rather than waiting for an
|
|
76
|
+
* artifact that would change nothing.
|
|
77
|
+
*/
|
|
70
78
|
declare class BootRefused extends Error {
|
|
71
79
|
readonly missing: readonly string[];
|
|
72
80
|
constructor(missing: readonly string[], message: string);
|
|
@@ -171,10 +179,27 @@ interface FindManyOptions {
|
|
|
171
179
|
* refused without it — see `offsetClause`. */
|
|
172
180
|
offset?: number;
|
|
173
181
|
}
|
|
174
|
-
/** The six string-keyed operations, plus an interactive `transaction`. */
|
|
175
182
|
declare function createOps(tx: TxLike): {
|
|
176
183
|
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
177
184
|
insert(table: string, data: Row): Promise<Row>;
|
|
185
|
+
/**
|
|
186
|
+
* Çok satırı TEK statement'la ekle.
|
|
187
|
+
*
|
|
188
|
+
* Motor bunu zaten yapıyordu ve yalnız PLAN yolundan erişilebiliyordu
|
|
189
|
+
* (`tx.public.x.insertMany`). Dışarıda tek kapı `insert(row)` olduğu için
|
|
190
|
+
* "şu 200 satırı yaz" ya 200 gidiş-dönüş ya da ham SQL oluyordu — ölçüldü:
|
|
191
|
+
* bir müşteri projesinde bir seed rutini satırları tek tek siliyor
|
|
192
|
+
* (`deleteMany` VARKEN) ve tek tek ekliyor.
|
|
193
|
+
*
|
|
194
|
+
* SATIRLARIN ANAHTAR KÜMESİ AYNI OLMAK ZORUNDA. Kolon listesi tek bir
|
|
195
|
+
* statement'ta paylaşıldığı için ilk satırdan türer; farklı anahtar taşıyan
|
|
196
|
+
* bir satırın fazla kolonu SESSİZCE YAZILMAZDI. Eksik kolon için `null`
|
|
197
|
+
* yazın ya da varsayılanı istiyorsanız o satırları ayrı çağrıda ekleyin.
|
|
198
|
+
*/
|
|
199
|
+
insertMany(table: string, rows: readonly Row[], opts?: {
|
|
200
|
+
onConflict: readonly string[];
|
|
201
|
+
action?: "ignore" | "update";
|
|
202
|
+
}): Promise<Row[]>;
|
|
178
203
|
/**
|
|
179
204
|
* Bir ADI kilitle — satırı değil (FR-054).
|
|
180
205
|
*
|
|
@@ -266,7 +291,9 @@ declare function createOps(tx: TxLike): {
|
|
|
266
291
|
* should not silently succeed. Callers who mean every row say so with a
|
|
267
292
|
* predicate that is true for every row.
|
|
268
293
|
*/
|
|
269
|
-
updateMany(table: string, where: Row, set: Row
|
|
294
|
+
updateMany(table: string, where: Row, set: Row, opts?: {
|
|
295
|
+
returning?: boolean;
|
|
296
|
+
}): Promise<Row[] | number>;
|
|
270
297
|
/**
|
|
271
298
|
* Delete every row the filter matches, in ONE statement; resolves to how
|
|
272
299
|
* many went. Same filter language, same empty-filter refusal as
|
|
@@ -282,6 +309,27 @@ declare function createOps(tx: TxLike): {
|
|
|
282
309
|
* An empty filter is legitimate HERE: counting a whole table is a read, and
|
|
283
310
|
* reads do not destroy anything.
|
|
284
311
|
*/
|
|
312
|
+
/**
|
|
313
|
+
* Toplama — `count`'un yanına `sum`/`avg`/`min`/`max` ve `groupBy`.
|
|
314
|
+
*
|
|
315
|
+
* Var olma nedeni: bunlar olmadan "bu hesabın toplamı" ya `$query`'ye ya da
|
|
316
|
+
* TÜM satırları çekip JS'te toplamaya düşüyor. İkincisi hem N+1 hem de para
|
|
317
|
+
* için YANLIŞ — `numeric` JS `number`'ına uğradığı anda kesinliğini
|
|
318
|
+
* kaybeder.
|
|
319
|
+
*
|
|
320
|
+
* `groupBy` verilirse SATIRLAR döner, verilmezse TEK sonuç. Boş kümede
|
|
321
|
+
* Postgres NULL döndürür, 0 değil — ve bu SDK onu `null` olarak geçiriyor:
|
|
322
|
+
* "hiç satır yoktu" ile "toplam sıfırdı" farklı şeyler.
|
|
323
|
+
*/
|
|
324
|
+
aggregate(table: string, q?: {
|
|
325
|
+
where?: Row;
|
|
326
|
+
sum?: readonly string[];
|
|
327
|
+
avg?: readonly string[];
|
|
328
|
+
min?: readonly string[];
|
|
329
|
+
max?: readonly string[];
|
|
330
|
+
count?: boolean;
|
|
331
|
+
groupBy?: readonly string[];
|
|
332
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
285
333
|
count(table: string, where?: Row): Promise<number>;
|
|
286
334
|
findById(table: string, id: string): Promise<Row | null>;
|
|
287
335
|
findMany(table: string, query?: Row, opts?: FindManyOptions): Promise<Row[]>;
|
|
@@ -527,6 +575,80 @@ declare function createRequestDatabase(sql: SqlDriver, identity: {
|
|
|
527
575
|
claimsJson: string;
|
|
528
576
|
}): RequestDatabase;
|
|
529
577
|
|
|
578
|
+
/**
|
|
579
|
+
* The two ways a stack refuses to boot — and they are two because their CURES
|
|
580
|
+
* are two.
|
|
581
|
+
*
|
|
582
|
+
* A LEAF MODULE ON PURPOSE. `db/` does not import from `engine/` and must not
|
|
583
|
+
* start: the schema layer is below the engine, and a refusal both of them raise
|
|
584
|
+
* cannot live in either. Anything imported here would invert that.
|
|
585
|
+
*
|
|
586
|
+
* WHY THE SPLIT EXISTS AT ALL — measured live on 2026-09-04.
|
|
587
|
+
*
|
|
588
|
+
* `8qitbtucm` ran for days on an image whose `setSchema` did not build
|
|
589
|
+
* relations. Moved onto one that does, the same artifact hit
|
|
590
|
+
* `buildRelations` at boot, threw a bare `Error`, and the runtime — which waits
|
|
591
|
+
* only on its own `ArtifactRefused` — treated it as fatal. The supervisor took
|
|
592
|
+
* the pod down, palsvc with it. CrashLoopBackOff, back-off 5m, and palsvc is
|
|
593
|
+
* THE PROCESS THAT ACCEPTS THE PUSH the message asks for.
|
|
594
|
+
*
|
|
595
|
+
* That is verbatim the lesson `v2/runtime/src/loader.ts` already carries for
|
|
596
|
+
* ABI refusals: *"the cure was named in the error and made impossible by the
|
|
597
|
+
* exit that carried it."* It cost a tenant a third time because the second
|
|
598
|
+
* refusal had no type to be recognised by.
|
|
599
|
+
*
|
|
600
|
+
* SO THE RULE IS THE CURE, NOT THE SEVERITY:
|
|
601
|
+
*
|
|
602
|
+
* {@link DeclarationRefused} — what was PUSHED cannot be built. Restarting
|
|
603
|
+
* re-reads the same bytes and fails identically; only a new artifact
|
|
604
|
+
* changes the answer. The runtime WAITS on this, keeps palsvc alive, and
|
|
605
|
+
* says the reason out loud.
|
|
606
|
+
*
|
|
607
|
+
* {@link BootRefused} — the ENVIRONMENT this stack was handed is unusable
|
|
608
|
+
* (no DATABASE_URL, an unparseable PORT, no SQL driver). No push fixes it;
|
|
609
|
+
* waiting for one would be a lie told in a log line forever. Stays fatal.
|
|
610
|
+
*
|
|
611
|
+
* NOT A MESSAGE PATTERN. The runtime's loader already says why: *"The
|
|
612
|
+
* distinction is the loader's TYPE, not a pattern over its wording."* A gate
|
|
613
|
+
* that reads wording drifts from the thing it claims to measure the first time
|
|
614
|
+
* someone improves an error message.
|
|
615
|
+
*/
|
|
616
|
+
/**
|
|
617
|
+
* The tag that survives a realm boundary.
|
|
618
|
+
*
|
|
619
|
+
* `instanceof` compares constructor identity, and identity is per module
|
|
620
|
+
* instance. In the pod today the runtime and the bundle share one install
|
|
621
|
+
* (measured: both frames resolve to `/app/node_modules/@palbase/backend`), so
|
|
622
|
+
* `instanceof` would work — but it works by a coincidence of packaging, and a
|
|
623
|
+
* bundle that ever carries its own copy would make every declaration refusal
|
|
624
|
+
* silently fatal again. `Symbol.for` reads from the process-wide registry, so
|
|
625
|
+
* the tag means the same thing in every copy.
|
|
626
|
+
*
|
|
627
|
+
* Exported so the runtime can recognise the refusal without importing the
|
|
628
|
+
* class — see {@link isDeclarationRefused}.
|
|
629
|
+
*/
|
|
630
|
+
declare const DECLARATION_REFUSAL: unique symbol;
|
|
631
|
+
/**
|
|
632
|
+
* What was pushed cannot be built. The cure is a NEW ARTIFACT.
|
|
633
|
+
*
|
|
634
|
+
* Thrown by the declaration layer — relation naming, ownership, entry points —
|
|
635
|
+
* wherever a fact about the author's code makes the app impossible to
|
|
636
|
+
* construct. Never thrown for anything the environment could change.
|
|
637
|
+
*/
|
|
638
|
+
declare class DeclarationRefused extends Error {
|
|
639
|
+
/** @see DECLARATION_REFUSAL — realm-safe, unlike `instanceof`. */
|
|
640
|
+
readonly [DECLARATION_REFUSAL]: true;
|
|
641
|
+
constructor(message: string);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* True for a refusal whose only cure is a new artifact — across realms.
|
|
645
|
+
*
|
|
646
|
+
* Takes `unknown` because every caller is a `catch`. A non-object, a null, a
|
|
647
|
+
* plain `Error`: all false, and false is the safe answer — it means "keep
|
|
648
|
+
* treating this as fatal", which is what the code did before this type existed.
|
|
649
|
+
*/
|
|
650
|
+
declare function isDeclarationRefused(e: unknown): e is DeclarationRefused;
|
|
651
|
+
|
|
530
652
|
/**
|
|
531
653
|
* How a container refuses.
|
|
532
654
|
*
|
|
@@ -550,6 +672,14 @@ declare class DiError extends Error {
|
|
|
550
672
|
readonly path: string[];
|
|
551
673
|
readonly at: string;
|
|
552
674
|
readonly fixes: string[];
|
|
675
|
+
/**
|
|
676
|
+
* EVERY `DiKind` IS A FACT ABOUT THE AUTHOR'S DECLARATIONS — an unresolvable
|
|
677
|
+
* dependency, a cycle, a class no module owns. Not one of them is something
|
|
678
|
+
* the environment could change, so restarting re-reads the same bytes and
|
|
679
|
+
* fails identically. The cure is a new artifact, and the tag is how the
|
|
680
|
+
* runtime learns that without matching on wording.
|
|
681
|
+
*/
|
|
682
|
+
readonly [DECLARATION_REFUSAL]: true;
|
|
553
683
|
constructor(kind: DiKind, path: string[], at: string, detail: string, fixes: string[]);
|
|
554
684
|
}
|
|
555
685
|
/** How often a module appears in the OTHERS' `imports`. */
|
|
@@ -702,6 +832,9 @@ declare class AuthVerifier {
|
|
|
702
832
|
interface EffectiveAuth {
|
|
703
833
|
required: boolean;
|
|
704
834
|
role?: string;
|
|
835
|
+
/** The permission the route demands, as `resource.action`. Resolved against
|
|
836
|
+
* `auth.has_permission(...)` at the gate — see AuthConfig.permission. */
|
|
837
|
+
permission?: string;
|
|
705
838
|
verifiedEmail: boolean;
|
|
706
839
|
}
|
|
707
840
|
/**
|
|
@@ -921,10 +1054,6 @@ interface App {
|
|
|
921
1054
|
*/
|
|
922
1055
|
readonly container: Container;
|
|
923
1056
|
}
|
|
924
|
-
/**
|
|
925
|
-
* Build the app. Fails fast: the database is reached here, at boot, rather than
|
|
926
|
-
* on the first request that needs it.
|
|
927
|
-
*/
|
|
928
1057
|
declare function createApp(opts: CreateAppOptions): Promise<App>;
|
|
929
1058
|
|
|
930
|
-
export { type App as A, BootRefused as B, type Container as C,
|
|
1059
|
+
export { type App as A, BootRefused as B, type Container as C, DECLARATION_REFUSAL as D, type EgressPolicy as E, quoteIdent as F, scrubSecrets as G, withTables as H, type ModuleClients as M, RateLimiter as R, type ScrubResult as S, DeclarationRefused as a, DiError as b, type DiKind as c, type ModulePressure as d, assertNoOrphanEntryPoints as e, buildContainer as f, AuthVerifier as g, type CreateAppOptions as h, isDeclarationRefused as i, type EngineConfig as j, type RequestDatabase as k, type RouteEntry as l, type RuntimeHooks as m, type SqlDriver as n, type SqlTx as o, buildRouteTable as p, createApp as q, createLazyTransaction as r, createOps as s, createRequestDatabase as t, effectiveAuth as u, hostAllowed as v, installEgressFence as w, loadConfig as x, makeMemoryCache as y, matchRoute as z };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-
|
|
1
|
+
import { D as DBClient, a as DBOps, T as TxPlanBody, b as TxPlanResponse, A as AuthSpec, C as CacheClient, c as RuntimeServices, _ as __runWithRuntime, d as __requestALS } from './index-ChvoVczS.cjs';
|
|
2
2
|
import { T as Token } from './module-Dl1KFVtc.cjs';
|
|
3
|
-
import { R as RouteMeta } from './registry-
|
|
3
|
+
import { R as RouteMeta } from './registry-B2KfKWv1.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* engine/config.ts — settings from the environment, and the gate that refuses
|
|
@@ -66,7 +66,15 @@ interface EngineConfig {
|
|
|
66
66
|
dbServiceRole: string;
|
|
67
67
|
poolMax: number;
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* THE ENVIRONMENT THIS STACK WAS HANDED IS UNUSABLE. Carries the missing names.
|
|
71
|
+
*
|
|
72
|
+
* ONLY the environment. A refusal about the author's own declarations is
|
|
73
|
+
* `DeclarationRefused` (see `src/refusals.ts`) and the difference is not
|
|
74
|
+
* severity, it is the CURE: no push fixes a missing DATABASE_URL, so the
|
|
75
|
+
* runtime must keep treating this one as fatal rather than waiting for an
|
|
76
|
+
* artifact that would change nothing.
|
|
77
|
+
*/
|
|
70
78
|
declare class BootRefused extends Error {
|
|
71
79
|
readonly missing: readonly string[];
|
|
72
80
|
constructor(missing: readonly string[], message: string);
|
|
@@ -171,10 +179,27 @@ interface FindManyOptions {
|
|
|
171
179
|
* refused without it — see `offsetClause`. */
|
|
172
180
|
offset?: number;
|
|
173
181
|
}
|
|
174
|
-
/** The six string-keyed operations, plus an interactive `transaction`. */
|
|
175
182
|
declare function createOps(tx: TxLike): {
|
|
176
183
|
query<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
177
184
|
insert(table: string, data: Row): Promise<Row>;
|
|
185
|
+
/**
|
|
186
|
+
* Çok satırı TEK statement'la ekle.
|
|
187
|
+
*
|
|
188
|
+
* Motor bunu zaten yapıyordu ve yalnız PLAN yolundan erişilebiliyordu
|
|
189
|
+
* (`tx.public.x.insertMany`). Dışarıda tek kapı `insert(row)` olduğu için
|
|
190
|
+
* "şu 200 satırı yaz" ya 200 gidiş-dönüş ya da ham SQL oluyordu — ölçüldü:
|
|
191
|
+
* bir müşteri projesinde bir seed rutini satırları tek tek siliyor
|
|
192
|
+
* (`deleteMany` VARKEN) ve tek tek ekliyor.
|
|
193
|
+
*
|
|
194
|
+
* SATIRLARIN ANAHTAR KÜMESİ AYNI OLMAK ZORUNDA. Kolon listesi tek bir
|
|
195
|
+
* statement'ta paylaşıldığı için ilk satırdan türer; farklı anahtar taşıyan
|
|
196
|
+
* bir satırın fazla kolonu SESSİZCE YAZILMAZDI. Eksik kolon için `null`
|
|
197
|
+
* yazın ya da varsayılanı istiyorsanız o satırları ayrı çağrıda ekleyin.
|
|
198
|
+
*/
|
|
199
|
+
insertMany(table: string, rows: readonly Row[], opts?: {
|
|
200
|
+
onConflict: readonly string[];
|
|
201
|
+
action?: "ignore" | "update";
|
|
202
|
+
}): Promise<Row[]>;
|
|
178
203
|
/**
|
|
179
204
|
* Bir ADI kilitle — satırı değil (FR-054).
|
|
180
205
|
*
|
|
@@ -266,7 +291,9 @@ declare function createOps(tx: TxLike): {
|
|
|
266
291
|
* should not silently succeed. Callers who mean every row say so with a
|
|
267
292
|
* predicate that is true for every row.
|
|
268
293
|
*/
|
|
269
|
-
updateMany(table: string, where: Row, set: Row
|
|
294
|
+
updateMany(table: string, where: Row, set: Row, opts?: {
|
|
295
|
+
returning?: boolean;
|
|
296
|
+
}): Promise<Row[] | number>;
|
|
270
297
|
/**
|
|
271
298
|
* Delete every row the filter matches, in ONE statement; resolves to how
|
|
272
299
|
* many went. Same filter language, same empty-filter refusal as
|
|
@@ -282,6 +309,27 @@ declare function createOps(tx: TxLike): {
|
|
|
282
309
|
* An empty filter is legitimate HERE: counting a whole table is a read, and
|
|
283
310
|
* reads do not destroy anything.
|
|
284
311
|
*/
|
|
312
|
+
/**
|
|
313
|
+
* Toplama — `count`'un yanına `sum`/`avg`/`min`/`max` ve `groupBy`.
|
|
314
|
+
*
|
|
315
|
+
* Var olma nedeni: bunlar olmadan "bu hesabın toplamı" ya `$query`'ye ya da
|
|
316
|
+
* TÜM satırları çekip JS'te toplamaya düşüyor. İkincisi hem N+1 hem de para
|
|
317
|
+
* için YANLIŞ — `numeric` JS `number`'ına uğradığı anda kesinliğini
|
|
318
|
+
* kaybeder.
|
|
319
|
+
*
|
|
320
|
+
* `groupBy` verilirse SATIRLAR döner, verilmezse TEK sonuç. Boş kümede
|
|
321
|
+
* Postgres NULL döndürür, 0 değil — ve bu SDK onu `null` olarak geçiriyor:
|
|
322
|
+
* "hiç satır yoktu" ile "toplam sıfırdı" farklı şeyler.
|
|
323
|
+
*/
|
|
324
|
+
aggregate(table: string, q?: {
|
|
325
|
+
where?: Row;
|
|
326
|
+
sum?: readonly string[];
|
|
327
|
+
avg?: readonly string[];
|
|
328
|
+
min?: readonly string[];
|
|
329
|
+
max?: readonly string[];
|
|
330
|
+
count?: boolean;
|
|
331
|
+
groupBy?: readonly string[];
|
|
332
|
+
}): Promise<Record<string, unknown> | Record<string, unknown>[]>;
|
|
285
333
|
count(table: string, where?: Row): Promise<number>;
|
|
286
334
|
findById(table: string, id: string): Promise<Row | null>;
|
|
287
335
|
findMany(table: string, query?: Row, opts?: FindManyOptions): Promise<Row[]>;
|
|
@@ -527,6 +575,80 @@ declare function createRequestDatabase(sql: SqlDriver, identity: {
|
|
|
527
575
|
claimsJson: string;
|
|
528
576
|
}): RequestDatabase;
|
|
529
577
|
|
|
578
|
+
/**
|
|
579
|
+
* The two ways a stack refuses to boot — and they are two because their CURES
|
|
580
|
+
* are two.
|
|
581
|
+
*
|
|
582
|
+
* A LEAF MODULE ON PURPOSE. `db/` does not import from `engine/` and must not
|
|
583
|
+
* start: the schema layer is below the engine, and a refusal both of them raise
|
|
584
|
+
* cannot live in either. Anything imported here would invert that.
|
|
585
|
+
*
|
|
586
|
+
* WHY THE SPLIT EXISTS AT ALL — measured live on 2026-09-04.
|
|
587
|
+
*
|
|
588
|
+
* `8qitbtucm` ran for days on an image whose `setSchema` did not build
|
|
589
|
+
* relations. Moved onto one that does, the same artifact hit
|
|
590
|
+
* `buildRelations` at boot, threw a bare `Error`, and the runtime — which waits
|
|
591
|
+
* only on its own `ArtifactRefused` — treated it as fatal. The supervisor took
|
|
592
|
+
* the pod down, palsvc with it. CrashLoopBackOff, back-off 5m, and palsvc is
|
|
593
|
+
* THE PROCESS THAT ACCEPTS THE PUSH the message asks for.
|
|
594
|
+
*
|
|
595
|
+
* That is verbatim the lesson `v2/runtime/src/loader.ts` already carries for
|
|
596
|
+
* ABI refusals: *"the cure was named in the error and made impossible by the
|
|
597
|
+
* exit that carried it."* It cost a tenant a third time because the second
|
|
598
|
+
* refusal had no type to be recognised by.
|
|
599
|
+
*
|
|
600
|
+
* SO THE RULE IS THE CURE, NOT THE SEVERITY:
|
|
601
|
+
*
|
|
602
|
+
* {@link DeclarationRefused} — what was PUSHED cannot be built. Restarting
|
|
603
|
+
* re-reads the same bytes and fails identically; only a new artifact
|
|
604
|
+
* changes the answer. The runtime WAITS on this, keeps palsvc alive, and
|
|
605
|
+
* says the reason out loud.
|
|
606
|
+
*
|
|
607
|
+
* {@link BootRefused} — the ENVIRONMENT this stack was handed is unusable
|
|
608
|
+
* (no DATABASE_URL, an unparseable PORT, no SQL driver). No push fixes it;
|
|
609
|
+
* waiting for one would be a lie told in a log line forever. Stays fatal.
|
|
610
|
+
*
|
|
611
|
+
* NOT A MESSAGE PATTERN. The runtime's loader already says why: *"The
|
|
612
|
+
* distinction is the loader's TYPE, not a pattern over its wording."* A gate
|
|
613
|
+
* that reads wording drifts from the thing it claims to measure the first time
|
|
614
|
+
* someone improves an error message.
|
|
615
|
+
*/
|
|
616
|
+
/**
|
|
617
|
+
* The tag that survives a realm boundary.
|
|
618
|
+
*
|
|
619
|
+
* `instanceof` compares constructor identity, and identity is per module
|
|
620
|
+
* instance. In the pod today the runtime and the bundle share one install
|
|
621
|
+
* (measured: both frames resolve to `/app/node_modules/@palbase/backend`), so
|
|
622
|
+
* `instanceof` would work — but it works by a coincidence of packaging, and a
|
|
623
|
+
* bundle that ever carries its own copy would make every declaration refusal
|
|
624
|
+
* silently fatal again. `Symbol.for` reads from the process-wide registry, so
|
|
625
|
+
* the tag means the same thing in every copy.
|
|
626
|
+
*
|
|
627
|
+
* Exported so the runtime can recognise the refusal without importing the
|
|
628
|
+
* class — see {@link isDeclarationRefused}.
|
|
629
|
+
*/
|
|
630
|
+
declare const DECLARATION_REFUSAL: unique symbol;
|
|
631
|
+
/**
|
|
632
|
+
* What was pushed cannot be built. The cure is a NEW ARTIFACT.
|
|
633
|
+
*
|
|
634
|
+
* Thrown by the declaration layer — relation naming, ownership, entry points —
|
|
635
|
+
* wherever a fact about the author's code makes the app impossible to
|
|
636
|
+
* construct. Never thrown for anything the environment could change.
|
|
637
|
+
*/
|
|
638
|
+
declare class DeclarationRefused extends Error {
|
|
639
|
+
/** @see DECLARATION_REFUSAL — realm-safe, unlike `instanceof`. */
|
|
640
|
+
readonly [DECLARATION_REFUSAL]: true;
|
|
641
|
+
constructor(message: string);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* True for a refusal whose only cure is a new artifact — across realms.
|
|
645
|
+
*
|
|
646
|
+
* Takes `unknown` because every caller is a `catch`. A non-object, a null, a
|
|
647
|
+
* plain `Error`: all false, and false is the safe answer — it means "keep
|
|
648
|
+
* treating this as fatal", which is what the code did before this type existed.
|
|
649
|
+
*/
|
|
650
|
+
declare function isDeclarationRefused(e: unknown): e is DeclarationRefused;
|
|
651
|
+
|
|
530
652
|
/**
|
|
531
653
|
* How a container refuses.
|
|
532
654
|
*
|
|
@@ -550,6 +672,14 @@ declare class DiError extends Error {
|
|
|
550
672
|
readonly path: string[];
|
|
551
673
|
readonly at: string;
|
|
552
674
|
readonly fixes: string[];
|
|
675
|
+
/**
|
|
676
|
+
* EVERY `DiKind` IS A FACT ABOUT THE AUTHOR'S DECLARATIONS — an unresolvable
|
|
677
|
+
* dependency, a cycle, a class no module owns. Not one of them is something
|
|
678
|
+
* the environment could change, so restarting re-reads the same bytes and
|
|
679
|
+
* fails identically. The cure is a new artifact, and the tag is how the
|
|
680
|
+
* runtime learns that without matching on wording.
|
|
681
|
+
*/
|
|
682
|
+
readonly [DECLARATION_REFUSAL]: true;
|
|
553
683
|
constructor(kind: DiKind, path: string[], at: string, detail: string, fixes: string[]);
|
|
554
684
|
}
|
|
555
685
|
/** How often a module appears in the OTHERS' `imports`. */
|
|
@@ -702,6 +832,9 @@ declare class AuthVerifier {
|
|
|
702
832
|
interface EffectiveAuth {
|
|
703
833
|
required: boolean;
|
|
704
834
|
role?: string;
|
|
835
|
+
/** The permission the route demands, as `resource.action`. Resolved against
|
|
836
|
+
* `auth.has_permission(...)` at the gate — see AuthConfig.permission. */
|
|
837
|
+
permission?: string;
|
|
705
838
|
verifiedEmail: boolean;
|
|
706
839
|
}
|
|
707
840
|
/**
|
|
@@ -921,10 +1054,6 @@ interface App {
|
|
|
921
1054
|
*/
|
|
922
1055
|
readonly container: Container;
|
|
923
1056
|
}
|
|
924
|
-
/**
|
|
925
|
-
* Build the app. Fails fast: the database is reached here, at boot, rather than
|
|
926
|
-
* on the first request that needs it.
|
|
927
|
-
*/
|
|
928
1057
|
declare function createApp(opts: CreateAppOptions): Promise<App>;
|
|
929
1058
|
|
|
930
|
-
export { type App as A, BootRefused as B, type Container as C,
|
|
1059
|
+
export { type App as A, BootRefused as B, type Container as C, DECLARATION_REFUSAL as D, type EgressPolicy as E, quoteIdent as F, scrubSecrets as G, withTables as H, type ModuleClients as M, RateLimiter as R, type ScrubResult as S, DeclarationRefused as a, DiError as b, type DiKind as c, type ModulePressure as d, assertNoOrphanEntryPoints as e, buildContainer as f, AuthVerifier as g, type CreateAppOptions as h, isDeclarationRefused as i, type EngineConfig as j, type RequestDatabase as k, type RouteEntry as l, type RuntimeHooks as m, type SqlDriver as n, type SqlTx as o, buildRouteTable as p, createApp as q, createLazyTransaction as r, createOps as s, createRequestDatabase as t, effectiveAuth as u, hostAllowed as v, installEgressFence as w, loadConfig as x, makeMemoryCache as y, matchRoute as z };
|