@objectstack/types 17.2.0 → 17.3.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/CHANGELOG.md +941 -0
- package/dist/index.d.mts +533 -9
- package/dist/index.d.ts +533 -9
- package/dist/index.js +309 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +293 -3
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +12 -3
- package/dist/node.d.ts +12 -3
- package/dist/node.js +198 -2
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +200 -4
- package/dist/node.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TenancyPosture } from '@objectstack/spec/security';
|
|
2
2
|
import { ErrorCode, ApiError, FieldErrorCode } from '@objectstack/spec/api';
|
|
3
|
+
import { Logger } from '@objectstack/spec/contracts';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Degraded-boot reporting, shared by every subsystem that can be told to boot
|
|
@@ -44,6 +45,47 @@ import { ErrorCode, ApiError, FieldErrorCode } from '@objectstack/spec/api';
|
|
|
44
45
|
*/
|
|
45
46
|
declare function emitDegradedBootBanner(message: string): void;
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* [#11343 / #12751] Verified-email predicate over a stored `sys_user` row — a
|
|
50
|
+
* fail-closed ALLOW-LIST over the representations a driver may hand back for
|
|
51
|
+
* the `sys_user.email_verified` boolean column (JS `true`, SQLite `1`, and
|
|
52
|
+
* their stringified forms). Everything else — `false`/`0`, `null`, an ABSENT
|
|
53
|
+
* field on an imported/legacy row, or any representation not listed — reads
|
|
54
|
+
* as UNVERIFIED. Absent-means-unverified is deliberate: treating a missing
|
|
55
|
+
* column as verified would re-open the exact hole this predicate closes for
|
|
56
|
+
* every row that predates the column.
|
|
57
|
+
*
|
|
58
|
+
* ONE resolution, several consumers, by design (#12751) — and since the
|
|
59
|
+
* #11663 platform-admin re-anchor (leg L4) the walled platform-admin
|
|
60
|
+
* ELEVATION GATE this paragraph used to name first is RETIRED: under a
|
|
61
|
+
* walled posture `bootstrapPlatformAdmin` writes no grant row and elevates
|
|
62
|
+
* nobody, it reports. Standing is derived PER REQUEST instead — from a
|
|
63
|
+
* config-anchored verified email, or the legacy unscoped grant row — so the
|
|
64
|
+
* consumer set now includes the authorization derivation itself:
|
|
65
|
+
*
|
|
66
|
+
* - `matchesConfiguredPlatformAdmin` (`@objectstack/core`
|
|
67
|
+
* `security/platform-admin.ts`), read at the one derivation site
|
|
68
|
+
* (`resolve-authz-context.ts` §6b-config), where an UNVERIFIED account
|
|
69
|
+
* holding a declared address confers nothing — and, through it,
|
|
70
|
+
* `plugin-auth`'s last-admin guard, whose administrator enumeration must
|
|
71
|
+
* answer the same question the resolver does;
|
|
72
|
+
* - `resolvePlatformAdminStanding` (`plugin-security`
|
|
73
|
+
* `platform-admin-service.ts`), the read-only standing/audit answer the
|
|
74
|
+
* walled boot reports from, and `isVerifiedPlatformOwnerRow` beside it
|
|
75
|
+
* (`platform-owner-wall-bypass.ts`), the Layer 0 wall bypass;
|
|
76
|
+
* - the walled owner-verification boot diagnostic (`plugin-auth`
|
|
77
|
+
* `walled-owner-verification-path.ts`, where the check decides whether the
|
|
78
|
+
* declared owner's account is already past needing a verification path).
|
|
79
|
+
*
|
|
80
|
+
* They must all answer "is this row verified?" identically — a drift is no
|
|
81
|
+
* longer just a boot warning forecasting a refusal that will not be made, it
|
|
82
|
+
* is a diagnostic, an audit surface or a guard disagreeing with who actually
|
|
83
|
+
* resolves PLATFORM_ADMIN on the next request. `@objectstack/types` is the
|
|
84
|
+
* shared home every one of those packages already resolves
|
|
85
|
+
* `OS_PLATFORM_OWNER_EMAIL` from (`env.ts`).
|
|
86
|
+
*/
|
|
87
|
+
declare function isEmailVerifiedUserRow(row: unknown): boolean;
|
|
88
|
+
|
|
47
89
|
/**
|
|
48
90
|
* Environment-variable helpers shared across `@objectstack/*` packages.
|
|
49
91
|
*
|
|
@@ -142,6 +184,49 @@ declare function resolveMultiOrgEnabled(): boolean;
|
|
|
142
184
|
* enforced is the `tenancy` service's answer (`isolationActive` / `degraded`).
|
|
143
185
|
*/
|
|
144
186
|
declare function resolveTenancyPosture(): TenancyPosture;
|
|
187
|
+
/**
|
|
188
|
+
* The env variable naming the deployment's PLATFORM OWNER account
|
|
189
|
+
* (#11184, the framework leg of cloud#1509).
|
|
190
|
+
*
|
|
191
|
+
* Exported as a constant so every message that names it quotes exactly one
|
|
192
|
+
* spelling: the walled boot guard in plugin-auth, and plugin-security's
|
|
193
|
+
* `bootstrapPlatformAdmin` — its fail-closed backstop for an undeclared or
|
|
194
|
+
* refused config, and the config-derived standing it logs beside it.
|
|
195
|
+
*
|
|
196
|
+
* ⚠️ That second site is no longer an ELEVATION refusal. Since the #11663
|
|
197
|
+
* platform-admin re-anchor (leg L4) the walled `bootstrapPlatformAdmin` writes
|
|
198
|
+
* no grant row and elevates nobody — it reports. Standing is derived PER
|
|
199
|
+
* REQUEST at `resolve-authz-context.ts` §6b-config, from a declared address
|
|
200
|
+
* held on a VERIFIED `sys_user` row.
|
|
201
|
+
*/
|
|
202
|
+
declare const PLATFORM_OWNER_EMAIL_ENV = "OS_PLATFORM_OWNER_EMAIL";
|
|
203
|
+
/**
|
|
204
|
+
* [#11184 / cloud#1509] Resolve the env-declared platform OWNER email —
|
|
205
|
+
* `OS_PLATFORM_OWNER_EMAIL`.
|
|
206
|
+
*
|
|
207
|
+
* Under a WALLED tenancy posture (`group` / `isolated`) the "first registrant
|
|
208
|
+
* becomes owner/platform admin" bootstrap path is REMOVED (maintainer ruling
|
|
209
|
+
* 2026-08-23, verbatim: 「1509 选择 env 指定 owner 邮箱」): on a walled
|
|
210
|
+
* deployment with self-registration reachable, whoever curls the sign-up
|
|
211
|
+
* endpoint first would otherwise receive the cross-tenant `admin_full_access`
|
|
212
|
+
* grant — measured on a real walled SaaS in cloud#1509. Platform admin is
|
|
213
|
+
* granted ONLY to the account whose email matches this variable, and a walled
|
|
214
|
+
* posture with no value declared REFUSES STARTUP (fail-closed, same reasoning
|
|
215
|
+
* as {@link resolveTenancyPosture}'s throw and ADR-0093 D5) rather than
|
|
216
|
+
* silently reverting to first-registrant elevation.
|
|
217
|
+
*
|
|
218
|
+
* The `single` posture never consults this: "first user is owner" is ruled
|
|
219
|
+
* reasonable there and unchanged.
|
|
220
|
+
*
|
|
221
|
+
* Returns the operator's value trimmed, or `undefined` when unset/blank.
|
|
222
|
+
* Comparison against `sys_user.email` is the CONSUMER's job and must be
|
|
223
|
+
* case-insensitive (this resolver echoes what the operator typed so refusal
|
|
224
|
+
* messages can quote it verbatim).
|
|
225
|
+
*
|
|
226
|
+
* Reads `process.env` live on each call, through `globalThis` like the other
|
|
227
|
+
* resolvers here (this package targets non-Node runtimes too).
|
|
228
|
+
*/
|
|
229
|
+
declare function resolvePlatformOwnerEmail(): string | undefined;
|
|
145
230
|
/**
|
|
146
231
|
* Escape hatch for the degraded-tenancy boot guard (ADR-0093 D5).
|
|
147
232
|
*
|
|
@@ -257,6 +342,27 @@ declare function resolveMcpStdioAutoStart(): {
|
|
|
257
342
|
* Deployments that let users self-create orgs SHOULD set a generous cap.
|
|
258
343
|
*/
|
|
259
344
|
declare function resolveOrgLimit(): number | undefined;
|
|
345
|
+
/**
|
|
346
|
+
* Maximum number of MEMBERS a single organization may hold, from
|
|
347
|
+
* `OS_ORG_MEMBERSHIP_LIMIT`. A different question from {@link resolveOrgLimit},
|
|
348
|
+
* which caps how many organizations one user may create.
|
|
349
|
+
*
|
|
350
|
+
* Unset → `undefined`, which the auth plugin forwards as "no cap". That default
|
|
351
|
+
* is a product decision, not an omission: seat entitlements are metered on AI
|
|
352
|
+
* seats, and plain membership is not a billed axis, so nothing about the
|
|
353
|
+
* platform wants a member ceiling.
|
|
354
|
+
*
|
|
355
|
+
* It has to be stated explicitly because better-auth's organization plugin
|
|
356
|
+
* substitutes a vendor default of **100** for an absent `membershipLimit`
|
|
357
|
+
* (`count >= (membershipLimit || 100)`), which reaches the operator as
|
|
358
|
+
* `Organization membership limit reached` — a refusal nobody in this codebase
|
|
359
|
+
* ever chose, on an axis the product does not limit.
|
|
360
|
+
*
|
|
361
|
+
* A deployment that DOES want a ceiling (a pilot, a trial tenant) sets a
|
|
362
|
+
* positive integer here. Non-positive or unparsable values read as unset rather
|
|
363
|
+
* than as zero: a typo must not be the thing that locks an organization.
|
|
364
|
+
*/
|
|
365
|
+
declare function resolveOrgMembershipLimit(): number | undefined;
|
|
260
366
|
/**
|
|
261
367
|
* SINGLE decision point for "is pinyin search recall on?" (#2486).
|
|
262
368
|
*
|
|
@@ -667,7 +773,8 @@ declare function sendOk(res: EnvelopeResponse, data: unknown, status?: number):
|
|
|
667
773
|
* ## `extra` is `ApiError`'s own optional fields, not a `Record`
|
|
668
774
|
*
|
|
669
775
|
* Merged into `error`, and typed as exactly what `ApiErrorSchema` declares
|
|
670
|
-
* beside `code` and `message` — `details`, `category`, `requestId`,
|
|
776
|
+
* beside `code` and `message` — `details`, `category`, `requestId`,
|
|
777
|
+
* `httpStatus`, `declaredCode`, `userMessage`.
|
|
671
778
|
* `details` is the slot for structured context: `package-routes` puts a partial
|
|
672
779
|
* delete's per-item failures there, `settings-routes` the whole
|
|
673
780
|
* `SettingsActionResult`.
|
|
@@ -683,8 +790,80 @@ declare function sendOk(res: EnvelopeResponse, data: unknown, status?: number):
|
|
|
683
790
|
* Closing it at the shared builder is the part that lasts: an undeclared sibling
|
|
684
791
|
* is now a compile error in every module at once, rather than a key that quietly
|
|
685
792
|
* evaporates at the schema boundary in whichever module reintroduces it.
|
|
793
|
+
*
|
|
794
|
+
* ## `declaredCode` — declared by the schema, barred by this writer
|
|
795
|
+
*
|
|
796
|
+
* ADR-0112's 2026-08-17 amendment (#9106, extended to the flat `/data` door by
|
|
797
|
+
* #9232) rules the demote at EVERY door: `code` stays the closed vocabulary,
|
|
798
|
+
* and a thrown code that is not a member is demoted to a declared sibling,
|
|
799
|
+
* `ApiError.declaredCode` — the open, author-authored channel that carries a
|
|
800
|
+
* metadata app's OWN `.code` across the QuickJS boundary (#7867) and onto the
|
|
801
|
+
* wire.
|
|
802
|
+
*
|
|
803
|
+
* `ApiErrorSchema` has declared that field since #9106 and the flat door emits
|
|
804
|
+
* it, but it was absent from the `Pick` above — so it was a COMPILE ERROR for
|
|
805
|
+
* any route answering the NESTED envelope to pass one, and every such route
|
|
806
|
+
* dropped the producer's spelling. Nothing invalid shipped (the closed `code`
|
|
807
|
+
* still carried the derived member), which is what made the loss silent and
|
|
808
|
+
* one-directional: the author's spelling gone, and a consumer told by the ADR
|
|
809
|
+
* to read `declaredCode` finding nothing there. Declared-but-unemittable is a
|
|
810
|
+
* `declared = enforced` gap, and admitting the field closes it at the ONE
|
|
811
|
+
* writer rather than in each module that later notices.
|
|
812
|
+
*
|
|
813
|
+
* ⛔ Presence MEANS demotion, and this writer does not re-derive that — the
|
|
814
|
+
* CALLER does, with `demotedDeclaredCode` (`thrown-http-error.ts`, one file
|
|
815
|
+
* over), exactly as the flat door's `thrownCodeFields` already does. That
|
|
816
|
+
* helper answers `undefined` when the producer's spelling IS the vocabulary
|
|
817
|
+
* member already sitting in `code`, which is what stops a registered refusal
|
|
818
|
+
* from carrying two spellings of one fact — `ApiErrorSchema.declaredCode`'s
|
|
819
|
+
* documented invariant. Passing a raw `thrown.declaredCode` re-opens exactly
|
|
820
|
+
* that, and no type here can catch it: vocabulary and position stay two
|
|
821
|
+
* decisions (#9232), so the demotion rule stays with the resolver that owns
|
|
822
|
+
* it rather than being restated in the envelope writer.
|
|
823
|
+
*
|
|
824
|
+
* ## `userMessage` — the second declared channel, and why this `Pick` stays explicit
|
|
825
|
+
*
|
|
826
|
+
* #9934's producer-side opt-in (maintainer ruling 2026-08-19 on objectui#5210,
|
|
827
|
+
* option 1) declares `ApiError.userMessage`: the text a producer marked, AT
|
|
828
|
+
* THROW TIME, as addressed to the END USER. Presence IS the marking — a
|
|
829
|
+
* consumer that sees the field renders it verbatim and keeps its generic
|
|
830
|
+
* substitution (#3821) for everything unmarked.
|
|
831
|
+
*
|
|
832
|
+
* The schema declared it and this writer barred it, with the same
|
|
833
|
+
* one-directional silence `declaredCode` had: the other two doors already emit
|
|
834
|
+
* it — the flat `/data` door through `withDeclaredUserMessage`
|
|
835
|
+
* (`rest/error-response.ts`) and the dispatcher door through
|
|
836
|
+
* `thrown.userMessage` (`runtime/http-dispatcher.ts`) — while a route
|
|
837
|
+
* answering the NESTED envelope could not, so an author's deliberate,
|
|
838
|
+
* localized refusal text was dropped on this door alone. Nothing invalid
|
|
839
|
+
* shipped; the text simply was not there.
|
|
840
|
+
*
|
|
841
|
+
* The channel is live on both ends, which is what makes admitting it a repair
|
|
842
|
+
* rather than a new declared-but-dead surface: a hook sets it at throw time —
|
|
843
|
+
* host-side, or a metadata app's sandboxed body whose `e.userMessage` crosses
|
|
844
|
+
* the QuickJS boundary through `SANDBOX_ERROR_PASSTHROUGH`
|
|
845
|
+
* (`runtime/sandbox/quickjs-runner.ts`) — and `resolveThrownHttpError` already
|
|
846
|
+
* carries it onto `ThrownHttpError` for every caller of the shared resolver.
|
|
847
|
+
*
|
|
848
|
+
* ⛔ Unlike `declaredCode`, this field carries NO invariant for the caller to
|
|
849
|
+
* re-derive. `declaredCode`'s presence MEANS demotion, so its caller passes
|
|
850
|
+
* `demotedDeclaredCode(thrown)` rather than the raw field; `userMessage`'s
|
|
851
|
+
* presence means only that the producer opted in, and `declaredUserMessage`
|
|
852
|
+
* has already decided that (a non-empty string, or nothing at all). The caller
|
|
853
|
+
* passes `thrown.userMessage` straight through, exactly as the dispatcher door
|
|
854
|
+
* does.
|
|
855
|
+
*
|
|
856
|
+
* That difference is why `extra` stays an explicit `Pick` rather than becoming
|
|
857
|
+
* "every optional field of `ApiError`". A derivation would admit each future
|
|
858
|
+
* optional on the day it lands, with nobody asked whether that channel should
|
|
859
|
+
* cross this door or what obligation it hands the caller — and the two fields
|
|
860
|
+
* above needed opposite answers to exactly that question. Recorded for the next
|
|
861
|
+
* reader, because it is the honest cost: with `userMessage` admitted the `Pick`
|
|
862
|
+
* now names ALL SIX of `ApiError`'s optional fields, so this gate has to date
|
|
863
|
+
* rejected none. What it has produced is a different caller obligation per
|
|
864
|
+
* field, which a derivation cannot produce at all.
|
|
686
865
|
*/
|
|
687
|
-
declare function sendError(res: EnvelopeResponse, status: number, code: ErrorCode, message: string, extra?: Pick<ApiError, 'category' | 'httpStatus' | 'details' | 'requestId'>): void;
|
|
866
|
+
declare function sendError(res: EnvelopeResponse, status: number, code: ErrorCode, message: string, extra?: Pick<ApiError, 'category' | 'httpStatus' | 'details' | 'requestId' | 'declaredCode' | 'userMessage'>): void;
|
|
688
867
|
|
|
689
868
|
/**
|
|
690
869
|
* The ONE rule for "what HTTP answer does a THROWN error declare?" (#8016).
|
|
@@ -756,6 +935,14 @@ declare function sendError(res: EnvelopeResponse, status: number, code: ErrorCod
|
|
|
756
935
|
* answers come from ONE function, which is what keeps agreement a construction
|
|
757
936
|
* rather than two suites agreeing about literals.
|
|
758
937
|
*
|
|
938
|
+
* [#12509] And the channel has a SCOPE, ruled 2026-08-27 (option D): on a 5xx
|
|
939
|
+
* the producer did not declare, the demoted spelling came off an undeclared
|
|
940
|
+
* producer and is withheld with the prose, while an author-declared code
|
|
941
|
+
* survives. The discriminator is {@link serverFaultProvenance} — one function,
|
|
942
|
+
* read by {@link demotedDeclaredCode}, which every door already calls, so no
|
|
943
|
+
* registrar carries a variant. Read that function's note for why the status
|
|
944
|
+
* channel is the only honest signal here.
|
|
945
|
+
*
|
|
759
946
|
* ## What this deliberately does NOT decide
|
|
760
947
|
*
|
|
761
948
|
* - **Message disclosure.** A 5xx message may name physical tables or carry a
|
|
@@ -814,6 +1001,11 @@ interface ThrownHttpError {
|
|
|
814
1001
|
* every door (#9106) — but for the wire's `declaredCode` channel when the
|
|
815
1002
|
* spelling is not a vocabulary member ({@link demotedDeclaredCode}). See the
|
|
816
1003
|
* module note on why there are two.
|
|
1004
|
+
*
|
|
1005
|
+
* ⚠️ This field records what the producer WROTE, not what a boundary may
|
|
1006
|
+
* emit: since #12509 a demoted spelling is withheld on an undeclared 5xx.
|
|
1007
|
+
* ⛔ Read {@link demotedDeclaredCode}, never this field, when deciding what
|
|
1008
|
+
* goes on a wire.
|
|
817
1009
|
*/
|
|
818
1010
|
declaredCode?: string;
|
|
819
1011
|
/** The thrown message, UNSANITISED — see the module note on disclosure. */
|
|
@@ -888,21 +1080,206 @@ declare function resolveThrownHttpError(error: unknown, fallbackStatus?: number)
|
|
|
888
1080
|
* consumer keeps its generic substitution (#3821 preserved by construction).
|
|
889
1081
|
*/
|
|
890
1082
|
declare function declaredUserMessage(error: unknown): string | undefined;
|
|
1083
|
+
/**
|
|
1084
|
+
* [#12509] WHO named this 5xx — the producer, or this resolver's fallback.
|
|
1085
|
+
* `undefined` for anything below 500, where nothing is sanitised at all.
|
|
1086
|
+
*
|
|
1087
|
+
* This is the ONE definition of the distinction ADR-0112's 5xx-sanitisation
|
|
1088
|
+
* scope turns on (maintainer ruling 2026-08-27, option D), and it exists as a
|
|
1089
|
+
* named function rather than as an inline conjunction because TWO rules read
|
|
1090
|
+
* it and they read opposite limbs:
|
|
1091
|
+
*
|
|
1092
|
+
* - `'undeclared'` — the throw declared no HTTP answer, so
|
|
1093
|
+
* {@link ThrownHttpError.status} is the caller's `fallbackStatus` and
|
|
1094
|
+
* EVERYTHING this resolver picked up off that throw is the producer's
|
|
1095
|
+
* internals rather than an answer it composed. A driver errno
|
|
1096
|
+
* (`SQLITE_ERROR`, `42P01`) is the measured case, and it is why
|
|
1097
|
+
* {@link demotedDeclaredCode} withholds the code here: the spelling names
|
|
1098
|
+
* the backend, which is one of the two disclosures the 5xx message
|
|
1099
|
+
* withhold exists to prevent (`looksLikeInternalErrorLeak`; the other,
|
|
1100
|
+
* identifiers, is already covered).
|
|
1101
|
+
* - `'declared'` — the producer named a 5xx ITSELF, so its code is authored
|
|
1102
|
+
* and survives. #11718's `{ status: 503, code: 'SERVICE_UNAVAILABLE' }`
|
|
1103
|
+
* relay is this limb, and so is a metadata app's own 5xx refusal spelling
|
|
1104
|
+
* (#7867), which the ADR-0112 amendment wrote `declaredCode` for.
|
|
1105
|
+
*
|
|
1106
|
+
* ⚠️ The DISCRIMINATOR is the status channel, not the code's shape. There is
|
|
1107
|
+
* no other structural signal: a driver errno and an app's own spelling both
|
|
1108
|
+
* arrive on `.code` as a plain string, so anything that told them apart by
|
|
1109
|
+
* LOOKING at the string would be a heuristic over an open channel — the
|
|
1110
|
+
* consumer-side tolerance ADR-0112 exists to forbid, and unfalsifiable besides
|
|
1111
|
+
* (nothing stops an app from spelling `SQLITE_ERROR`). The cost of the
|
|
1112
|
+
* structural answer is stated rather than hidden: a producer that spells a
|
|
1113
|
+
* code but declares NO status loses that code on a 5xx. It keeps it by
|
|
1114
|
+
* declaring the status it means, which is the shape the ADR already asks for.
|
|
1115
|
+
*
|
|
1116
|
+
* ⛔ NOT gated on whether `looksLikeInternalErrorLeak` actually fired on the
|
|
1117
|
+
* message. That predicate is a heuristic over a DIFFERENT channel, and gating
|
|
1118
|
+
* here on it would leak the errno for exactly the dialects whose prose the
|
|
1119
|
+
* heuristic misses — the ceiling `sendThrownError`'s note records. The 5xx
|
|
1120
|
+
* sanitisation REGIME is the condition, not one of its two outcomes.
|
|
1121
|
+
*
|
|
1122
|
+
* ⭐ #12281 — the prose axis of the same 2026-08-27 ruling — is the
|
|
1123
|
+
* `'declared'` limb of this same function: the dispatcher door withholds the
|
|
1124
|
+
* message of EVERY declared 5xx, aligning to `/data`. It is a separate card
|
|
1125
|
+
* with its own measurement-first step, so nothing here applies it; this
|
|
1126
|
+
* function is the shape it will read rather than a second copy it would have
|
|
1127
|
+
* to grow.
|
|
1128
|
+
*/
|
|
1129
|
+
type ServerFaultProvenance = 'declared' | 'undeclared';
|
|
1130
|
+
/** See {@link ServerFaultProvenance}. */
|
|
1131
|
+
declare function serverFaultProvenance(thrown: ThrownHttpError): ServerFaultProvenance | undefined;
|
|
891
1132
|
/**
|
|
892
1133
|
* The producer's spelling a boundary should surface as the wire's
|
|
893
1134
|
* `declaredCode` beside the closed `code` — or `undefined` when there is
|
|
894
1135
|
* nothing to surface (#9106).
|
|
895
1136
|
*
|
|
896
1137
|
* Present exactly when the throw spelled a code that did NOT survive into
|
|
897
|
-
* {@link ThrownHttpError.code} — i.e. the demote happened
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
*
|
|
901
|
-
* "presence means demotion"
|
|
902
|
-
* semantics) has one definition.
|
|
1138
|
+
* {@link ThrownHttpError.code} — i.e. the demote happened — AND the answer is
|
|
1139
|
+
* not an undeclared server fault. A registered code is already in `code`, so
|
|
1140
|
+
* emitting it again would put two spellings of one fact on every refusal; a
|
|
1141
|
+
* throw with no code has nothing to declare. Spelled once here rather than as
|
|
1142
|
+
* three `!==` comparisons at three exits, so "presence means demotion"
|
|
1143
|
+
* (`ApiErrorSchema.declaredCode`'s documented semantics) has one definition.
|
|
1144
|
+
*
|
|
1145
|
+
* [#12509] The withhold limb, ruled 2026-08-27 (option D): on a 5xx the
|
|
1146
|
+
* producer did NOT declare, the spelling this resolver demoted came off an
|
|
1147
|
+
* undeclared producer — a driver errno, measured on the wire at three of this
|
|
1148
|
+
* repo's doors — and it is withheld along with the prose. An AUTHOR-declared
|
|
1149
|
+
* code survives at every status. The judgement lives in
|
|
1150
|
+
* {@link serverFaultProvenance}; it is applied HERE, in the one read every
|
|
1151
|
+
* boundary already makes, so all of them inherit it without a door growing a
|
|
1152
|
+
* rule of its own. ⛔ Do not re-derive the condition at a door: a per-door
|
|
1153
|
+
* variant is the divergence this channel has now been repaired for twice.
|
|
903
1154
|
*/
|
|
904
1155
|
declare function demotedDeclaredCode(thrown: ThrownHttpError): string | undefined;
|
|
905
1156
|
|
|
1157
|
+
/**
|
|
1158
|
+
* [#14310] The one rule for "a 5xx must never be silent", shared by every
|
|
1159
|
+
* transport that turns a fault into an HTTP envelope.
|
|
1160
|
+
*
|
|
1161
|
+
* ## The hole this closes
|
|
1162
|
+
*
|
|
1163
|
+
* A 500 that leaves no server-side line is diagnosed from the browser or not
|
|
1164
|
+
* at all. Measured on `main`: a plain `Error` thrown out of a dispatcher route
|
|
1165
|
+
* answered `500 INTERNAL_ERROR` with **zero** log records at any level — the
|
|
1166
|
+
* only evidence was the client's console and the response body. The failure
|
|
1167
|
+
* that motivated this had been reachable for a week and nobody saw it, which
|
|
1168
|
+
* is AGENTS.md "Route & surface ownership §3 — absence must be loud" inverted.
|
|
1169
|
+
*
|
|
1170
|
+
* The reporting that DID exist was not a substitute, in two independent ways:
|
|
1171
|
+
*
|
|
1172
|
+
* 1. `ErrorReporter.captureException` is an APM channel and defaults to
|
|
1173
|
+
* `NoopErrorReporter`. A dev server — the surface an operator actually
|
|
1174
|
+
* watches — wires no reporter, so the capture was a no-op every time.
|
|
1175
|
+
* 2. It is fed by `res.__obsRecordedError`, which only the THROWN exit sets.
|
|
1176
|
+
* A dispatcher route that catches its own fault and RETURNS a 5xx envelope
|
|
1177
|
+
* (`deps.errorFromThrown`, which is how every `/packages` handler answers)
|
|
1178
|
+
* records nothing, so even a wired reporter never saw those.
|
|
1179
|
+
*
|
|
1180
|
+
* This module is the log half, and it is deliberately not the reporter half:
|
|
1181
|
+
* an APM capture is opt-in telemetry, a log line is the operator's floor.
|
|
1182
|
+
*
|
|
1183
|
+
* ## Why it lives here
|
|
1184
|
+
*
|
|
1185
|
+
* Same argument, and the same package, as `resolveThrownHttpError` one file
|
|
1186
|
+
* over: a rule two doors must agree on cannot live inside one of them.
|
|
1187
|
+
* `@objectstack/runtime` depends on `@objectstack/rest`, so an import between
|
|
1188
|
+
* the two doors could only ever point one way — which is exactly why the
|
|
1189
|
+
* "what status does this throw mean" rule was moved here in #8016. "Is this
|
|
1190
|
+
* answer worth an operator's attention" is the same kind of rule, read by the
|
|
1191
|
+
* same two doors, so it gets the same home rather than a second one.
|
|
1192
|
+
*
|
|
1193
|
+
* Living beside {@link sendError} is what makes the REST side automatic: that
|
|
1194
|
+
* writer is the single exit for every nested-envelope 5xx, so the direct-mount
|
|
1195
|
+
* registrars need no per-door call and cannot forget one. Each transport logs
|
|
1196
|
+
* at its own single exit, so a fault costs one line and never two.
|
|
1197
|
+
*
|
|
1198
|
+
* ## `error` level, and why that clears the default
|
|
1199
|
+
*
|
|
1200
|
+
* The requirement is that the line survives `--log-level`'s DEFAULT. The CLI
|
|
1201
|
+
* default is `warn` (`packages/cli/src/utils/log-level.ts`) and `error` (40)
|
|
1202
|
+
* outranks `warn` (30) in `LEVEL_PRIORITY`, so an `error` record passes the
|
|
1203
|
+
* default threshold without any bypass of the level system. An operator who
|
|
1204
|
+
* asks for `--log-level silent` still gets silence: that is a deliberate
|
|
1205
|
+
* instruction, not the default this issue is about.
|
|
1206
|
+
*
|
|
1207
|
+
* ## 5xx only
|
|
1208
|
+
*
|
|
1209
|
+
* 4xx stays quiet, deliberately and at this one gate rather than at each call
|
|
1210
|
+
* site. A client error is the caller's mistake and the response already
|
|
1211
|
+
* explains it; logging them is how the `/meta` `?state=draft` probe once
|
|
1212
|
+
* printed 45 stack traces in one browsing session. `isServerFault` is the
|
|
1213
|
+
* whole rule: at or above 500.
|
|
1214
|
+
*/
|
|
1215
|
+
|
|
1216
|
+
/** The request coordinates an operator needs to find the failing call. */
|
|
1217
|
+
interface ServerFaultRequest {
|
|
1218
|
+
/** HTTP method, e.g. `GET`. */
|
|
1219
|
+
method?: string;
|
|
1220
|
+
/** Request path as served, e.g. `/api/v1/packages`. */
|
|
1221
|
+
path?: string;
|
|
1222
|
+
/** Correlation id — the `X-Request-Id` echoed on the response. */
|
|
1223
|
+
requestId?: string;
|
|
1224
|
+
}
|
|
1225
|
+
/** One fault, as the emitting door knows it. */
|
|
1226
|
+
interface ServerFaultLogInput {
|
|
1227
|
+
/** The HTTP status about to be written. Below 500 nothing is logged. */
|
|
1228
|
+
status: number;
|
|
1229
|
+
/**
|
|
1230
|
+
* The original thrown value, when the door still holds it. Carries the
|
|
1231
|
+
* stack; the wire body never does, because a 5xx message is withheld.
|
|
1232
|
+
*/
|
|
1233
|
+
error?: unknown;
|
|
1234
|
+
/** The envelope's `code`, when the door resolved one. */
|
|
1235
|
+
code?: string;
|
|
1236
|
+
/**
|
|
1237
|
+
* The message to print when {@link ServerFaultLogInput.error} carries
|
|
1238
|
+
* none — a declared fault built from a string rather than a throw.
|
|
1239
|
+
*/
|
|
1240
|
+
message?: string;
|
|
1241
|
+
/** Where the call came in. */
|
|
1242
|
+
request?: ServerFaultRequest;
|
|
1243
|
+
}
|
|
1244
|
+
/** The prefix every fault line carries, so an operator can grep one token. */
|
|
1245
|
+
declare const SERVER_FAULT_LOG_PREFIX = "[5xx]";
|
|
1246
|
+
/**
|
|
1247
|
+
* THE predicate. A response is a server fault worth a line exactly when its
|
|
1248
|
+
* status is 5xx. Exported so a door can decide without restating `>= 500`.
|
|
1249
|
+
*/
|
|
1250
|
+
declare function isServerFault(status: number): boolean;
|
|
1251
|
+
/**
|
|
1252
|
+
* The human half of the line: `[5xx] 500 GET /api/v1/packages — <message>`.
|
|
1253
|
+
* Split out so both the emitted record and a test can name the same string.
|
|
1254
|
+
*/
|
|
1255
|
+
declare function serverFaultLogMessage(input: ServerFaultLogInput): string;
|
|
1256
|
+
/**
|
|
1257
|
+
* The structured half. `status`/`code`/`requestId` are what a log search keys
|
|
1258
|
+
* on; `method`/`path` repeat the message's coordinates because a JSON sink
|
|
1259
|
+
* indexes fields, not prose.
|
|
1260
|
+
*/
|
|
1261
|
+
declare function serverFaultLogMeta(input: ServerFaultLogInput): Record<string, unknown>;
|
|
1262
|
+
/**
|
|
1263
|
+
* Emit EXACTLY ONE `error`-level record for a 5xx, or nothing at all.
|
|
1264
|
+
*
|
|
1265
|
+
* Returns whether a record was emitted, so a caller that must not double-log
|
|
1266
|
+
* can branch on the answer rather than re-deriving the 5xx test.
|
|
1267
|
+
*
|
|
1268
|
+
* `logger` is optional: a door with no injected logger falls back to
|
|
1269
|
+
* `console.error`, because the point of this function is that the line exists
|
|
1270
|
+
* even on a surface nobody configured. Emission never throws — a logging
|
|
1271
|
+
* failure must not become a second fault on top of the one being reported.
|
|
1272
|
+
*/
|
|
1273
|
+
declare function logServerFault(input: ServerFaultLogInput, logger?: Logger): boolean;
|
|
1274
|
+
/**
|
|
1275
|
+
* Read request coordinates off whatever request object the transport hands
|
|
1276
|
+
* the door. Adapters disagree on the spelling (`path` / `url` /
|
|
1277
|
+
* `originalUrl`), and the request id may be on the object (set by
|
|
1278
|
+
* `instrumentRouteHandler`) or only on the incoming header — so both are
|
|
1279
|
+
* read here, once, instead of at each call site.
|
|
1280
|
+
*/
|
|
1281
|
+
declare function describeFaultRequest(req: unknown): ServerFaultRequest;
|
|
1282
|
+
|
|
906
1283
|
/** The HTTP status a validation failure maps to when the error names none. */
|
|
907
1284
|
declare const VALIDATION_FAILED_STATUS = 400;
|
|
908
1285
|
interface ValidationFailureDetails {
|
|
@@ -1154,6 +1531,153 @@ declare function isUniqueViolationError(error: unknown): boolean;
|
|
|
1154
1531
|
*/
|
|
1155
1532
|
declare function uniqueViolationColumn(error: unknown): string | undefined;
|
|
1156
1533
|
|
|
1534
|
+
/**
|
|
1535
|
+
* [#13438] The physical table a driver's statement TARGETED, declared on the
|
|
1536
|
+
* error envelope by the producer that knows it.
|
|
1537
|
+
*
|
|
1538
|
+
* `readObject` closed the #13324 hole for callers that can name what they read
|
|
1539
|
+
* — and left a residual one layer down. A caller names its OBJECT (the API
|
|
1540
|
+
* name); a driver compiles the statement against the PHYSICAL table, and for a
|
|
1541
|
+
* federated object (ADR-0015, `external.remoteName`) those are two different
|
|
1542
|
+
* names. `driver-sql` reads `crm_order` from `legacy_orders`, so when that
|
|
1543
|
+
* remote is genuinely absent the dialect phrase names `legacy_orders`, the
|
|
1544
|
+
* caller names `crm_order`, and the comparison called a real missing table
|
|
1545
|
+
* "about something else" — loud, for the one case the licence was built for.
|
|
1546
|
+
*
|
|
1547
|
+
* Nothing at a call site can fold that away: the mapping lives on the driver
|
|
1548
|
+
* instance, and asking every caller to consult it is the guessing this channel
|
|
1549
|
+
* exists to remove (maintainer ruling 2026-09-01, option 2 on the card). So the
|
|
1550
|
+
* fact is declared where it is known — the driver that composed the envelope
|
|
1551
|
+
* stamps the table its statement targeted onto it — and the predicate PREFERS
|
|
1552
|
+
* a declared table over the caller-supplied `readObject`. The caller never
|
|
1553
|
+
* needs to know a federated object's remote name, and a driver that declares
|
|
1554
|
+
* nothing gets exactly the #13324 behaviour.
|
|
1555
|
+
*
|
|
1556
|
+
* A symbol key from the global registry, held non-enumerable: the carrier
|
|
1557
|
+
* discipline `driver-sql` already applies to its withheld-diagnostic symbols
|
|
1558
|
+
* and to the envelope's own `cause`. Readable by code; invisible to
|
|
1559
|
+
* `JSON.stringify`, `{ ...err }`, `Object.keys`, `for…in` and the
|
|
1560
|
+
* structured-clone boundary — so the physical table name, the very thing the
|
|
1561
|
+
* envelope's composed message withholds, can never ride back onto a wire that
|
|
1562
|
+
* serialises the error. `Symbol.for` so a duplicated copy of this package
|
|
1563
|
+
* resolves the same key.
|
|
1564
|
+
*
|
|
1565
|
+
* ⚠️ A declaration is EVIDENCE, so it also narrows the one-argument form: an
|
|
1566
|
+
* envelope declaring `legacy_orders` whose dialect phrase names some other
|
|
1567
|
+
* relation reads not-benign even with no `readObject` — the driver supplied
|
|
1568
|
+
* the fact the caller could not. That is the #13324 verdict reached without
|
|
1569
|
+
* the caller's help, in the direction the module docblock calls cheap.
|
|
1570
|
+
*/
|
|
1571
|
+
declare const DRIVER_TARGETED_TABLE: symbol;
|
|
1572
|
+
/**
|
|
1573
|
+
* Declare, on `error`, the physical table the statement that raised it targeted.
|
|
1574
|
+
*
|
|
1575
|
+
* The producer's half of {@link DRIVER_TARGETED_TABLE} — for a driver composing
|
|
1576
|
+
* an error envelope over a dialect failure. `table` is the name the statement
|
|
1577
|
+
* was compiled against (a federated object's `external.remoteName`, otherwise
|
|
1578
|
+
* the object's own table), bare: the comparison folds away schema and database
|
|
1579
|
+
* qualifiers on both sides, so none is needed here.
|
|
1580
|
+
*
|
|
1581
|
+
* Non-enumerable and non-writable, and the FIRST declaration wins: the actor
|
|
1582
|
+
* that compiled the statement is the one that knows its target, and a later,
|
|
1583
|
+
* more distant wrapper re-declaring it would be re-introducing the guess. (The
|
|
1584
|
+
* predicate applies the same rule across a `cause` chain: the declaration
|
|
1585
|
+
* NEAREST the dialect phrase is the one compared.) An empty or non-string
|
|
1586
|
+
* `table` declares nothing — silently, because this runs on an error path
|
|
1587
|
+
* where a thrown `TypeError` would replace the envelope it was meant to
|
|
1588
|
+
* annotate; the predicate then falls back to `readObject` exactly as if no
|
|
1589
|
+
* driver had spoken.
|
|
1590
|
+
*
|
|
1591
|
+
* @returns `error`, for chaining.
|
|
1592
|
+
*/
|
|
1593
|
+
declare function declareTargetedTable<E extends object>(error: E, table: string): E;
|
|
1594
|
+
/**
|
|
1595
|
+
* The table `error` declares its statement targeted, or `null` when it declares
|
|
1596
|
+
* none — the reading half of {@link declareTargetedTable}. Tolerant of bare
|
|
1597
|
+
* input: any non-object, and any object without a non-empty string under the
|
|
1598
|
+
* key, is "no declaration".
|
|
1599
|
+
*/
|
|
1600
|
+
declare function targetedTableOf(error: unknown): string | null;
|
|
1601
|
+
/**
|
|
1602
|
+
* Is this DDL error the benign "already provisioned" case?
|
|
1603
|
+
*
|
|
1604
|
+
* @param error - The value thrown by `syncSchema()` (or any DDL call).
|
|
1605
|
+
* @param depth - Internal `cause`-chain recursion counter; callers pass nothing.
|
|
1606
|
+
* @returns `true` only when the error positively identifies as
|
|
1607
|
+
* table/column/index-already-exists. Anything else — including an
|
|
1608
|
+
* unrecognised error, `undefined`, or a permission/connection failure —
|
|
1609
|
+
* returns `false` and MUST be reported loudly by the caller.
|
|
1610
|
+
*/
|
|
1611
|
+
declare function isSchemaAlreadyExistsError(error: unknown, depth?: number): boolean;
|
|
1612
|
+
/**
|
|
1613
|
+
* Is this READ error the benign "table has not been provisioned yet" case?
|
|
1614
|
+
*
|
|
1615
|
+
* The only failure that licenses a caller to treat an empty table as the truth
|
|
1616
|
+
* — there are no rows, so there is nothing to be inconsistent with. A
|
|
1617
|
+
* connection drop, a timeout, a permission denial or a query error all mean the
|
|
1618
|
+
* rows may well exist and simply were not seen; those return `false` and the
|
|
1619
|
+
* caller must report the consequence and give up rather than compute an answer
|
|
1620
|
+
* from data it never read (#4825).
|
|
1621
|
+
*
|
|
1622
|
+
* A failure about a **column** of a relation is never this case, in either of
|
|
1623
|
+
* Postgres' two phrasings — the relation is right there in the message because
|
|
1624
|
+
* it exists (#6347). See {@link MISSING_TABLE}'s `excludes`.
|
|
1625
|
+
*
|
|
1626
|
+
* [#13324] Neither is a failure that names a **different relation**, and that
|
|
1627
|
+
* one cannot be seen without `readObject`. The message test asks what the
|
|
1628
|
+
* phrase LOOKS like and never which table it names, so a read of a view whose
|
|
1629
|
+
* base table has been dropped — `no such table: main.<base>`, measured on
|
|
1630
|
+
* libsql for a view that itself exists — answered benign for a relation that is
|
|
1631
|
+
* present and may be backed by rows. Naming the read closes it: the phrase must
|
|
1632
|
+
* be about the table the caller asked for, or it is not evidence about it.
|
|
1633
|
+
*
|
|
1634
|
+
* Pass `readObject` from every in-repo call site. It is **optional** so that
|
|
1635
|
+
* omitting it is exactly the pre-#13324 behaviour rather than a new loud
|
|
1636
|
+
* failure — this is a published export (`@objectstack/types`, and still
|
|
1637
|
+
* `@objectstack/metadata/errors` by re-export), and a required parameter would
|
|
1638
|
+
* be a breaking change to it. The cost of the choice
|
|
1639
|
+
* is that the narrowing is opt-in per call site: a new caller that forgets it
|
|
1640
|
+
* silently gets the old, wider verdict.
|
|
1641
|
+
*
|
|
1642
|
+
* [#13440] That last sentence is no longer only a warning. In-repo callers are
|
|
1643
|
+
* held to it by `driver-error-classification.callers.test.ts`, which walks every
|
|
1644
|
+
* TypeScript source under `packages/` and fails any call of this function that
|
|
1645
|
+
* omits `readObject` or passes it as `undefined`/`null`. The exemption is this
|
|
1646
|
+
* module's own contract tests, which exercise the one-argument PUBLISHED form on
|
|
1647
|
+
* purpose; read that file's header before adding to the exemption, because
|
|
1648
|
+
* widening it is how the enforcement becomes prose again. External consumers are
|
|
1649
|
+
* untouched: the signature below is unchanged, and the gate binds only callers
|
|
1650
|
+
* inside this repository.
|
|
1651
|
+
*
|
|
1652
|
+
* [#13438] `readObject` is the caller's name for what it read, and for a
|
|
1653
|
+
* federated object (ADR-0015) that is not the name the driver put in the
|
|
1654
|
+
* statement — `crm_order` reads `external.remoteName: 'legacy_orders'`, so a
|
|
1655
|
+
* genuinely absent remote raised a phrase naming `legacy_orders` against a
|
|
1656
|
+
* caller naming `crm_order`, and the #13324 comparison read it loud. A driver
|
|
1657
|
+
* that knows the table it targeted now DECLARES it on the envelope
|
|
1658
|
+
* ({@link declareTargetedTable}), and a declared table is preferred over
|
|
1659
|
+
* `readObject` outright: the phrase is compared against the declared name, and
|
|
1660
|
+
* the caller-supplied one is not consulted at that node or below it. Absent a
|
|
1661
|
+
* declaration the comparison is the #13324 one, unchanged. Two consequences,
|
|
1662
|
+
* both pinned: a genuinely absent federated remote reads benign again without
|
|
1663
|
+
* the caller learning the mapping; and — because a declaration is evidence the
|
|
1664
|
+
* caller did not have — an envelope whose phrase names a relation other than
|
|
1665
|
+
* its declared table reads NOT benign even through the one-argument form.
|
|
1666
|
+
*
|
|
1667
|
+
* @param error - The value thrown by a driver/engine read (`find`, `findOne`, …).
|
|
1668
|
+
* @param readObject - The object/table whose emptiness the caller is about to
|
|
1669
|
+
* treat as the truth — its own API name is fine, the comparison folds
|
|
1670
|
+
* away schema qualifiers, the legacy `ns__short` prefix and case.
|
|
1671
|
+
* Omitted (or not a string) means "cannot say", never "be loud".
|
|
1672
|
+
* Superseded, at any node of the `cause` chain that declares the
|
|
1673
|
+
* table its statement targeted, by that declaration (#13438).
|
|
1674
|
+
* @param depth - Internal `cause`-chain recursion counter; callers pass nothing.
|
|
1675
|
+
* @returns `true` only when the error positively identifies as
|
|
1676
|
+
* table/relation-does-not-exist **for the table that was read** —
|
|
1677
|
+
* the declared target where a driver supplied one, else `readObject`.
|
|
1678
|
+
*/
|
|
1679
|
+
declare function isMissingTableError(error: unknown, readObject?: string, depth?: number): boolean;
|
|
1680
|
+
|
|
1157
1681
|
/**
|
|
1158
1682
|
* Whether a thrown driver error says the `ON CONFLICT` target it was given is
|
|
1159
1683
|
* backed by no PRIMARY KEY or UNIQUE index.
|
|
@@ -1407,4 +1931,4 @@ interface RuntimePlugin {
|
|
|
1407
1931
|
onStart?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
1408
1932
|
}
|
|
1409
1933
|
|
|
1410
|
-
export { type EnvelopeResponse, GLOBAL_UNIQUE_CONFIRMATION_REQUIRED, GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION, type GlobalUniqueAttestation, type GlobalUniqueFinding, type IKernel, INTERNAL_ERROR_MESSAGE, type KeysetPageQuery, type KeysetWalk, type KeysetWalkOptions, type RuntimeContext, type RuntimePlugin, type ThrownHttpError, VALIDATION_FAILED_STATUS, type ValidationFailureDetails, _resetEnvDeprecationWarnings, buildGlobalUniqueStopMessage, collectConfiguredLocales, collectGlobalUniques, declaredIndexUniqueIsGlobal, declaredUserMessage, declaresServerFault, demotedDeclaredCode, describeGlobalUniqueFinding, emitDegradedBootBanner, fieldUniqueIsGlobal, fieldsFromZodIssues, globalUniqueFindingId, isMcpServerEnabled, isModuleNotFoundError, isPlatformOwnedObject, isRelationSubObjectPhrase, isUnbackedConflictTargetError, isUniqueViolationError, keysetWalk, looksLikeInternalErrorLeak, matchMissingColumnOfRelation, postureGatesGlobalUniques, readEnvWithDeprecation, recordGlobalUniqueAttestation, resolveAllowDegradedTenancy, resolveAllowDevPlugin, resolveAllowDriverConnectFailure, resolveMcpStdioAutoStart, resolveMultiOrgEnabled, resolveOrgLimit, resolveSandboxTimeoutMs, resolveSearchPinyinEnabled, resolveTenancyPosture, resolveThrownHttpError, sendError, sendOk, stampSearchPinyinEnabled, unconfirmedGlobalUniques, uniqueViolationColumn, validationFailure, validationFailureDetails };
|
|
1934
|
+
export { DRIVER_TARGETED_TABLE, type EnvelopeResponse, GLOBAL_UNIQUE_CONFIRMATION_REQUIRED, GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION, type GlobalUniqueAttestation, type GlobalUniqueFinding, type IKernel, INTERNAL_ERROR_MESSAGE, type KeysetPageQuery, type KeysetWalk, type KeysetWalkOptions, PLATFORM_OWNER_EMAIL_ENV, type RuntimeContext, type RuntimePlugin, SERVER_FAULT_LOG_PREFIX, type ServerFaultLogInput, type ServerFaultProvenance, type ServerFaultRequest, type ThrownHttpError, VALIDATION_FAILED_STATUS, type ValidationFailureDetails, _resetEnvDeprecationWarnings, buildGlobalUniqueStopMessage, collectConfiguredLocales, collectGlobalUniques, declareTargetedTable, declaredIndexUniqueIsGlobal, declaredUserMessage, declaresServerFault, demotedDeclaredCode, describeFaultRequest, describeGlobalUniqueFinding, emitDegradedBootBanner, fieldUniqueIsGlobal, fieldsFromZodIssues, globalUniqueFindingId, isEmailVerifiedUserRow, isMcpServerEnabled, isMissingTableError, isModuleNotFoundError, isPlatformOwnedObject, isRelationSubObjectPhrase, isSchemaAlreadyExistsError, isServerFault, isUnbackedConflictTargetError, isUniqueViolationError, keysetWalk, logServerFault, looksLikeInternalErrorLeak, matchMissingColumnOfRelation, postureGatesGlobalUniques, readEnvWithDeprecation, recordGlobalUniqueAttestation, resolveAllowDegradedTenancy, resolveAllowDevPlugin, resolveAllowDriverConnectFailure, resolveMcpStdioAutoStart, resolveMultiOrgEnabled, resolveOrgLimit, resolveOrgMembershipLimit, resolvePlatformOwnerEmail, resolveSandboxTimeoutMs, resolveSearchPinyinEnabled, resolveTenancyPosture, resolveThrownHttpError, sendError, sendOk, serverFaultLogMessage, serverFaultLogMeta, serverFaultProvenance, stampSearchPinyinEnabled, targetedTableOf, unconfirmedGlobalUniques, uniqueViolationColumn, validationFailure, validationFailureDetails };
|