@objectstack/core 17.0.0-rc.6 → 17.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Logger, LifecycleEventName, IServiceRegistry, IObjectQLEngine } from '@objectstack/spec/contracts';
2
- export { EngineSchemaRegistryView, EngineTransactionInfo, EngineTransactionOptions, IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, IObjectQLEngine, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
1
+ import { Logger, LifecycleEventName, IServiceRegistry, AudienceBindingSuggestionFilter, IObjectQLEngine } from '@objectstack/spec/contracts';
2
+ export { EngineSchemaRegistryView, EngineTransactionInfo, EngineTransactionOptions, HttpResponseObservation, HttpResponseObserver, IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, IObjectQLEngine, Logger, Middleware, RouteHandler, UNMATCHED_ROUTE_PATTERN } from '@objectstack/spec/contracts';
3
3
  import { z } from 'zod';
4
4
  import { LoggerConfig, MigrationOnCrashPolicy, MigrationJournalEvent } from '@objectstack/spec/system';
5
5
  import { ObjectLogger } from './logger.js';
@@ -7,7 +7,7 @@ export { createLogger } from './logger.js';
7
7
  import * as QA from '@objectstack/spec/qa';
8
8
  import { KeyObject } from 'node:crypto';
9
9
  import { PluginCapability, PluginPermissions as PluginPermissions$1, PluginPermissionSet, ResourceType, PermissionAction, PluginPermission, SandboxConfig, KernelSecurityScanResult, KernelSecurityVulnerability, ExecutionContext, PluginHealthCheckParsed, PluginHealthStatus as PluginHealthStatus$1, PluginHealthReport, HotReloadConfigParsed, VersionConstraint, DependencyConflict, SemanticVersion, CompatibilityLevel } from '@objectstack/spec/kernel';
10
- import { AuthzPosture } from '@objectstack/spec/security';
10
+ import { TenancyPosture, AuthzPosture } from '@objectstack/spec/security';
11
11
  export { nextUtcCalendarDay, utcInstantMs } from '@objectstack/spec/data';
12
12
 
13
13
  /**
@@ -222,6 +222,14 @@ declare class ObjectKernel {
222
222
  constructor(config?: ObjectKernelConfig);
223
223
  /**
224
224
  * Register a plugin with enhanced validation
225
+ *
226
+ * Duplicate names OVERWRITE, with one `warn` naming both versions — the
227
+ * declared contract in `plugin-registration.ts`, applied identically by
228
+ * `LiteKernel.use()` (#9864, maintainer ruling 2026-08-19). The overwrite
229
+ * itself is unchanged: it is what lets an app config's `plugins` entry
230
+ * supersede a plugin the CLI auto-registered earlier in the same boot
231
+ * (#9863). What changes is that it is no longer silent, and no longer
232
+ * disagrees with the other kernel.
225
233
  */
226
234
  use(plugin: Plugin): Promise<this>;
227
235
  /**
@@ -811,6 +819,17 @@ declare class LiteKernel extends ObjectKernelBase {
811
819
  /**
812
820
  * Register a plugin
813
821
  * @param plugin - Plugin instance
822
+ *
823
+ * Duplicate names OVERWRITE, with one `warn` naming both versions — the
824
+ * declared contract in `plugin-registration.ts`, applied identically by
825
+ * `ObjectKernel.use()` (#9864, maintainer ruling 2026-08-19).
826
+ *
827
+ * This method used to `throw` `[Kernel] Plugin '<name>' already
828
+ * registered` here while `ObjectKernel` overwrote silently, so one input
829
+ * had two meanings depending on which kernel was running — and the kernel
830
+ * that runs in production was the silent one. The ruling converged them on
831
+ * the behaviour that already works (an app config superseding a plugin the
832
+ * CLI auto-registered, #9863) and made it audible rather than removing it.
814
833
  */
815
834
  use(plugin: Plugin): this;
816
835
  /**
@@ -882,7 +901,67 @@ declare class TestRunner {
882
901
  declare class HttpTestAdapter implements TestExecutionAdapter {
883
902
  private baseUrl;
884
903
  private authToken?;
904
+ /**
905
+ * The single discovery probe of a run, memoised as the in-flight promise so
906
+ * concurrent record actions share one request rather than racing N.
907
+ *
908
+ * `os test` builds ONE adapter for the whole run (`packages/cli/src/commands/
909
+ * test.ts`) and hands it to every suite, so instance scope IS run scope.
910
+ */
911
+ private mountPromise?;
885
912
  constructor(baseUrl: string, authToken?: string | undefined);
913
+ /** The resolved data mount; probes at most once per adapter. */
914
+ private dataMount;
915
+ /**
916
+ * Ask the server where it serves the Data Protocol, and fall back to the
917
+ * convention — loudly — when it cannot say.
918
+ *
919
+ * ## [#7983] What the probe recovers, measured rather than assumed
920
+ *
921
+ * `@objectstack/client` answers the same question through discovery
922
+ * (`getRoute`, `packages/client/src/index.ts`), and this follows it: prefer
923
+ * the server's own `routes.data`, fall back to the convention. Measured on a
924
+ * booted stack (REST generator + dispatcher bridge, three configs):
925
+ *
926
+ * | deployment | `{apiBase}/discovery` | serves |
927
+ * |--------------------------------|-----------------------|---------------|
928
+ * | stock | 200 `/api/v1/data` | `/api/v1/data`|
929
+ * | `crud.dataPrefix: '/objects'` | 200 `/api/v1/objects` | `/api/v1/objects` |
930
+ * | `api.apiPath: '/api/2026-01'` | **404** | `/api/2026-01/data` |
931
+ *
932
+ * So the probe closes the `dataPrefix` row exactly: `RestServer`'s discovery
933
+ * handler substitutes the configured prefix into `routes.data`, and reading
934
+ * it is strictly better than recomputing it here. The `apiPath` row it cannot
935
+ * close, and the reason is structural rather than an oversight — `apiPath`
936
+ * moves the base that discovery itself is mounted under, so the document that
937
+ * would name the new mount is behind the very prefix we are missing.
938
+ *
939
+ * ⛔ And the one discovery document at a FIXED path does not rescue it:
940
+ * `/.well-known/objectstack` is mounted at the site root by the dispatcher
941
+ * bridge, but its `routes.data` is the DISPATCHER's own `${prefix}/data` —
942
+ * measured as `/api/v1/data` under all three configs above, including the two
943
+ * where the server serves elsewhere. Falling back to it would turn "we could
944
+ * not resolve the mount" into "discovery told us `/api/v1/data`": the same
945
+ * 404, now with a false provenance attached. Not probed, deliberately.
946
+ *
947
+ * Hence: one probe, then a diagnostic that NAMES the mount, the evidence and
948
+ * the remedy. `api_call` takes the path it is given and is unaffected either
949
+ * way — it stays the escape hatch for a host this cannot reach.
950
+ */
951
+ private resolveDataMount;
952
+ /** `{baseUrl}{dataMount}/{object}` — the collection URL. */
953
+ private collectionUrl;
954
+ /** `{collection}/{id}` — the single-record URL. */
955
+ private recordUrl;
956
+ /**
957
+ * The provenance clause appended to a failed record action's error.
958
+ *
959
+ * The card this closes is about a 404 that reads like the author's own URL
960
+ * mistake; the mount is the one fact that distinguishes the two, so it rides
961
+ * on the failure itself rather than only on a warning printed earlier in the
962
+ * transcript.
963
+ */
964
+ private mountNote;
886
965
  execute(action: QA.TestAction, _context: Record<string, unknown>): Promise<unknown>;
887
966
  private createRecord;
888
967
  private updateRecord;
@@ -1708,9 +1787,74 @@ declare function isExpired(value: unknown, nowMs: number): boolean;
1708
1787
  /** The principal resolved from a valid `sys_api_key`. */
1709
1788
  interface ApiKeyPrincipal {
1710
1789
  userId: string;
1790
+ /**
1791
+ * The organization this key authenticates INTO — read from the row's
1792
+ * `active_organization_id` and adopted by `resolveAuthzContext` as the
1793
+ * request's active organization (`ExecutionContext.tenantId`), which is what
1794
+ * lets the ADR-0105 Layer 0 wall match. `undefined` for a key minted before
1795
+ * #8287, or one minted under the `single` posture where there is no
1796
+ * organization to inherit.
1797
+ */
1711
1798
  tenantId?: string;
1712
1799
  scopes: string[];
1713
1800
  }
1801
+ /**
1802
+ * [#8287] Why a key was refused. Distinct from "no key present" and from "this
1803
+ * key is unknown/revoked/expired": a refusal means the credential is real and
1804
+ * intact but cannot be admitted under this deployment's tenancy posture.
1805
+ */
1806
+ type ApiKeyRefusalReason = 'organization_required' | 'organization_membership_ended';
1807
+ /**
1808
+ * The verdict on an inbound API key. Three outcomes, deliberately distinct:
1809
+ *
1810
+ * - `none` — no key header, or a key that is unknown / revoked / expired /
1811
+ * owner-less. Indistinguishable by design (never tell a prober which), and
1812
+ * the caller MAY fall through to the session path exactly as before.
1813
+ * - `admitted` — a usable principal.
1814
+ * - `refused` — a real, intact key the posture cannot admit. The caller must
1815
+ * NOT fall through to the session path: falling through would be more
1816
+ * permissive than today's behaviour (an API key already outranks a session),
1817
+ * and the whole point of the refusal is that it is LOUD at call time.
1818
+ */
1819
+ type ApiKeyAdmission = {
1820
+ outcome: 'none';
1821
+ } | {
1822
+ outcome: 'admitted';
1823
+ principal: ApiKeyPrincipal;
1824
+ } | {
1825
+ outcome: 'refused';
1826
+ reason: ApiKeyRefusalReason;
1827
+ message: string;
1828
+ };
1829
+ /**
1830
+ * The shape of the kernel's `tenancy` service this module reads a posture from.
1831
+ * Structural on purpose: `@objectstack/core` must not depend on the plugin that
1832
+ * provides it, and an embedding without that plugin simply supplies nothing.
1833
+ */
1834
+ interface TenancyPostureSource {
1835
+ posture?: string;
1836
+ isolationActive?: boolean;
1837
+ }
1838
+ /**
1839
+ * [#8287] Resolve the EFFECTIVE tenancy posture from the kernel's `tenancy`
1840
+ * service — the same reconciliation `plugin-security` performs before handing a
1841
+ * posture to `computeTenantLayer0Filter`, so the wall and the API-key admission
1842
+ * can never disagree about which posture is in force.
1843
+ *
1844
+ * ⚠️ Deliberately NOT `resolveTenancyPosture()` from `@objectstack/types`, which
1845
+ * reads `OS_TENANCY_POSTURE` directly. That answers what the operator ASKED
1846
+ * for, not what is ENFORCED: under ADR-0093 D4/D5 a deployment that requests
1847
+ * `isolated` without the enterprise `@objectstack/organizations` runtime
1848
+ * resolves to `single` and runs with NO organization wall. Reading the env
1849
+ * there would refuse org-less API keys on a deployment whose wall is not even
1850
+ * active — breaking working automation to enforce a boundary that does not
1851
+ * exist. The `tenancy` service is the one place that already knows the
1852
+ * difference.
1853
+ *
1854
+ * Returns `undefined` when no service is available, which callers must treat as
1855
+ * "no posture-conditional refusal" — see {@link resolveApiKeyAdmission}.
1856
+ */
1857
+ declare function effectiveTenancyPosture(tenancy: TenancyPostureSource | undefined | null): TenancyPosture | undefined;
1714
1858
  /**
1715
1859
  * Verify an inbound API key against `sys_api_key` and resolve its principal.
1716
1860
  * This is the ONE verify path shared by the dispatcher/MCP and REST surfaces.
@@ -1722,7 +1866,21 @@ interface ApiKeyPrincipal {
1722
1866
  * @param headers Request headers (Web `Headers` or a plain object).
1723
1867
  * @param nowMs Clock for expiry checks (injectable for tests).
1724
1868
  */
1725
- declare function resolveApiKeyPrincipal(ql: any, headers: any, nowMs?: number): Promise<ApiKeyPrincipal | undefined>;
1869
+ declare function resolveApiKeyPrincipal(ql: any, headers: any, nowMs?: number, tenancyPosture?: TenancyPosture): Promise<ApiKeyPrincipal | undefined>;
1870
+ /**
1871
+ * [#8287] The full verdict behind {@link resolveApiKeyPrincipal} — same lookup,
1872
+ * but it distinguishes a POSTURE REFUSAL from "no principal".
1873
+ *
1874
+ * `resolveApiKeyPrincipal` collapses `refused` into `undefined` so every
1875
+ * existing caller keeps working and keeps failing closed; a caller that can
1876
+ * report WHY (the shared `resolveAuthzContext`) uses this instead.
1877
+ *
1878
+ * The only refusal decided here is the org-less one, because it needs nothing
1879
+ * but the row and the posture. The ex-member refusal needs the caller's
1880
+ * membership set and is decided in `resolveAuthzContext`, where that set is
1881
+ * already resolved.
1882
+ */
1883
+ declare function resolveApiKeyAdmission(ql: any, headers: any, nowMs?: number, tenancyPosture?: TenancyPosture): Promise<ApiKeyAdmission>;
1726
1884
 
1727
1885
  /** The transport-agnostic authorization envelope produced from a request. */
1728
1886
  interface ResolvedAuthzContext {
@@ -1754,6 +1912,24 @@ interface ResolvedAuthzContext {
1754
1912
  * anonymous requests carry no rung.
1755
1913
  */
1756
1914
  posture?: AuthzPosture;
1915
+ /**
1916
+ * [#8287] Set when an inbound API key was REFUSED — a real, intact
1917
+ * credential this deployment's tenancy posture cannot admit. The context is
1918
+ * otherwise EMPTY (no `userId`), so every transport already fails it closed
1919
+ * to 401 with no change; this field only lets a transport that wants to say
1920
+ * WHY do so, instead of answering the operator with a bare "unauthenticated"
1921
+ * for a key they can see is neither revoked nor expired.
1922
+ *
1923
+ * ⚠️ `reason` is NOT an `error.code`. The wire vocabulary is closed
1924
+ * (ADR-0112: `StandardErrorCode ∪ ERROR_CODE_LEDGER`, both in `packages/spec`)
1925
+ * and a refused credential's standard member is `UNAUTHENTICATED`. This is a
1926
+ * diagnostic discriminator for the message, deliberately lowercase so it can
1927
+ * never be mistaken for one.
1928
+ */
1929
+ authRefusal?: {
1930
+ reason: ApiKeyRefusalReason;
1931
+ message: string;
1932
+ };
1757
1933
  }
1758
1934
  interface ResolveAuthzInput {
1759
1935
  /** Data engine (ObjectQL) exposing `find(object, { where, limit, context })`. */
@@ -1768,6 +1944,18 @@ interface ResolveAuthzInput {
1768
1944
  getSession?: (headers: any) => Promise<any> | any;
1769
1945
  /** Clock injection for API-key expiry (tests). */
1770
1946
  nowMs?: number;
1947
+ /**
1948
+ * [#8287] The deployment's EFFECTIVE tenancy posture, as resolved from the
1949
+ * kernel's `tenancy` service (`effectiveTenancyPosture`) — never from
1950
+ * `OS_TENANCY_POSTURE`, which reports what was requested rather than what is
1951
+ * enforced (ADR-0093 D4/D5).
1952
+ *
1953
+ * Supplied by the transport because this resolver is deliberately
1954
+ * kernel-agnostic. OMITTING it disables the two posture-conditional API-key
1955
+ * refusals and leaves behaviour exactly as it was — so an unwired caller is
1956
+ * never made WORSE, only less strict.
1957
+ */
1958
+ tenancyPosture?: TenancyPosture;
1771
1959
  }
1772
1960
  /**
1773
1961
  * Resolve the authorization context for an inbound request. Always resolves —
@@ -2226,12 +2414,16 @@ declare const ANONYMOUS_DENY_CODE: "UNAUTHENTICATED";
2226
2414
  /** Human-facing message. */
2227
2415
  declare const ANONYMOUS_DENY_MESSAGE = "Authentication is required to access this endpoint.";
2228
2416
  /**
2229
- * The **REST seam's** 401 body — flat `{ error, message }`. NOT the platform's
2230
- * only one; see the two-envelope table below before you reuse this shape.
2417
+ * The **REST seam's** 401 body — flat `{ error, code, message }`. NOT the
2418
+ * platform's only one; see the two-envelope table below before you reuse this
2419
+ * shape.
2231
2420
  *
2232
- * Exactly one consumer writes it: `@objectstack/rest`'s `enforceAuth`
2233
- * (`rest-server.ts` — `res.status(ANONYMOUS_DENY_STATUS).json(ANONYMOUS_DENY_BODY)`),
2234
- * which owns the `/data/*` and `/meta` surfaces.
2421
+ * Two consumers write it verbatim, both flat-family seams: `@objectstack/rest`'s
2422
+ * `enforceAuth` (`rest-server.ts` —
2423
+ * `res.status(ANONYMOUS_DENY_STATUS).json(ANONYMOUS_DENY_BODY)`), which owns the
2424
+ * `/data/*` and `/meta` surfaces, and `@objectstack/runtime`'s
2425
+ * `mountRouteOnServer` (`dispatcher-plugin.ts` — the endpoint-route 401 arm,
2426
+ * #9823), which answers declared routes mounted on the HTTP server.
2235
2427
  *
2236
2428
  * ## Two live envelopes, one denial (#5632)
2237
2429
  *
@@ -2240,8 +2432,11 @@ declare const ANONYMOUS_DENY_MESSAGE = "Authentication is required to access thi
2240
2432
  * {@link ANONYMOUS_DENY_MESSAGE}). What differs is the **wrapper**:
2241
2433
  *
2242
2434
  * - **REST seam** — `@objectstack/rest` `enforceAuth`, this constant, verbatim:
2243
- * `{ error: 'UNAUTHENTICATED', message: '…' }`. The code is the value of the
2244
- * top-level `error` key; there is no `success` key and no nesting.
2435
+ * `{ error: 'UNAUTHENTICATED', code: 'UNAUTHENTICATED', message: '…' }`.
2436
+ * The machine code lives in the top-level `code` key the same documented
2437
+ * key every other REST error family answers (#9487, maintainer-ruled
2438
+ * ADDITIVE: `error` keeps carrying the code value it always has, so no
2439
+ * existing reader breaks). There is no `success` key and no nesting.
2245
2440
  * - **Dispatcher seams** — the five runtime domains `domains/ai.ts`,
2246
2441
  * `domains/meta.ts`, `domains/security.ts`, `domains/actions.ts` and
2247
2442
  * `domains/automation.ts` do NOT use this constant. Each calls
@@ -2253,7 +2448,10 @@ declare const ANONYMOUS_DENY_MESSAGE = "Authentication is required to access thi
2253
2448
  * (#4007) records the flat and wrapped envelopes as the two live ones, and
2254
2449
  * assigns retiring one of them to the envelope-convergence line (#3843 family).
2255
2450
  * Converging them is a breaking wire change; it is not this module's to make,
2256
- * and this constant must not be read as if it had already happened.
2451
+ * and this constant must not be read as if it had already happened. The #9487
2452
+ * `code` key does NOT settle that question either way (ADR-0112 D5 stays
2453
+ * open): it aligns the flat family to the `{ error, code }` shape the other
2454
+ * flat REST error families already answer, without moving or removing a key.
2257
2455
  *
2258
2456
  * ## Reading this from a consumer (human or AI author)
2259
2457
  *
@@ -2270,6 +2468,7 @@ declare const ANONYMOUS_DENY_MESSAGE = "Authentication is required to access thi
2270
2468
  */
2271
2469
  declare const ANONYMOUS_DENY_BODY: {
2272
2470
  readonly error: "UNAUTHENTICATED";
2471
+ readonly code: "UNAUTHENTICATED";
2273
2472
  readonly message: "Authentication is required to access this endpoint.";
2274
2473
  };
2275
2474
  interface AnonymousDenyInput {
@@ -2312,6 +2511,156 @@ declare function isGrantActive(row: GrantValidityWindow | null | undefined, nowM
2312
2511
  */
2313
2512
  declare function isGrantExpired(row: GrantValidityWindow | null | undefined, nowMs: number): boolean;
2314
2513
 
2514
+ /** A catalogue row that may carry the `active` flag (`sys_permission_set`, `sys_position`). */
2515
+ interface ActivatableRow {
2516
+ active?: unknown;
2517
+ }
2518
+ /**
2519
+ * True unless the row carries an `active` column that is explicitly OFF.
2520
+ *
2521
+ * The ONE predicate every reader of `sys_permission_set.active` /
2522
+ * `sys_position.active` uses, so the resolver that enforces the flag and the
2523
+ * break-glass guard that simulates a write to it can never disagree about what
2524
+ * "deactivated" means.
2525
+ */
2526
+ declare function isRowActive(row: ActivatableRow | null | undefined): boolean;
2527
+
2528
+ /**
2529
+ * ADMIN_STANDING_SURFACE — what `resolveAuthzContext` READS when it decides
2530
+ * who is an administrator, declared beside the resolver that reads it.
2531
+ *
2532
+ * ## Why this file exists (#8734)
2533
+ *
2534
+ * `plugin-auth`'s break-glass guard (`last-admin-guard.ts`, ADR-0024 D5.2)
2535
+ * decides whether a pending write can empty the administrator population by
2536
+ * testing the payload against three standing-key lists — `MEMBER_STANDING_KEYS`,
2537
+ * `GRANT_STANDING_KEYS`, `PERMISSION_SET_STANDING_KEYS`. Those lists are not an
2538
+ * independent design artifact: they are a CACHE of the columns this resolver
2539
+ * consumes. A payload touching none of them is skipped without any reads, so a
2540
+ * column this resolver starts reading and the guard's list omits is a write
2541
+ * class the guard silently stops judging — the one write class that can lock an
2542
+ * installation out of its own administration, with no in-product recovery.
2543
+ *
2544
+ * Nothing bound the two together. The correspondence was carried by a comment,
2545
+ * and it had already gone false once: #6084 wrote, beside the list, that
2546
+ * everything a permission-set write touches other than `name` — naming `active`
2547
+ * explicitly — is invisible to "who is an administrator". That was true when
2548
+ * written. #8613 made `active` a resolution-time predicate (a DEACTIVATED
2549
+ * `admin_full_access` set confers nothing, §6b below), and the sentence became
2550
+ * false. It was caught by one agent reading the comment closely enough to
2551
+ * notice it contradicted the code being written. Nothing mechanical would have
2552
+ * caught it: the guard's own tests stay green, because the guard is simply never
2553
+ * consulted for that write.
2554
+ *
2555
+ * ## What this file is, and what it is NOT
2556
+ *
2557
+ * It is a MEASUREMENT, not a wish. Its column lists are asserted equal to what
2558
+ * the resolver actually reads at runtime, by
2559
+ * `admin-standing-surface.test.ts`, which drives the real
2560
+ * `resolveAuthzContext` over a recording engine and collects every property
2561
+ * access and every `where` key per table. That is deliberate: a hand-written
2562
+ * list of "columns the derivation reads" is the same artifact as the comment
2563
+ * that went stale, one indirection along. Observation is also the only reading
2564
+ * that survives the derivation moving INTO a helper — `active` is read by
2565
+ * `isRowActive(ps)` and the window bounds by `isGrantActive(row, now)`, neither
2566
+ * of which names a column at the resolver's own call site.
2567
+ *
2568
+ * It is NOT a projection the resolver consumes. `ql.find` here returns whole
2569
+ * rows and the reads are ordinary property accesses on untyped rows, so nothing
2570
+ * in this file can FORCE the resolver to read only what it declares. The force
2571
+ * comes from the observation test: add a read, and this declaration is red
2572
+ * until it is updated; update this declaration, and `plugin-auth`'s
2573
+ * correspondence test is red until every new column is either in a standing-key
2574
+ * list or explicitly excluded with a reason.
2575
+ *
2576
+ * ## Reading the entries
2577
+ *
2578
+ * Every table this resolution path reads is listed — including the ones that
2579
+ * CANNOT confer administrator standing, each with the reason it cannot. That is
2580
+ * the table-level half of the same guarantee: a resolver that starts deriving
2581
+ * administrator standing from a new table would otherwise be invisible to a
2582
+ * column-set comparison, because the new table appears in neither side's list.
2583
+ */
2584
+ /** How a table this resolver reads relates to "who is an administrator". */
2585
+ interface AdminStandingTable {
2586
+ /**
2587
+ * `derives` — a write to this table can change the administrator population,
2588
+ * so `last-admin-guard.ts` must carry a standing-key list for it.
2589
+ * `reads-only` — this resolver reads the table for something else entirely.
2590
+ */
2591
+ readonly role: 'derives' | 'reads-only';
2592
+ /** Why the row above is the right classification. Prose, but pinned to a measured table. */
2593
+ readonly reason: string;
2594
+ /**
2595
+ * Every column this resolver reads on the table — property accesses and
2596
+ * `where` keys alike, in every spelling it actually touches. Declared for
2597
+ * `derives` tables only; asserted equal to the observed set.
2598
+ */
2599
+ readonly columns?: readonly string[];
2600
+ }
2601
+ /**
2602
+ * The measured read surface of the administrator derivation.
2603
+ *
2604
+ * Scope, stated so the gate cannot be read as claiming more than it measures:
2605
+ * this is the SESSION/user-id resolution path — `resolveAuthzContext` with a
2606
+ * principal, and therefore all of `resolveUserAuthzGrants`. The API-key
2607
+ * ADMISSION path (`resolveApiKeyAdmission`) is outside it on purpose: it
2608
+ * authenticates a principal and seeds `permissions` with the key's scopes, and
2609
+ * confers no administrator standing of its own — `hasPlatformAdminGrant` (§6b)
2610
+ * is set only from a `sys_permission_set` row reached through an UNSCOPED
2611
+ * `sys_user_permission_set` grant, never from a scope string.
2612
+ */
2613
+ declare const ADMIN_STANDING_SURFACE: Readonly<Record<string, AdminStandingTable>>;
2614
+ /** The tables a write to which can change who is an administrator. */
2615
+ declare function adminStandingTables(): string[];
2616
+ /**
2617
+ * The columns this resolver reads on `table`, or `undefined` when the table is
2618
+ * not part of the administrator derivation.
2619
+ */
2620
+ declare function adminStandingColumns(table: string): readonly string[] | undefined;
2621
+
2622
+ /**
2623
+ * [#7678] The `?status=` vocabulary of the audience-binding suggestion list
2624
+ * (ADR-0090 D5/D9) — ONE owner for a rule that had exactly one implementation
2625
+ * and two seams needing it.
2626
+ *
2627
+ * The predicate was written for the runtime dispatcher's `/security` domain and
2628
+ * lived there, private. The **live** REST route
2629
+ * (`rest-server.ts` → `registerSecurityEndpoints`) is a second seam onto the
2630
+ * same service call and never had it, so `?status=garbage` reached the service,
2631
+ * matched no row, and answered **200 with an empty list** — which reads as
2632
+ * "there are no suggestions", a plausible and actionable-looking answer, rather
2633
+ * than "your filter was not a status". That silent arm is the defect; the two
2634
+ * seams disagreeing about one contract is the cause.
2635
+ *
2636
+ * So this module is the convergence, not a copy: `domains/security.ts` and
2637
+ * `rest-server.ts` both import from here, and the vocabulary — including the
2638
+ * refusal wording — exists once.
2639
+ *
2640
+ * The record is keyed BY the contract type on purpose (carried over from the
2641
+ * original): adding a status to `AudienceBindingSuggestionFilter` leaves a key
2642
+ * missing here and renaming one leaves a key excess, and either way this fails
2643
+ * to compile. A plain `['pending', …]` array would silently drift.
2644
+ */
2645
+
2646
+ /** The `status` arm of {@link AudienceBindingSuggestionFilter}, named. */
2647
+ type AudienceBindingSuggestionStatus = NonNullable<AudienceBindingSuggestionFilter['status']>;
2648
+ /** The accepted `?status=` values, keyed by the contract type (see module note). */
2649
+ declare const AUDIENCE_BINDING_SUGGESTION_STATUSES: Record<AudienceBindingSuggestionStatus, true>;
2650
+ /**
2651
+ * The same vocabulary as a list — for refusal messages, and for tests that must
2652
+ * enumerate every valid value FROM the type rather than hand-picking one.
2653
+ */
2654
+ declare const AUDIENCE_BINDING_SUGGESTION_STATUS_VALUES: readonly AudienceBindingSuggestionStatus[];
2655
+ /**
2656
+ * Is `value` one of the three statuses the contract declares? Case-sensitive on
2657
+ * purpose — the contract's values are lowercase, so `PENDING` is not a status
2658
+ * and gets the same refusal as `garbage`.
2659
+ */
2660
+ declare const isAudienceBindingSuggestionStatus: (value: string) => value is AudienceBindingSuggestionStatus;
2661
+ /** The refusal wording, shared so both seams answer an unknown status identically. */
2662
+ declare const unknownAudienceBindingSuggestionStatusMessage: (value: string) => string;
2663
+
2315
2664
  /**
2316
2665
  * [#7284] The `__` operation-private-key convention — one owner, on the
2317
2666
  * CONSUMER side.
@@ -2333,8 +2682,10 @@ declare function isGrantExpired(row: GrantValidityWindow | null | undefined, now
2333
2682
  * `__delegatorReadScope` / `__delegatorWriteScope`, stamped in place by
2334
2683
  * `security-plugin.ts` (`sc.__readScope = …`);
2335
2684
  * - the engine's internal privilege markers on the same channel —
2336
- * `__expandRead` waives the object-level CRUD check for a lookup expansion,
2337
- * `__referentialFieldClear` the referential-clear write.
2685
+ * `__expandRead` marks a read as a lookup EXPANSION sub-read (it no longer
2686
+ * relaxes any gate — #7626 removed that waiver — but it still travels with
2687
+ * one operation and must not be inherited by another), `__referentialFieldClear`
2688
+ * authorizes the referential-clear write.
2338
2689
  *
2339
2690
  * plugin-security is the PRODUCER of that vocabulary and would be the most
2340
2691
  * honest owner of the rule for consuming it, but none of the three consumers
@@ -2464,6 +2815,20 @@ interface CalendarParts {
2464
2815
  month: number;
2465
2816
  day: number;
2466
2817
  }
2818
+ /**
2819
+ * A wall clock as a human writes it — calendar day plus an optional
2820
+ * time-of-day, with **no zone attached**. `2026-08-01 06:00:00` is this shape:
2821
+ * it names a reading on a clock, and only a reference timezone turns it into an
2822
+ * instant. Omitted time components default to 0, so {@link CalendarParts} alone
2823
+ * is midnight.
2824
+ */
2825
+ interface WallClockParts extends CalendarParts {
2826
+ /** 0-23. */
2827
+ hour?: number;
2828
+ minute?: number;
2829
+ second?: number;
2830
+ millisecond?: number;
2831
+ }
2467
2832
  /**
2468
2833
  * The year/month/day an instant falls on in `tz`. Throws if `tz` is not a
2469
2834
  * valid IANA zone (callers treat that as a fall-through to UTC).
@@ -2488,8 +2853,52 @@ declare function calendarPartsInTzOrUtc(d: Date, tz?: string): CalendarParts;
2488
2853
  *
2489
2854
  * Used by date-bucket drill ranges (#1752): a `datetime` field buckets on the
2490
2855
  * reference-tz calendar, so its bucket boundary is that tz's midnight instant.
2856
+ *
2857
+ * Date-only by contract: a `YYYY-MM-DD HH:mm:ss` argument is still `NaN` here.
2858
+ * Callers holding a wall clock with a time-of-day want
2859
+ * {@link zonedWallClockToUtcMs}, which this delegates its zone arithmetic to.
2491
2860
  */
2492
2861
  declare function zonedDateStartToUtcMs(ymd: string, tz?: string): number;
2862
+ /**
2863
+ * The UTC instant (epoch ms) at which a **wall clock** reading happens in
2864
+ * reference timezone `tz` — the general inverse of {@link calendarPartsInTz},
2865
+ * of which {@link zonedDateStartToUtcMs} is the midnight special case.
2866
+ *
2867
+ * `2026-08-01 06:00:00` in `Asia/Shanghai` is `2026-07-31T22:00:00Z`: a
2868
+ * different day, month and quarter. That gap is why this direction exists as a
2869
+ * shared primitive at all — bulk import (#8485) reads offset-free spreadsheet
2870
+ * cells, which are wall clocks and nothing more, and `new Date(cell)` resolves
2871
+ * them against the **process** `TZ`, i.e. a host setting rather than the
2872
+ * tenant's configured zone.
2873
+ *
2874
+ * DST-safe: the zone offset is read from the platform tz database via
2875
+ * `Intl.DateTimeFormat` (never hand-computed), and a two-pass resolution settles
2876
+ * the case where the offset differs side-to-side of the target instant. Two
2877
+ * wall clocks are not a bijection with instants, and this function resolves
2878
+ * both degenerate cases to the **earlier candidate instant** — in both, the
2879
+ * final pass reads the offset on the DST side of the transition (measured, not
2880
+ * merely intended — `datetime.test.ts` pins both):
2881
+ * - a clock reading the zone **skips** (spring forward: `02:30` on a US
2882
+ * spring-forward day) settles on the *post*-transition offset (EDT, −04),
2883
+ * which places the instant just **before** the gap: it reads `01:30` EST
2884
+ * locally, not `03:30` EDT. Note this is the opposite of Temporal's
2885
+ * `'compatible'` disambiguation, which pushes a gap reading forward;
2886
+ * - a clock reading that happens **twice** (fall back: `01:30` on a US
2887
+ * fall-back day) resolves to its first occurrence, the one still on the
2888
+ * pre-transition DST offset (EDT, −04).
2889
+ *
2890
+ * A spreadsheet cell naming a wall clock that its zone never had is ambiguous
2891
+ * by construction; what matters for an import is that the answer is
2892
+ * deterministic and host-independent, which both branches above are.
2893
+ *
2894
+ * FALLBACK — an unset, `'UTC'`, or invalid `tz` reads the wall clock **as UTC**,
2895
+ * never as the process-local clock. Every caller of this family already degrades
2896
+ * that way ({@link zonedDateStartToUtcMs}, and the export renderer's cell path),
2897
+ * and a host `TZ` fallback would reintroduce exactly the deployment-dependent
2898
+ * instant this primitive exists to remove. A parts object that produces an
2899
+ * invalid date (`NaN` components) returns `NaN`, as `Date.UTC` does.
2900
+ */
2901
+ declare function zonedWallClockToUtcMs(parts: WallClockParts, tz?: string): number;
2493
2902
 
2494
2903
  /**
2495
2904
  * Granularity of a canonical date-bucket key. Mirrors `@objectstack/spec`'s
@@ -2641,6 +3050,30 @@ declare function withTransientRetry<T>(fn: (attempt: number) => Promise<T>, opts
2641
3050
  */
2642
3051
  declare function bulkWrite<TRow, TRecord = any>(rows: TRow[], opts: BulkWriteOptions<TRow, TRecord>): Promise<BulkWriteRowResult<TRecord>[]>;
2643
3052
 
3053
+ /**
3054
+ * Collect the names of fields declared `internal: true` on `schema`.
3055
+ *
3056
+ * Same verdicts as objectql's `collectInternalReadFields` (see the module
3057
+ * header for why it is restated rather than imported): strict `=== true`,
3058
+ * empty result for a missing/field-less schema.
3059
+ */
3060
+ declare function collectInternalWriteResponseFields(schema: unknown): string[];
3061
+ /**
3062
+ * Drop every `internal: true` field from a write response's record(s), in
3063
+ * place. THE single helper every external write mouth goes through — see the
3064
+ * module header; the three tripwires enforce the "every".
3065
+ *
3066
+ * @param schema The registered object schema (`engine.registry.getObject(...)`
3067
+ * / the protocol's own registry view / `metadataService
3068
+ * .getObject(...)`). An unknown object (no schema) strips
3069
+ * nothing — the write itself would have been refused upstream
3070
+ * by the object-existence gate.
3071
+ * @param records A single record, an array of records, or anything a write
3072
+ * mouth hands back where a record could sit (`null`, a count, a
3073
+ * boolean): non-objects are skipped, arrays are walked.
3074
+ */
3075
+ declare function omitInternalFieldsFromWriteResponse(schema: unknown, records: unknown): void;
3076
+
2644
3077
  /**
2645
3078
  * Can this runtime actually roll back? — the ADR-0119 D4 gate, shared.
2646
3079
  *
@@ -2934,6 +3367,87 @@ declare function resolveFilterTokens<T>(filter: T, ctx?: FilterTokenResolutionCo
2934
3367
  */
2935
3368
  declare function filterTokenContextFrom(execCtx: ExecutionContextLike | undefined, now?: Date): FilterTokenResolutionContext;
2936
3369
 
3370
+ /** Which temporal storage rule a declared field takes. */
3371
+ type TemporalComparandKind = 'datetime' | 'date' | 'time';
3372
+ /**
3373
+ * The kind a declared field's `type` takes, or `null` for every non-temporal
3374
+ * field.
3375
+ *
3376
+ * The same three-way split `driver-memory`'s `indexTemporalFields` and
3377
+ * `SqlDriver.temporalFieldKind` make, so the door and the drivers cannot
3378
+ * disagree about which fields are temporal at all.
3379
+ */
3380
+ declare function temporalComparandKind(fieldType: unknown): TemporalComparandKind | null;
3381
+ /**
3382
+ * Is `value` a comparand that a `kind` column's storage rule cannot read?
3383
+ *
3384
+ * `true` ONLY for a non-empty, non-placeholder STRING that the kind's rule
3385
+ * would hand back unchanged. Everything else — a number, a `Date`, `null`, a
3386
+ * `{ $field }` reference, filter structure, the empty string, a `{token}` —
3387
+ * answers `false`, each for a reason recorded in the module note or below.
3388
+ *
3389
+ * A `{placeholder}` is stepped around rather than judged because it is another
3390
+ * layer's vocabulary and that layer already refuses the unknown ones loudly
3391
+ * (`FILTER_TOKEN_UNKNOWN` / 400, with the resolvable tokens listed). Both doors
3392
+ * that call this run BEFORE token resolution, so judging a placeholder here
3393
+ * would refuse `{30_days_ago}` — the platform's own correct spelling, and the
3394
+ * positive control this fix is pinned against.
3395
+ */
3396
+ declare function isUninterpretableTemporalComparand(kind: TemporalComparandKind, value: unknown): boolean;
3397
+
3398
+ /**
3399
+ * [#4435] The 404 a single-record operation answers when the id names no row.
3400
+ *
3401
+ * Extracted so the READ and the two WRITE paths cannot disagree about it. They
3402
+ * did: `getData` answered `404 RECORD_NOT_FOUND` while `updateData` returned
3403
+ * `200 { record: null }` and `deleteData` returned `200 { success: true }` for
3404
+ * any string in the path — so a typo'd id, an already-deleted row and a real
3405
+ * deletion were indistinguishable, and a client PATCHing a concurrently deleted
3406
+ * record was told its write had landed.
3407
+ *
3408
+ * That is the same silent-no-op shape the v17 train removed everywhere else
3409
+ * this window (#4240/#4303/#4315 refuse missing fields, #4169 refuses unknown
3410
+ * params, #4190 stopped dropping filters) — a write that touched zero rows
3411
+ * reporting 200 is that shape one level up, on the verb where it costs the
3412
+ * most.
3413
+ *
3414
+ * [#5138] EXPORTED, for the same "cannot disagree about it" reason one layer
3415
+ * out. `@objectstack/runtime`'s `callData` is protocol-first with an ObjectQL
3416
+ * FALLBACK, and the fallback had reinvented this fact three incompatible ways
3417
+ * (`get` → `null`, `update` → a bare `Error` with no status ⇒ 500, `delete` →
3418
+ * no check at all ⇒ `200 { deleted: true }` for a row that never existed). It
3419
+ * now calls THIS function, so the two paths behind one `callData` answer a
3420
+ * missing id identically — which is the only reason a caller may stop caring
3421
+ * which of them served it. Re-spelling the envelope there would have been a
3422
+ * second not-found envelope; `RECORD_NOT_FOUND` (#5088) is the one this repo
3423
+ * has.
3424
+ *
3425
+ * ── [#7867] Why it lives in `@objectstack/core` and not where it was written ──
3426
+ *
3427
+ * Because the THIRD path that needed it could not reach the second one. An
3428
+ * action body's `ctx.api.object(name).update({ id, … })` traverses neither
3429
+ * `protocol.updateData` nor `callData`: it reaches `ObjectQL.update()`'s by-id
3430
+ * branch directly, which had no existence gate at all, so a ghost id was a
3431
+ * silent no-op that then died on whatever the pipeline complained about first
3432
+ * (a `HookConditionError` 400 on a hooked object, a required-field
3433
+ * `VALIDATION_FAILED` 400 on an unhooked one — the 400 class varied with the
3434
+ * object's declarations; the missing 404 was the constant).
3435
+ *
3436
+ * The gate for that path belongs in the engine, and `packages/objectql` cannot
3437
+ * import `@objectstack/metadata-protocol` where this function was written:
3438
+ * ADR-0076 D2's boundary ratchet (`core-boundary.ratchet.test.ts`) forbids the
3439
+ * whole `@objectstack/objectql/core` closure — `engine.ts` included — from
3440
+ * pulling that package in. So the choice was a FOURTH spelling of the envelope
3441
+ * or one home both layers already depend on. #5138's own sentence rules the
3442
+ * first out, so this is the second: the factory moved down to the lowest
3443
+ * package the three producers share, and `@objectstack/metadata-protocol`
3444
+ * re-exports it unchanged for every existing importer.
3445
+ *
3446
+ * This is the same move `engineCanRollBack` made for the same reason — a fact
3447
+ * two layers must agree on lives in the layer beneath both, not in a copy each.
3448
+ */
3449
+ declare function recordNotFoundError(object: string, id: string | number): Error;
3450
+
2937
3451
  /**
2938
3452
  * In-memory Map-backed cache fallback.
2939
3453
  *
@@ -3069,7 +3583,24 @@ declare function createMemoryI18n(): {
3069
3583
  * not a merge — so deleted items/keys stop resolving on the next sync.
3070
3584
  */
3071
3585
  replaceAuthoredTranslations(byLocale: Record<string, Record<string, unknown>>): void;
3586
+ /**
3587
+ * Report the locales this stack offers.
3588
+ *
3589
+ * [#7679] When the app declared `i18n.supportedLocales`, that declaration
3590
+ * IS the answer — in declared order, and including a declared locale no
3591
+ * bundle was ever loaded for (declared-but-unserved). Reporting the
3592
+ * declaration rather than an intersection is what gives a client the
3593
+ * signal that the locale it is being offered has nothing behind it yet;
3594
+ * quietly dropping it would leave the gap invisible on both sides. It is
3595
+ * also the only answer that does not depend on how much had loaded by the
3596
+ * time this was called.
3597
+ *
3598
+ * With nothing declared, the loaded set — the behaviour every app that
3599
+ * never opted in already has.
3600
+ */
3072
3601
  getLocales(): string[];
3602
+ /** @see II18nService.setSupportedLocales — [#7679] */
3603
+ setSupportedLocales(locales: readonly string[] | undefined): void;
3073
3604
  getDefaultLocale(): string;
3074
3605
  setDefaultLocale(locale: string): void;
3075
3606
  };
@@ -3080,6 +3611,13 @@ declare function createMemoryI18n(): {
3080
3611
  * Implements the IMetadataService contract with a simple Map-of-Maps store.
3081
3612
  * Used by ObjectKernel as an automatic fallback when no real metadata plugin
3082
3613
  * (e.g. MetadataPlugin with file-system persistence) is registered.
3614
+ *
3615
+ * [#7378] Carries the ruled register/read argument contract
3616
+ * (`../metadata-service-contract.ts` — the ruling is quoted there):
3617
+ * `register` refuses a `data.name` that disagrees with the `name` argument and
3618
+ * refuses a non-document `data` (rows 1/3), and every type store is keyed on
3619
+ * the CANONICAL type (row 2), so `register('objects', n, d)` and
3620
+ * `get('object', n)` address one store rather than two.
3083
3621
  */
3084
3622
  declare function createMemoryMetadata(): {
3085
3623
  __serviceInfo: {
@@ -3133,6 +3671,37 @@ declare function wireAuthoredTranslationSync(ctx: MinimalCtx): void;
3133
3671
  */
3134
3672
  declare const CORE_FALLBACK_FACTORIES: Record<string, () => Record<string, any>>;
3135
3673
 
3674
+ /**
3675
+ * The canonical spelling an `IMetadataService` type store is keyed on
3676
+ * (#7378 row 2). Folds a plural manifest spelling to the singular metadata
3677
+ * type name (`'objects'` → `'object'`, `'views'` → `'view'`, …) through the
3678
+ * platform's one plural↔singular map (`PLURAL_TO_SINGULAR`,
3679
+ * `@objectstack/spec/shared`); a name with no plural mapping — which includes
3680
+ * every canonical singular type — passes through unchanged.
3681
+ */
3682
+ declare function canonicalMetadataServiceType(type: string): string;
3683
+ /**
3684
+ * Enforce rows 1 and 3 of the #7378 ruling on a
3685
+ * `register(type, name, data)` payload — call it before the first store write,
3686
+ * so a refusal writes nothing anywhere.
3687
+ *
3688
+ * Refuses, with a locating `VALIDATION_ERROR` (status 400):
3689
+ *
3690
+ * - **a non-document `data`** (row 3): anything that is not a plain object —
3691
+ * primitives, `null`, arrays. The contract declares `data: unknown`, so
3692
+ * this is a runtime refusal, not a type error;
3693
+ * - **a `data.name` that disagrees with the `name` argument** (row 1), in
3694
+ * either direction. A document with NO `name` of its own is fine — the
3695
+ * argument is the key, and there is no disagreement to refuse.
3696
+ *
3697
+ * Deliberately NOT called by `registerInMemory`: that optional member is a
3698
+ * boot-time seeding primitive outside the ruled surface (the ruling names
3699
+ * `register`), and its callers hand it artefacts whose shape source control
3700
+ * owns. It shares the row-2 canonical fold — a store key is a store fact, not
3701
+ * a per-member choice — just not the refusals.
3702
+ */
3703
+ declare function assertMetadataRegisterContract(type: string, name: string, data: unknown): asserts data is Record<string, unknown>;
3704
+
3136
3705
  /**
3137
3706
  * Plugin Health Monitor
3138
3707
  *
@@ -3450,4 +4019,4 @@ declare class NamespaceResolver {
3450
4019
  private suggestAlternative;
3451
4020
  }
3452
4021
 
3453
- export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, ENTRY_EXECUTION_CONTEXT_FIELDS, type EngineWithTransaction, type EntryExecutionContextField, type EntryLocalization, type ExecutionContextAssemblyInput, type ExecutionContextEntryFields, type ExecutionContextLike, type FilterTokenResolutionContext, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type InterruptedRun, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type MigrationChunk, type MigrationChunkContext, MigrationJournalRefusal, type MigrationPlan, type MigrationPlanProvider, MigrationPlanRegistry, type MigrationPlanStep, type MigrationRunResult, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, type OAuthTokenProvenance, OPERATION_PRIVATE_KEY_PREFIX, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type OrderablePlugin, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, type RunMigrationJournalOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, assembleExecutionContext, assembleExecutionContextOrGuest, assertInitServiceRequirements, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, hashMigrationPlan, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, normalizeAuthGate, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readRunJournal, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, runMigrationJournal, safeExit, shouldDenyAnonymous, signPayload, validateInitServiceContract, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, withoutOperationPrivateKeys, zonedDateStartToUtcMs };
4022
+ export { ADMIN_STANDING_SURFACE, ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, AUDIENCE_BINDING_SUGGESTION_STATUSES, AUDIENCE_BINDING_SUGGESTION_STATUS_VALUES, type ActivatableRow, type AdminStandingTable, type AnonymousDenyInput, type ApiKeyAdmission, type ApiKeyPrincipal, type ApiKeyRefusalReason, type AudienceBindingSuggestionStatus, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, ENTRY_EXECUTION_CONTEXT_FIELDS, type EngineWithTransaction, type EntryExecutionContextField, type EntryLocalization, type ExecutionContextAssemblyInput, type ExecutionContextEntryFields, type ExecutionContextLike, type FilterTokenResolutionContext, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type InterruptedRun, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type MigrationChunk, type MigrationChunkContext, MigrationJournalRefusal, type MigrationPlan, type MigrationPlanProvider, MigrationPlanRegistry, type MigrationPlanStep, type MigrationRunResult, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, type OAuthTokenProvenance, OPERATION_PRIVATE_KEY_PREFIX, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type OrderablePlugin, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, type RunMigrationJournalOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type TemporalComparandKind, type TenancyPostureSource, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, type WallClockParts, adminStandingColumns, adminStandingTables, assembleExecutionContext, assembleExecutionContextOrGuest, assertInitServiceRequirements, assertMetadataRegisterContract, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, canonicalMetadataServiceType, collectInternalWriteResponseFields, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, effectiveTenancyPosture, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, hashMigrationPlan, isAudienceBindingSuggestionStatus, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, isRowActive, isUninterpretableTemporalComparand, normalizeAuthGate, omitInternalFieldsFromWriteResponse, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readRunJournal, recordNotFoundError, resolveApiKeyAdmission, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, runMigrationJournal, safeExit, shouldDenyAnonymous, signPayload, temporalComparandKind, unknownAudienceBindingSuggestionStatusMessage, validateInitServiceContract, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, withoutOperationPrivateKeys, zonedDateStartToUtcMs, zonedWallClockToUtcMs };