@objectstack/core 17.0.0-rc.5 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Logger, LifecycleEventName, IServiceRegistry, IObjectQLEngine } from '@objectstack/spec/contracts';
1
+ import { Logger, LifecycleEventName, IServiceRegistry, AudienceBindingSuggestionFilter, IObjectQLEngine } from '@objectstack/spec/contracts';
2
2
  export { EngineSchemaRegistryView, EngineTransactionInfo, EngineTransactionOptions, IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, IObjectQLEngine, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
3
3
  import { z } from 'zod';
4
4
  import { LoggerConfig, MigrationOnCrashPolicy, MigrationJournalEvent } from '@objectstack/spec/system';
@@ -6,7 +6,7 @@ import { ObjectLogger } from './logger.cjs';
6
6
  export { createLogger } from './logger.cjs';
7
7
  import * as QA from '@objectstack/spec/qa';
8
8
  import { KeyObject } from 'node:crypto';
9
- import { PluginCapability, PluginPermissions as PluginPermissions$1, PluginPermissionSet, ResourceType, PermissionAction, PluginPermission, SandboxConfig, KernelSecurityScanResult, KernelSecurityVulnerability, PluginHealthCheck, PluginHealthStatus as PluginHealthStatus$1, PluginHealthReport, HotReloadConfig, VersionConstraint, DependencyConflict, SemanticVersion, CompatibilityLevel } from '@objectstack/spec/kernel';
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
10
  import { AuthzPosture } from '@objectstack/spec/security';
11
11
  export { nextUtcCalendarDay, utcInstantMs } from '@objectstack/spec/data';
12
12
 
@@ -353,13 +353,18 @@ declare class ObjectKernel {
353
353
  * one bad handler must not amplify into leaked resources and unflushed
354
354
  * writes. Same reasoning, same wording, same `Hook handler failed:
355
355
  * kernel:shutdown` log line as `LiteKernel`'s dispatch site, which reaches
356
- * the shared isolating dispatcher `ObjectKernelBase.triggerHook` (#5257).
356
+ * the isolating dispatcher through `ObjectKernelBase.triggerHook` (#5257).
357
357
  *
358
- * `ObjectKernel` cannot call that dispatcher: it does not extend
358
+ * Until #5282 "same wording" was literally that the loop was typed out a
359
+ * second time here, because `ObjectKernel` does not extend
359
360
  * `ObjectKernelBase` (only `LiteKernel` does) and owns its own `hooks` map,
360
- * so the semantics are mirrored here rather than shared. One hook name
361
- * meaning two opposite things across the two kernels is exactly the bug
362
- * #5170/#5257 closed, so the pin for this one lives on both sides too.
361
+ * so the base's `protected triggerHook` is out of reach. The loop now lives
362
+ * in {@link dispatchHookIsolating}, which BOTH sides call: the storage is
363
+ * still two maps (deliberately unifying it was out of #5282's scope), but
364
+ * "isolating" is one implementation, so it can no longer drift on one
365
+ * kernel while the other keeps the old shape. That drift is exactly the bug
366
+ * #5170 / #5257 / #5274 each closed one hook at a time, and the paired-pin
367
+ * gate (`scripts/check-kernel-hook-pairs.mjs`) covers the residue.
363
368
  */
364
369
  private triggerShutdownHookIsolating;
365
370
  private performShutdown;
@@ -622,6 +627,11 @@ declare abstract class ObjectKernelBase {
622
627
  * (`kernel:ready`, `kernel:bootstrapped`, `kernel:listening`) use
623
628
  * {@link triggerHookOrThrow} (#5170, #5257).
624
629
  *
630
+ * The loop itself lives in {@link dispatchHookIsolating} — one
631
+ * implementation shared with `ObjectKernel`'s own `kernel:shutdown`
632
+ * dispatch, which cannot inherit this method (`ObjectKernel` does not
633
+ * extend this class) and used to hand-mirror it (#5282).
634
+ *
625
635
  * @param name - Hook name
626
636
  * @param args - Arguments to pass to handlers
627
637
  */
@@ -661,6 +671,10 @@ declare abstract class ObjectKernelBase {
661
671
  * default — and it is the reason this dispatcher is chosen per hook rather
662
672
  * than swapped in wholesale.
663
673
  *
674
+ * The loop itself lives in {@link dispatchHookPropagating} — the same
675
+ * function `PluginContext.trigger` runs on both kernels, so "propagating"
676
+ * means one thing repo-wide (#5282).
677
+ *
664
678
  * @param name - Hook name
665
679
  * @param args - Arguments to pass to handlers
666
680
  */
@@ -869,6 +883,10 @@ declare class HttpTestAdapter implements TestExecutionAdapter {
869
883
  private baseUrl;
870
884
  private authToken?;
871
885
  constructor(baseUrl: string, authToken?: string | undefined);
886
+ /** `{baseUrl}{apiBasePath}{dataPrefix}/{object}` — the collection URL. */
887
+ private collectionUrl;
888
+ /** `{collection}/{id}` — the single-record URL. */
889
+ private recordUrl;
872
890
  execute(action: QA.TestAction, _context: Record<string, unknown>): Promise<unknown>;
873
891
  private createRecord;
874
892
  private updateRecord;
@@ -1831,6 +1849,275 @@ declare function resolveLocalizationContext(input: ResolveLocalizationInput): Pr
1831
1849
  currency?: string;
1832
1850
  }>;
1833
1851
 
1852
+ /**
1853
+ * ADR-0069 — authentication-policy session gate.
1854
+ *
1855
+ * Some auth policies (password expiry, enforced MFA) must block an
1856
+ * authenticated user from PROTECTED RESOURCES until they remediate, while
1857
+ * still letting them reach the auth endpoints (change-password, two-factor
1858
+ * enrollment, sign-out) and a few UI-bootstrap reads.
1859
+ *
1860
+ * The posture is computed ONCE, in the auth `customSession` enrichment, and
1861
+ * attached to the session user as `user.authGate = { code, message }`. The
1862
+ * transport seams (REST middleware, dispatcher) then call
1863
+ * {@link evaluateAuthGate} to decide whether THIS request is blocked. Keeping
1864
+ * the allow-list + decision in one pure function means the seams can never
1865
+ * drift on what is blocked.
1866
+ */
1867
+
1868
+ /**
1869
+ * The gate posture, DERIVED from its declaration on `ExecutionContextSchema`
1870
+ * (`packages/spec/src/kernel/execution-context.zod.ts`) rather than restated
1871
+ * here (#7280).
1872
+ *
1873
+ * It was a hand-written interface while the envelope field was undeclared, so
1874
+ * the two could have drifted with nothing to catch it — the exact class of
1875
+ * defect the closed entry field set (#6216) exists to make unrepresentable.
1876
+ * One declaration, one type.
1877
+ */
1878
+ type AuthGate = NonNullable<ExecutionContext['authGate']>;
1879
+ /**
1880
+ * Normalize the `authGate` a better-auth session user carries into the shape
1881
+ * `ExecutionContextSchema` declares — or `null` when there is no gate.
1882
+ *
1883
+ * The session user crosses an external boundary as `any`, so this is where the
1884
+ * declared contract is actually met: a gate naming no string `code` is not a
1885
+ * gate, and a missing/blank `message` is filled with the default rather than
1886
+ * riding onto the envelope (and into a `403` body) as `undefined`. Both
1887
+ * consumers normalize HERE, at the one producer, instead of tolerating a loose
1888
+ * shape downstream: {@link evaluateAuthGate} for the seams that decide per
1889
+ * path, and REST's `computeExecCtx` for the seam that lifts the posture onto
1890
+ * the execution context.
1891
+ */
1892
+ declare function normalizeAuthGate(sessionUser: any): AuthGate | null;
1893
+ /** True when `path` is exempt from the auth gate (auth + remediation + health). */
1894
+ declare function isAuthGateAllowlisted(rawPath: string | undefined | null): boolean;
1895
+ /**
1896
+ * Returns the active gate when `sessionUser` carries an `authGate` AND `path`
1897
+ * is not allow-listed; otherwise null. Anonymous users (no `authGate`) and
1898
+ * allow-listed paths always pass.
1899
+ */
1900
+ declare function evaluateAuthGate(sessionUser: any, path: string): AuthGate | null;
1901
+
1902
+ /**
1903
+ * assembleExecutionContext — the SINGLE assembly of an inbound request's
1904
+ * {@link ExecutionContext}, shared by every transport entry point.
1905
+ *
1906
+ * `resolveAuthzContext` (next door) already made AUTHORIZATION resolution
1907
+ * single-sourced. The step AFTER it — turning the resolved
1908
+ * {@link ResolvedAuthzContext} into the `ExecutionContext` envelope that
1909
+ * reaches enforcement — stayed hand-written per transport, and that duplication
1910
+ * produced a measured defect family:
1911
+ *
1912
+ * - **#6071 — field drift.** The REST copy never set `principalKind`, so every
1913
+ * enforcement judgment reading it (explain's guest⇒EXTERNAL floor, the
1914
+ * security plugin's agent baseline, the perf-disclosure gate) was silently
1915
+ * never-true on that face.
1916
+ * - **#6206 / #6551 — dropped fields.** The share-link copies omitted
1917
+ * `accessible_org_ids`, and the `group` posture's Layer 0 wall reads it
1918
+ * directly: real 403s for callers who should have been let through. Both
1919
+ * surfaces were since converted to pass the WHOLE envelope through.
1920
+ *
1921
+ * Both defects are the same shape: a field exists on `ExecutionContext`, one
1922
+ * copy carries it, another silently does not. This module makes that shape
1923
+ * unrepresentable by CLOSING the field set with a type
1924
+ * ({@link ExecutionContextEntryFields}) — every field a transport entry point
1925
+ * decides must be decided HERE, explicitly, and a new `ExecutionContext` field
1926
+ * fails to compile until it is either assembled or listed as
1927
+ * non-entry-resolved.
1928
+ *
1929
+ * ## Two named entries — the anonymous face is genuinely divergent (#6216)
1930
+ *
1931
+ * The maintainer ruling of 2026-08-08 on #6216 (Option A) settled the one
1932
+ * question that blocked convergence: what an anonymous request yields.
1933
+ *
1934
+ * - {@link assembleExecutionContext} — the DEFAULT, fail-closed entry. No
1935
+ * resolved principal → `undefined`, and the surface answers 401. This is the
1936
+ * REST face's contract, unchanged.
1937
+ * - {@link assembleExecutionContextOrGuest} — the EXPLICIT guest entry. No
1938
+ * resolved principal → a first-class guest envelope
1939
+ * (`principalKind: 'guest'`, `positions: ['guest']`), which the runtime /
1940
+ * MCP dispatcher has always produced and whose consumers are live
1941
+ * (`plugin-security/explain-engine.ts`: guest ⇒ `EXTERNAL` posture). A
1942
+ * surface adopts this entry ONLY when its product semantics serve anonymous
1943
+ * principals.
1944
+ *
1945
+ * Neither surface's runtime behaviour changes. What changes is that the
1946
+ * divergence is now NAMED API rather than drift — and the same is true of the
1947
+ * per-face values below (`accessToken`, `oauth`, `localization`): they are
1948
+ * REQUIRED inputs, so a face cannot silently omit one, and what a face chooses
1949
+ * to withhold it withholds on the record.
1950
+ *
1951
+ * Options B (guest everywhere — turns REST's anonymous 401s into authz-shaped
1952
+ * denials and makes anonymous-serving the DEFAULT posture of a new surface) and
1953
+ * C (no-ctx everywhere — deletes the guest principal, the `guest` position and
1954
+ * explain's `EXTERNAL` floor) were both considered and rejected: each breaks a
1955
+ * live consumer side.
1956
+ */
1957
+
1958
+ /**
1959
+ * `ExecutionContext` fields a transport ENTRY POINT does not resolve — they are
1960
+ * per-operation flags, engine internals, or attribution supplied further down
1961
+ * the stack. Listing one here is a deliberate, reviewable statement that no
1962
+ * request-identity resolution produces it; everything NOT listed is part of the
1963
+ * closed entry set below and must be assembled.
1964
+ *
1965
+ * - `actor` / `attributedUserId` — audit attribution, set by the host or the
1966
+ * hook layer (ADR-0014 D2, #4586), never by identity resolution.
1967
+ * - `rlsMembership` — engine-side RLS scoping cache.
1968
+ * - `transaction` / `traceId` — per-operation handles.
1969
+ * - `flowRunId`, `skipTriggers`, `skipAutomations`, `seedReplay`,
1970
+ * `skipStateMachine`, `preserveAudit` — per-write behaviour flags,
1971
+ * server-constructed at the call site.
1972
+ */
1973
+ type NonEntryExecutionContextField = 'actor' | 'attributedUserId' | 'rlsMembership' | 'transaction' | 'traceId' | 'flowRunId' | 'skipTriggers' | 'skipAutomations' | 'seedReplay' | 'skipStateMachine' | 'preserveAudit';
1974
+ /**
1975
+ * The CLOSED field set every transport entry point must decide. Derived from
1976
+ * `ExecutionContext` itself, so adding a field to `ExecutionContextSchema`
1977
+ * widens this union automatically — and the assembly below stops compiling
1978
+ * until the new field is either assembled or declared non-entry-resolved.
1979
+ */
1980
+ type EntryExecutionContextField = Exclude<keyof ExecutionContext, NonEntryExecutionContextField>;
1981
+ /**
1982
+ * One value per closed field. Every key is REQUIRED (`-?`) while the VALUE may
1983
+ * be `undefined` — the decision may not be omitted, only made explicitly. This
1984
+ * is the type that makes the #6071 drift class unrepresentable.
1985
+ */
1986
+ type ExecutionContextEntryFields = {
1987
+ [K in EntryExecutionContextField]-?: ExecutionContext[K];
1988
+ };
1989
+ /**
1990
+ * Emission order of the assembled envelope, and a second, independent
1991
+ * exhaustiveness bite: `satisfies` rejects a stale name, and
1992
+ * `_ENTRY_FIELDS_EXHAUSTIVE` below rejects a missing one.
1993
+ */
1994
+ declare const ENTRY_EXECUTION_CONTEXT_FIELDS: readonly ["positions", "permissions", "systemPermissions", "isSystem", "principalKind", "onBehalfOf", "audience", "userId", "tenantId", "email", "accessToken", "tabPermissions", "posture", "authGate", "org_user_ids", "accessible_org_ids", "oauthScopes", "timezone", "locale", "currency"];
1995
+ /**
1996
+ * OAuth 2.1 access-token provenance. Reaches the assembler from the `/mcp`
1997
+ * dispatch door ALONE (`acceptOAuthAccessToken`) — OAuth bearers carry coarse
1998
+ * tool-family scopes enforced at MCP tool dispatch, so honouring them on
1999
+ * another surface would bypass that scope model entirely.
2000
+ */
2001
+ interface OAuthTokenProvenance {
2002
+ /** The human `sub` the token was issued for. */
2003
+ userId: string;
2004
+ /** Granted scopes, surfaced on the envelope so MCP can narrow tool families. */
2005
+ scopes: string[];
2006
+ /**
2007
+ * The authorized client (`azp`). Present ⇒ this is an AI AGENT acting on
2008
+ * behalf of the human `userId`; absent ⇒ the token names no client and the
2009
+ * principal stays human (the scopes are still surfaced).
2010
+ */
2011
+ clientId?: string;
2012
+ /**
2013
+ * The agent's OWN permission CEILING, derived from {@link scopes} by the door
2014
+ * that speaks the OAuth scope vocabulary
2015
+ * (`scopesToAgentPermissionSets`, `@objectstack/spec/ai`).
2016
+ *
2017
+ * Interpreted THERE and not here on purpose: the scope vocabulary is
2018
+ * MCP-domain knowledge and `@objectstack/core` is the microkernel — it should
2019
+ * not acquire a dependency on the AI subdomain (concretely, every package
2020
+ * whose test config aliases `@objectstack/core` to its source would then have
2021
+ * to resolve `@objectstack/spec/ai` too, down to `driver-memory`). What the
2022
+ * ceiling REPLACES on the envelope is decided below, once, for every face —
2023
+ * and that is the part that drifted.
2024
+ */
2025
+ scopePermissions: string[];
2026
+ /**
2027
+ * Whether the token carries the user's consent to let this agent invoke
2028
+ * actions on their behalf — the `actions:execute` scope
2029
+ * (`MCP_OAUTH_SCOPE_ACTIONS`), evaluated at the same door for the same
2030
+ * reason.
2031
+ */
2032
+ delegatesActions: boolean;
2033
+ }
2034
+ /** Reference localization for an authenticated principal (@see resolveLocalizationContext). */
2035
+ interface EntryLocalization {
2036
+ timezone?: string;
2037
+ locale?: string;
2038
+ currency?: string;
2039
+ }
2040
+ /**
2041
+ * Everything the shared assembly needs. Every key is REQUIRED so a face cannot
2042
+ * silently omit one — a face that has no value for an input passes `undefined`
2043
+ * on the record, which is what turns the remaining divergences into named API.
2044
+ */
2045
+ interface ExecutionContextAssemblyInput {
2046
+ /** The shared authorization envelope (@see resolveAuthzContext). */
2047
+ authz: ResolvedAuthzContext;
2048
+ /**
2049
+ * OAuth access-token provenance, or `undefined` on a face that does not
2050
+ * accept one. Only the `/mcp` dispatch door passes a value; REST passes
2051
+ * `undefined` — which is why `principalKind: 'agent'`, `onBehalfOf` and
2052
+ * `oauthScopes` are not representable there.
2053
+ */
2054
+ oauth: OAuthTokenProvenance | undefined;
2055
+ /**
2056
+ * Resolved reference localization, or `undefined` when the face resolved
2057
+ * none (anonymous requests have no scope to resolve against).
2058
+ */
2059
+ localization: EntryLocalization | undefined;
2060
+ /**
2061
+ * The request's OWN locale preference (`Accept-Language`, `?locale`, …),
2062
+ * which wins over the workspace default; `undefined` when the caller
2063
+ * expresses none. Each face extracts it its own way — the PRECEDENCE lives
2064
+ * here so the two cannot disagree about it (#3957).
2065
+ */
2066
+ requestLocale: string | undefined;
2067
+ /**
2068
+ * The session bearer to carry on the envelope, surfaced to hooks as
2069
+ * `session.accessToken` (`objectql/engine.ts` `buildSession`,
2070
+ * `spec/data/hook.zod.ts`).
2071
+ *
2072
+ * A NAMED per-face divergence, preserved deliberately (#6216): the runtime /
2073
+ * MCP dispatcher passes `authz.accessToken`; the REST face has never carried
2074
+ * it and passes `undefined`, because widening a published hook surface to
2075
+ * expose the session token on a second transport is a product decision, not a
2076
+ * refactor. Being a required input, the choice is on the record at each face
2077
+ * instead of being an omission nobody can see.
2078
+ */
2079
+ accessToken: string | undefined;
2080
+ /**
2081
+ * [ADR-0069] The AUTHENTICATION-policy gate posture resolved for this
2082
+ * request's session (expired password / enforced MFA), or `undefined` when
2083
+ * the face resolves none — normalize a session user through
2084
+ * `normalizeAuthGate` rather than copying its `authGate` verbatim.
2085
+ *
2086
+ * A NAMED per-face divergence, on the same footing as {@link accessToken}
2087
+ * (#7280):
2088
+ *
2089
+ * - the **REST** face lifts it onto the envelope, because that is where its
2090
+ * consumer reads it (`RestServer.enforceAuth` → `403 { code, message }`);
2091
+ * - the **runtime / MCP dispatcher** passes `undefined`, because it enforces
2092
+ * the same ADR-0069 gate at its OWN seam (`HttpDispatcher.enforceAuthGate`
2093
+ * re-reads the session and calls `evaluateAuthGate` there) and never reads
2094
+ * `context.authGate` — carrying it would be a second, unread copy.
2095
+ *
2096
+ * Until #7280 declared it, this posture reached the envelope through an
2097
+ * `as any` spread AFTER assembly, which put it outside this closed set
2098
+ * entirely — the blind spot the set exists to remove.
2099
+ */
2100
+ authGate: AuthGate | undefined;
2101
+ }
2102
+ /**
2103
+ * The DEFAULT, fail-closed entry (#6216 Option A). An unauthenticated request
2104
+ * yields NO context — the surface answers 401. Every surface uses this one
2105
+ * unless serving anonymous principals is part of its product semantics.
2106
+ */
2107
+ declare function assembleExecutionContext(input: ExecutionContextAssemblyInput): ExecutionContext | undefined;
2108
+ /**
2109
+ * The EXPLICIT guest entry (#6216 Option A). An unauthenticated request becomes
2110
+ * a first-class guest principal — `principalKind: 'guest'`, `positions:
2111
+ * ['guest']` — which enforcement consumers read today
2112
+ * (`plugin-security/explain-engine.ts`: guest ⇒ `EXTERNAL` posture).
2113
+ *
2114
+ * Adopt this ONLY on a surface that genuinely serves anonymous principals: the
2115
+ * built-in `guest` position is the declared vocabulary for "what anonymous may
2116
+ * do", and handing a guest envelope to a surface that previously answered 401
2117
+ * converts an authentication failure into an authorization evaluation.
2118
+ */
2119
+ declare function assembleExecutionContextOrGuest(input: ExecutionContextAssemblyInput): ExecutionContext;
2120
+
1834
2121
  /**
1835
2122
  * ── The monotonic posture ladder (ADR-0095 D2/D3) ───────────────────────────
1836
2123
  *
@@ -1936,36 +2223,6 @@ interface LadderPrincipal {
1936
2223
  */
1937
2224
  declare function postureVisibleRows(posture: AuthzPosture, rows: readonly LadderRow[], principal: LadderPrincipal): LadderRow[];
1938
2225
 
1939
- /**
1940
- * ADR-0069 — authentication-policy session gate.
1941
- *
1942
- * Some auth policies (password expiry, enforced MFA) must block an
1943
- * authenticated user from PROTECTED RESOURCES until they remediate, while
1944
- * still letting them reach the auth endpoints (change-password, two-factor
1945
- * enrollment, sign-out) and a few UI-bootstrap reads.
1946
- *
1947
- * The posture is computed ONCE, in the auth `customSession` enrichment, and
1948
- * attached to the session user as `user.authGate = { code, message }`. The
1949
- * transport seams (REST middleware, dispatcher) then call
1950
- * {@link evaluateAuthGate} to decide whether THIS request is blocked. Keeping
1951
- * the allow-list + decision in one pure function means the seams can never
1952
- * drift on what is blocked.
1953
- */
1954
- interface AuthGate {
1955
- /** Stable machine code, e.g. `PASSWORD_EXPIRED` / `MFA_REQUIRED`. */
1956
- code: string;
1957
- /** Human-facing message. */
1958
- message: string;
1959
- }
1960
- /** True when `path` is exempt from the auth gate (auth + remediation + health). */
1961
- declare function isAuthGateAllowlisted(rawPath: string | undefined | null): boolean;
1962
- /**
1963
- * Returns the active gate when `sessionUser` carries an `authGate` AND `path`
1964
- * is not allow-listed; otherwise null. Anonymous users (no `authGate`) and
1965
- * allow-listed paths always pass.
1966
- */
1967
- declare function evaluateAuthGate(sessionUser: any, path: string): AuthGate | null;
1968
-
1969
2226
  /** HTTP status every seam returns for an anonymous-denied request. */
1970
2227
  declare const ANONYMOUS_DENY_STATUS: 401;
1971
2228
  /** Stable machine code (mirrors the REST `enforceAuth` seam). ADR-0112: SCREAMING, a `StandardErrorCode` member. */
@@ -2059,6 +2316,161 @@ declare function isGrantActive(row: GrantValidityWindow | null | undefined, nowM
2059
2316
  */
2060
2317
  declare function isGrantExpired(row: GrantValidityWindow | null | undefined, nowMs: number): boolean;
2061
2318
 
2319
+ /**
2320
+ * [#7678] The `?status=` vocabulary of the audience-binding suggestion list
2321
+ * (ADR-0090 D5/D9) — ONE owner for a rule that had exactly one implementation
2322
+ * and two seams needing it.
2323
+ *
2324
+ * The predicate was written for the runtime dispatcher's `/security` domain and
2325
+ * lived there, private. The **live** REST route
2326
+ * (`rest-server.ts` → `registerSecurityEndpoints`) is a second seam onto the
2327
+ * same service call and never had it, so `?status=garbage` reached the service,
2328
+ * matched no row, and answered **200 with an empty list** — which reads as
2329
+ * "there are no suggestions", a plausible and actionable-looking answer, rather
2330
+ * than "your filter was not a status". That silent arm is the defect; the two
2331
+ * seams disagreeing about one contract is the cause.
2332
+ *
2333
+ * So this module is the convergence, not a copy: `domains/security.ts` and
2334
+ * `rest-server.ts` both import from here, and the vocabulary — including the
2335
+ * refusal wording — exists once.
2336
+ *
2337
+ * The record is keyed BY the contract type on purpose (carried over from the
2338
+ * original): adding a status to `AudienceBindingSuggestionFilter` leaves a key
2339
+ * missing here and renaming one leaves a key excess, and either way this fails
2340
+ * to compile. A plain `['pending', …]` array would silently drift.
2341
+ */
2342
+
2343
+ /** The `status` arm of {@link AudienceBindingSuggestionFilter}, named. */
2344
+ type AudienceBindingSuggestionStatus = NonNullable<AudienceBindingSuggestionFilter['status']>;
2345
+ /** The accepted `?status=` values, keyed by the contract type (see module note). */
2346
+ declare const AUDIENCE_BINDING_SUGGESTION_STATUSES: Record<AudienceBindingSuggestionStatus, true>;
2347
+ /**
2348
+ * The same vocabulary as a list — for refusal messages, and for tests that must
2349
+ * enumerate every valid value FROM the type rather than hand-picking one.
2350
+ */
2351
+ declare const AUDIENCE_BINDING_SUGGESTION_STATUS_VALUES: readonly AudienceBindingSuggestionStatus[];
2352
+ /**
2353
+ * Is `value` one of the three statuses the contract declares? Case-sensitive on
2354
+ * purpose — the contract's values are lowercase, so `PENDING` is not a status
2355
+ * and gets the same refusal as `garbage`.
2356
+ */
2357
+ declare const isAudienceBindingSuggestionStatus: (value: string) => value is AudienceBindingSuggestionStatus;
2358
+ /** The refusal wording, shared so both seams answer an unknown status identically. */
2359
+ declare const unknownAudienceBindingSuggestionStatusMessage: (value: string) => string;
2360
+
2361
+ /**
2362
+ * [#7284] The `__` operation-private-key convention — one owner, on the
2363
+ * CONSUMER side.
2364
+ *
2365
+ * `assemble-execution-context.ts` next door is the single place an
2366
+ * `ExecutionContext` is BUILT at a transport entry point (#6216). This file is
2367
+ * its counterpart at the other end: the single place one is stripped back down
2368
+ * before being forwarded to a question it was not resolved for.
2369
+ *
2370
+ * ## What a `__` key is
2371
+ *
2372
+ * plugin-security's middleware STAMPS keys onto the operation context, resolved
2373
+ * for the object of the operation IN FLIGHT. They are middleware-private
2374
+ * vocabulary, not fields of `ExecutionContext`, and every one of them is read as
2375
+ * a WIDENING input by whoever consumes it:
2376
+ *
2377
+ * - the ADR-0057 D1 access DEPTH the sharing owner-match expands to —
2378
+ * `__readScope` / `__writeScope`, plus the ADR-0090 D10 delegator halves
2379
+ * `__delegatorReadScope` / `__delegatorWriteScope`, stamped in place by
2380
+ * `security-plugin.ts` (`sc.__readScope = …`);
2381
+ * - the engine's internal privilege markers on the same channel —
2382
+ * `__expandRead` marks a read as a lookup EXPANSION sub-read (it no longer
2383
+ * relaxes any gate — #7626 removed that waiver — but it still travels with
2384
+ * one operation and must not be inherited by another), `__referentialFieldClear`
2385
+ * authorizes the referential-clear write.
2386
+ *
2387
+ * plugin-security is the PRODUCER of that vocabulary and would be the most
2388
+ * honest owner of the rule for consuming it, but none of the three consumers
2389
+ * depends on it and a string-prefix filter does not justify three new dependency
2390
+ * edges onto a plugin (the trade the filing card priced, #7284). `@objectstack/
2391
+ * spec` is fenced off by Prime Directive #2. `@objectstack/core` is the only
2392
+ * candidate every consumer already depends on, so the rule lives here and the
2393
+ * producer stays free of reverse edges.
2394
+ *
2395
+ * ## Why a consumer must drop them
2396
+ *
2397
+ * A caller's envelope carries a depth resolved for the object the middleware
2398
+ * last saw. A consumer that forwards that envelope to ask about a DIFFERENT
2399
+ * object applies one object's widening to another object's question — the exact
2400
+ * stale-scope leak `resolveWriteScopeForSharing` was extracted to prevent ("a
2401
+ * stale value can never leak in through a spread", `security-plugin.ts`).
2402
+ *
2403
+ * The leak is not hypothetical and does not require the consumer to be careless:
2404
+ * plugin-security only OVERWRITES `__readScope` when it actually resolves
2405
+ * permission sets for the new object (`if (permissionSets.length > 0)`), so a
2406
+ * stale depth SURVIVES into a question it was never resolved for whenever that
2407
+ * branch does not fire. A REST request that touched another object before
2408
+ * reaching, say, `/reports/:id/run` hands over an envelope the middleware has
2409
+ * already written into.
2410
+ *
2411
+ * Dropping is safe in the one direction that matters: the middleware re-stamps
2412
+ * the depth for THIS object when it resolves any set, so the only thing dropping
2413
+ * can do is leave the sharing owner-match at its narrowest (`own`) — the safe
2414
+ * direction.
2415
+ *
2416
+ * ## Why by PREFIX and never by a name list
2417
+ *
2418
+ * The `__` convention is what marks a key as belonging to the operation in
2419
+ * flight. A hand-maintained list of the six names above would go stale the day
2420
+ * the middleware stamps a seventh, and it would go stale SILENTLY — a forwarded
2421
+ * key nobody remembered to add reads exactly like a key that was meant to be
2422
+ * forwarded. The prefix is the contract; the names are its current membership.
2423
+ *
2424
+ * ⛔ The corollary, for whoever changes the middleware: a key that is
2425
+ * operation-private MUST carry the `__` prefix. Stamping one without it makes it
2426
+ * invisible to every consumer at once, and there is no compiler error.
2427
+ *
2428
+ * ## Known consumers
2429
+ *
2430
+ * `plugin-audit` (`comment-access-hooks.ts`, #7141), `service-storage`
2431
+ * (`attachment-access-hooks.ts`, #7145) and `plugin-reports`
2432
+ * (`report-service.ts`, #7204) — each forwarding a caller envelope to a gate or
2433
+ * a read that asks about a parent/target object rather than about the object the
2434
+ * middleware resolved for. Each of the three grew its own byte-equivalent copy
2435
+ * of this file by hand before #7284 gave the rule a home; `operation-private-
2436
+ * keys.pin.test.ts` is what now catches a fourth.
2437
+ */
2438
+
2439
+ /**
2440
+ * The prefix marking a key as private to the operation plugin-security has in
2441
+ * flight. See this module's header for why the convention is a prefix and not a
2442
+ * list of names.
2443
+ */
2444
+ declare const OPERATION_PRIVATE_KEY_PREFIX = "__";
2445
+ /**
2446
+ * The caller's execution envelope, minus the operation-private keys.
2447
+ *
2448
+ * A FRESH object every time, and that is load-bearing in BOTH directions:
2449
+ *
2450
+ * - outbound — a callee that stamps its own `__writeScope` onto what it
2451
+ * receives (which is exactly what plugin-security does before it calls the
2452
+ * sharing service) can never write back into the operation context the caller
2453
+ * was handed;
2454
+ * - inbound — the engine's middleware stamps a depth for the object it is about
2455
+ * to read onto whatever it is handed, so forwarding a caller's envelope BY
2456
+ * REFERENCE would write that depth back into the request context the route
2457
+ * goes on using.
2458
+ *
2459
+ * ⛔ Never `return exec;` on the "nothing to strip" path. The copy is the point,
2460
+ * not an optimisation to skip when the envelope happens to be clean — the two
2461
+ * hazards above are about the callee's future writes, not about the current
2462
+ * contents.
2463
+ *
2464
+ * Note what this deliberately does NOT do: it strips, it never SYNTHESISES a
2465
+ * depth for the new object. Absent depth leaves the sharing owner-match at its
2466
+ * narrowest (`own`), which is the safe direction and byte-for-byte what the
2467
+ * five-field projections these call sites replaced produced.
2468
+ *
2469
+ * @param exec the caller's envelope, as a bare record
2470
+ * @returns a new envelope carrying only the non-operation-private keys
2471
+ */
2472
+ declare function withoutOperationPrivateKeys(exec: Record<string, unknown>): ExecutionContext;
2473
+
2062
2474
  /**
2063
2475
  * Environment utilities for universal (Node/Browser) compatibility.
2064
2476
  */
@@ -2277,6 +2689,30 @@ declare function withTransientRetry<T>(fn: (attempt: number) => Promise<T>, opts
2277
2689
  */
2278
2690
  declare function bulkWrite<TRow, TRecord = any>(rows: TRow[], opts: BulkWriteOptions<TRow, TRecord>): Promise<BulkWriteRowResult<TRecord>[]>;
2279
2691
 
2692
+ /**
2693
+ * Collect the names of fields declared `internal: true` on `schema`.
2694
+ *
2695
+ * Same verdicts as objectql's `collectInternalReadFields` (see the module
2696
+ * header for why it is restated rather than imported): strict `=== true`,
2697
+ * empty result for a missing/field-less schema.
2698
+ */
2699
+ declare function collectInternalWriteResponseFields(schema: unknown): string[];
2700
+ /**
2701
+ * Drop every `internal: true` field from a write response's record(s), in
2702
+ * place. THE single helper every external write mouth goes through — see the
2703
+ * module header; the three tripwires enforce the "every".
2704
+ *
2705
+ * @param schema The registered object schema (`engine.registry.getObject(...)`
2706
+ * / the protocol's own registry view / `metadataService
2707
+ * .getObject(...)`). An unknown object (no schema) strips
2708
+ * nothing — the write itself would have been refused upstream
2709
+ * by the object-existence gate.
2710
+ * @param records A single record, an array of records, or anything a write
2711
+ * mouth hands back where a record could sit (`null`, a count, a
2712
+ * boolean): non-objects are skipped, arrays are walked.
2713
+ */
2714
+ declare function omitInternalFieldsFromWriteResponse(schema: unknown, records: unknown): void;
2715
+
2280
2716
  /**
2281
2717
  * Can this runtime actually roll back? — the ADR-0119 D4 gate, shared.
2282
2718
  *
@@ -2564,11 +3000,65 @@ declare function resolveFilterTokens<T>(filter: T, ctx?: FilterTokenResolutionCo
2564
3000
  * `current_user.organization_id`).
2565
3001
  *
2566
3002
  * Typed structurally, not as `ExecutionContext`, so both the parsed context
2567
- * (defaults applied) and the pre-parse `ExecutionContextInput` a caller holds
2568
- * mid-pipeline satisfy it. The three fields read here are optional in both.
3003
+ * (`ExecutionContextParsed`, defaults applied) and the pre-parse
3004
+ * `ExecutionContext` a caller holds mid-pipeline satisfy it. The three fields
3005
+ * read here are optional in both.
2569
3006
  */
2570
3007
  declare function filterTokenContextFrom(execCtx: ExecutionContextLike | undefined, now?: Date): FilterTokenResolutionContext;
2571
3008
 
3009
+ /**
3010
+ * [#4435] The 404 a single-record operation answers when the id names no row.
3011
+ *
3012
+ * Extracted so the READ and the two WRITE paths cannot disagree about it. They
3013
+ * did: `getData` answered `404 RECORD_NOT_FOUND` while `updateData` returned
3014
+ * `200 { record: null }` and `deleteData` returned `200 { success: true }` for
3015
+ * any string in the path — so a typo'd id, an already-deleted row and a real
3016
+ * deletion were indistinguishable, and a client PATCHing a concurrently deleted
3017
+ * record was told its write had landed.
3018
+ *
3019
+ * That is the same silent-no-op shape the v17 train removed everywhere else
3020
+ * this window (#4240/#4303/#4315 refuse missing fields, #4169 refuses unknown
3021
+ * params, #4190 stopped dropping filters) — a write that touched zero rows
3022
+ * reporting 200 is that shape one level up, on the verb where it costs the
3023
+ * most.
3024
+ *
3025
+ * [#5138] EXPORTED, for the same "cannot disagree about it" reason one layer
3026
+ * out. `@objectstack/runtime`'s `callData` is protocol-first with an ObjectQL
3027
+ * FALLBACK, and the fallback had reinvented this fact three incompatible ways
3028
+ * (`get` → `null`, `update` → a bare `Error` with no status ⇒ 500, `delete` →
3029
+ * no check at all ⇒ `200 { deleted: true }` for a row that never existed). It
3030
+ * now calls THIS function, so the two paths behind one `callData` answer a
3031
+ * missing id identically — which is the only reason a caller may stop caring
3032
+ * which of them served it. Re-spelling the envelope there would have been a
3033
+ * second not-found envelope; `RECORD_NOT_FOUND` (#5088) is the one this repo
3034
+ * has.
3035
+ *
3036
+ * ── [#7867] Why it lives in `@objectstack/core` and not where it was written ──
3037
+ *
3038
+ * Because the THIRD path that needed it could not reach the second one. An
3039
+ * action body's `ctx.api.object(name).update({ id, … })` traverses neither
3040
+ * `protocol.updateData` nor `callData`: it reaches `ObjectQL.update()`'s by-id
3041
+ * branch directly, which had no existence gate at all, so a ghost id was a
3042
+ * silent no-op that then died on whatever the pipeline complained about first
3043
+ * (a `HookConditionError` 400 on a hooked object, a required-field
3044
+ * `VALIDATION_FAILED` 400 on an unhooked one — the 400 class varied with the
3045
+ * object's declarations; the missing 404 was the constant).
3046
+ *
3047
+ * The gate for that path belongs in the engine, and `packages/objectql` cannot
3048
+ * import `@objectstack/metadata-protocol` where this function was written:
3049
+ * ADR-0076 D2's boundary ratchet (`core-boundary.ratchet.test.ts`) forbids the
3050
+ * whole `@objectstack/objectql/core` closure — `engine.ts` included — from
3051
+ * pulling that package in. So the choice was a FOURTH spelling of the envelope
3052
+ * or one home both layers already depend on. #5138's own sentence rules the
3053
+ * first out, so this is the second: the factory moved down to the lowest
3054
+ * package the three producers share, and `@objectstack/metadata-protocol`
3055
+ * re-exports it unchanged for every existing importer.
3056
+ *
3057
+ * This is the same move `engineCanRollBack` made for the same reason — a fact
3058
+ * two layers must agree on lives in the layer beneath both, not in a copy each.
3059
+ */
3060
+ declare function recordNotFoundError(object: string, id: string | number): Error;
3061
+
2572
3062
  /**
2573
3063
  * In-memory Map-backed cache fallback.
2574
3064
  *
@@ -2704,7 +3194,24 @@ declare function createMemoryI18n(): {
2704
3194
  * not a merge — so deleted items/keys stop resolving on the next sync.
2705
3195
  */
2706
3196
  replaceAuthoredTranslations(byLocale: Record<string, Record<string, unknown>>): void;
3197
+ /**
3198
+ * Report the locales this stack offers.
3199
+ *
3200
+ * [#7679] When the app declared `i18n.supportedLocales`, that declaration
3201
+ * IS the answer — in declared order, and including a declared locale no
3202
+ * bundle was ever loaded for (declared-but-unserved). Reporting the
3203
+ * declaration rather than an intersection is what gives a client the
3204
+ * signal that the locale it is being offered has nothing behind it yet;
3205
+ * quietly dropping it would leave the gap invisible on both sides. It is
3206
+ * also the only answer that does not depend on how much had loaded by the
3207
+ * time this was called.
3208
+ *
3209
+ * With nothing declared, the loaded set — the behaviour every app that
3210
+ * never opted in already has.
3211
+ */
2707
3212
  getLocales(): string[];
3213
+ /** @see II18nService.setSupportedLocales — [#7679] */
3214
+ setSupportedLocales(locales: readonly string[] | undefined): void;
2708
3215
  getDefaultLocale(): string;
2709
3216
  setDefaultLocale(locale: string): void;
2710
3217
  };
@@ -2715,6 +3222,13 @@ declare function createMemoryI18n(): {
2715
3222
  * Implements the IMetadataService contract with a simple Map-of-Maps store.
2716
3223
  * Used by ObjectKernel as an automatic fallback when no real metadata plugin
2717
3224
  * (e.g. MetadataPlugin with file-system persistence) is registered.
3225
+ *
3226
+ * [#7378] Carries the ruled register/read argument contract
3227
+ * (`../metadata-service-contract.ts` — the ruling is quoted there):
3228
+ * `register` refuses a `data.name` that disagrees with the `name` argument and
3229
+ * refuses a non-document `data` (rows 1/3), and every type store is keyed on
3230
+ * the CANONICAL type (row 2), so `register('objects', n, d)` and
3231
+ * `get('object', n)` address one store rather than two.
2718
3232
  */
2719
3233
  declare function createMemoryMetadata(): {
2720
3234
  __serviceInfo: {
@@ -2768,6 +3282,37 @@ declare function wireAuthoredTranslationSync(ctx: MinimalCtx): void;
2768
3282
  */
2769
3283
  declare const CORE_FALLBACK_FACTORIES: Record<string, () => Record<string, any>>;
2770
3284
 
3285
+ /**
3286
+ * The canonical spelling an `IMetadataService` type store is keyed on
3287
+ * (#7378 row 2). Folds a plural manifest spelling to the singular metadata
3288
+ * type name (`'objects'` → `'object'`, `'views'` → `'view'`, …) through the
3289
+ * platform's one plural↔singular map (`PLURAL_TO_SINGULAR`,
3290
+ * `@objectstack/spec/shared`); a name with no plural mapping — which includes
3291
+ * every canonical singular type — passes through unchanged.
3292
+ */
3293
+ declare function canonicalMetadataServiceType(type: string): string;
3294
+ /**
3295
+ * Enforce rows 1 and 3 of the #7378 ruling on a
3296
+ * `register(type, name, data)` payload — call it before the first store write,
3297
+ * so a refusal writes nothing anywhere.
3298
+ *
3299
+ * Refuses, with a locating `VALIDATION_ERROR` (status 400):
3300
+ *
3301
+ * - **a non-document `data`** (row 3): anything that is not a plain object —
3302
+ * primitives, `null`, arrays. The contract declares `data: unknown`, so
3303
+ * this is a runtime refusal, not a type error;
3304
+ * - **a `data.name` that disagrees with the `name` argument** (row 1), in
3305
+ * either direction. A document with NO `name` of its own is fine — the
3306
+ * argument is the key, and there is no disagreement to refuse.
3307
+ *
3308
+ * Deliberately NOT called by `registerInMemory`: that optional member is a
3309
+ * boot-time seeding primitive outside the ruled surface (the ruling names
3310
+ * `register`), and its callers hand it artefacts whose shape source control
3311
+ * owns. It shares the row-2 canonical fold — a store key is a store fact, not
3312
+ * a per-member choice — just not the refusals.
3313
+ */
3314
+ declare function assertMetadataRegisterContract(type: string, name: string, data: unknown): asserts data is Record<string, unknown>;
3315
+
2771
3316
  /**
2772
3317
  * Plugin Health Monitor
2773
3318
  *
@@ -2787,7 +3332,7 @@ declare class PluginHealthMonitor {
2787
3332
  /**
2788
3333
  * Register a plugin for health monitoring
2789
3334
  */
2790
- registerPlugin(pluginName: string, config: PluginHealthCheck): void;
3335
+ registerPlugin(pluginName: string, config: PluginHealthCheckParsed): void;
2791
3336
  /**
2792
3337
  * Start monitoring a plugin
2793
3338
  */
@@ -2862,7 +3407,7 @@ declare class PluginStateManager {
2862
3407
  /**
2863
3408
  * Save plugin state before reload
2864
3409
  */
2865
- saveState(pluginId: string, version: string, state: Record<string, any>, config: HotReloadConfig): Promise<string>;
3410
+ saveState(pluginId: string, version: string, state: Record<string, any>, config: HotReloadConfigParsed): Promise<string>;
2866
3411
  /**
2867
3412
  * Restore plugin state after reload
2868
3413
  */
@@ -2895,7 +3440,7 @@ declare class HotReloadManager {
2895
3440
  /**
2896
3441
  * Register a plugin for hot reload
2897
3442
  */
2898
- registerPlugin(pluginName: string, config: HotReloadConfig): void;
3443
+ registerPlugin(pluginName: string, config: HotReloadConfigParsed): void;
2899
3444
  /**
2900
3445
  * Start watching for changes (requires file system integration)
2901
3446
  */
@@ -3085,4 +3630,4 @@ declare class NamespaceResolver {
3085
3630
  private suggestAlternative;
3086
3631
  }
3087
3632
 
3088
- 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, type EngineWithTransaction, 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, 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, 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, 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, zonedDateStartToUtcMs };
3633
+ export { 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 AnonymousDenyInput, type ApiKeyPrincipal, 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, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, assembleExecutionContext, assembleExecutionContextOrGuest, assertInitServiceRequirements, assertMetadataRegisterContract, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, canonicalMetadataServiceType, collectInternalWriteResponseFields, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, hashMigrationPlan, isAudienceBindingSuggestionStatus, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, normalizeAuthGate, omitInternalFieldsFromWriteResponse, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readRunJournal, recordNotFoundError, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, runMigrationJournal, safeExit, shouldDenyAnonymous, signPayload, unknownAudienceBindingSuggestionStatusMessage, validateInitServiceContract, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, withoutOperationPrivateKeys, zonedDateStartToUtcMs };