@objectstack/core 17.3.0 → 17.4.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,7 +1,7 @@
1
1
  import { Logger, LifecycleEventName, IServiceRegistry, AudienceBindingSuggestionFilter, IObjectQLEngine } from '@objectstack/spec/contracts';
2
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 { LoggerConfig, MigrationOnCrashPolicy, MigrationJournalEvent } from '@objectstack/spec/system';
4
- import { CORE_PLUGIN_TYPES, 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';
4
+ import { PluginDefinition, CORE_PLUGIN_TYPES, PluginCapability, PluginPermissions as PluginPermissions$1, PluginPermissionSet, ResourceType, PermissionAction, PluginPermission, SandboxConfig, ExecutionContext, PluginHealthCheckParsed, PluginHealthStatus as PluginHealthStatus$1, PluginHealthReport, HotReloadConfigParsed, VersionConstraint, DependencyConflict, SemanticVersion, CompatibilityLevel } from '@objectstack/spec/kernel';
5
5
  import { ObjectLogger } from './logger.js';
6
6
  export { createLogger } from './logger.js';
7
7
  import * as QA from '@objectstack/spec/qa';
@@ -72,6 +72,27 @@ interface PluginLoadResult {
72
72
  interface PluginStartupResult {
73
73
  success: boolean;
74
74
  pluginName: string;
75
+ /**
76
+ * Elapsed milliseconds the plugin's `start()` took.
77
+ *
78
+ * Named for the member `packages/spec` declares for the same measure --
79
+ * `PluginStartupResultSchema.durationMs` in
80
+ * `packages/spec/src/kernel/startup-orchestrator.zod.ts` ("Time taken to
81
+ * start the plugin in milliseconds"), where the bare `duration` spelling is
82
+ * retired: a duration-shaped number carries its unit in its key name. Like
83
+ * `PluginLoadResult.loadTime` above, it is the same `Date.now() - startTime`
84
+ * computation under a name that does not lie.
85
+ */
86
+ durationMs?: number;
87
+ /**
88
+ * The same elapsed milliseconds as {@link PluginStartupResult.durationMs}.
89
+ *
90
+ * @deprecated Misnamed: this has never held an instant, so a reader who
91
+ * correctly takes `startTime` for one and writes `Date.now() - result.startTime`
92
+ * gets an age near the epoch instead of a wait. Read `durationMs` instead.
93
+ * Still populated so nothing has to change on this release (ADR-0087 L1 --
94
+ * the old shape keeps working while the fleet moves); slated for removal.
95
+ */
75
96
  startTime?: number;
76
97
  error?: Error;
77
98
  timedOut?: boolean;
@@ -152,6 +173,25 @@ declare class PluginLoader {
152
173
  getLoadedPlugins(): Map<string, PluginMetadata>;
153
174
  private toPluginMetadata;
154
175
  private validatePluginStructure;
176
+ /**
177
+ * Refuse a plugin object the DECLARED plugin contract refuses (#16049,
178
+ * maintainer ruling 2026-09-06: "the protocol is the baseline; the runtime
179
+ * aligns to it").
180
+ *
181
+ * The check itself — `PluginSchema.safeParse` for validation only, the
182
+ * eight keys it reaches, the `version` exclusion and the
183
+ * `PLUGIN_CONTRACT_VIOLATION` envelope — lives in `plugin-contract.ts`,
184
+ * because since #16721 it is ONE statement run by BOTH kernels:
185
+ * `LiteKernel.use()` calls it directly, and `ObjectKernel.use()` reaches
186
+ * it here, through `loadPlugin`. That module's comment is the authority on
187
+ * what is refused; this method adds nothing to it and subtracts nothing.
188
+ *
189
+ * What stays THIS loader's own, and is deliberately not shared: the
190
+ * structural checks one call up ({@link validatePluginStructure} —
191
+ * `name`, `init`, semver) and the version-compatibility check below.
192
+ * The convergence is on the schema, not on the loader.
193
+ */
194
+ private validatePluginContract;
155
195
  private checkVersionCompatibility;
156
196
  private isValidSemanticVersion;
157
197
  private verifyPluginSignature;
@@ -204,7 +244,12 @@ declare class ObjectKernel {
204
244
  private pluginLoader;
205
245
  private config;
206
246
  private startedPlugins;
207
- private pluginStartTimes;
247
+ /**
248
+ * Plugin name -> elapsed milliseconds that plugin's `start()` took. These
249
+ * are DURATIONS, never start instants; the old spelling `pluginStartTimes`
250
+ * said the opposite of what it held.
251
+ */
252
+ private pluginStartupDurations;
208
253
  private shutdownHandlers;
209
254
  /**
210
255
  * Name of the plugin whose init() is currently executing (Phase 1 is
@@ -244,6 +289,25 @@ declare class ObjectKernel {
244
289
  * Validate Critical System Requirements
245
290
  */
246
291
  private validateSystemRequirements;
292
+ /**
293
+ * Publish this boot's degraded-capabilities conclusion on
294
+ * {@link DEGRADED_CAPABILITIES_SERVICE} — the data half of the warning
295
+ * `validateSystemRequirements()` just logged (#16630).
296
+ *
297
+ * ⛔ Best-effort, and silent on failure BY DESIGN: this is a diagnostic
298
+ * readout, and a readout must never be able to fail a boot that the kernel
299
+ * has just decided is good enough to run. The one way `registerService`
300
+ * can throw here is a name collision, which the guard above already
301
+ * forecloses; the `catch` is there so that stays true if either ever
302
+ * changes. (`recordSeedOutcome` in `@objectstack/runtime` states the same
303
+ * rule for the same reason.)
304
+ *
305
+ * The value is FROZEN and holds a COPY. `getService` hands out the stored
306
+ * reference, so an unfrozen live array would let any reader edit the
307
+ * kernel's own record of what was missing — and this record exists
308
+ * precisely so that two packages cannot disagree about it.
309
+ */
310
+ private publishDegradedCapabilities;
247
311
  /**
248
312
  * Bootstrap the kernel with enhanced features
249
313
  */
@@ -260,8 +324,18 @@ declare class ObjectKernel {
260
324
  * Check health of all plugins
261
325
  */
262
326
  checkAllPluginsHealth(): Promise<Map<string, any>>;
327
+ /**
328
+ * Per-plugin startup durations: plugin name -> elapsed milliseconds that
329
+ * plugin's `start()` took. Not start instants -- see
330
+ * {@link PluginStartupResult.durationMs}.
331
+ */
332
+ getPluginStartupDurations(): Map<string, number>;
263
333
  /**
264
334
  * Get plugin startup metrics
335
+ *
336
+ * @deprecated Renamed to {@link ObjectKernel.getPluginStartupDurations},
337
+ * which states what the values are. Retained as a delegating alias so
338
+ * nothing has to change on this release; slated for removal.
265
339
  */
266
340
  getPluginMetrics(): Map<string, number>;
267
341
  /**
@@ -474,24 +548,55 @@ type PluginType = 'standard' | (typeof CORE_PLUGIN_TYPES)[number];
474
548
  * Plugin Interface
475
549
  *
476
550
  * All ObjectStack plugins must implement this interface.
477
- */
478
- interface Plugin {
551
+ *
552
+ * ## Two halves, one contract (#16334)
553
+ *
554
+ * **The metadata half is inherited, not restated.** Every key `PluginSchema`
555
+ * declares (`@objectstack/spec`, `kernel/plugin.zod.ts`) — `id`, `type`,
556
+ * `staticPath`, `slug`, `default`, `version`, `description`, `author`,
557
+ * `homepage` — arrives here through `PluginDefinition`
558
+ * (`z.input<typeof PluginSchema>`), so the keys the compiler accepts on a
559
+ * plugin object and the keys `kernel.use()` validates
560
+ * (`PluginLoader.validatePluginContract`, #16049) are ONE declaration. Before
561
+ * this the interface spelled `type` and `version` itself and declared neither
562
+ * `staticPath` nor `slug`, so an in-repo `ui` plugin could not carry the two
563
+ * keys the schema requires of it without widening its own type — two shapes
564
+ * for one contract, free to drift.
565
+ *
566
+ * **The runtime half is declared here and only here**: `name`, the ADR-0116
567
+ * ordering declarations, and the `init` / `start` / `destroy` lifecycle. The
568
+ * spec's schema describes what a plugin OBJECT may say about itself, never
569
+ * what it does.
570
+ *
571
+ * ### `type`
572
+ *
573
+ * The inherited `type` is a {@link PluginType} — the closed set the spec
574
+ * declares (`'standard'` plus `CORE_PLUGIN_TYPES`); `packages/rest`'s
575
+ * `plugin-type-closed-set.pin.test.ts` pins that the inherited key and the
576
+ * exported alias are the same union. Absent means `'standard'` at the schema
577
+ * (`.default('standard')`), and the loader never writes that default back
578
+ * onto the object. A value outside the set no longer type-checks, and since
579
+ * #16049 `kernel.use()` REFUSES it at boot — `assertPluginContract`
580
+ * (`plugin-contract.ts`, run by BOTH `ObjectKernel.use()` and `LiteKernel.use()`
581
+ * since #16721) runs `PluginSchema` over every plugin object and raises
582
+ * `PLUGIN_CONTRACT_VIOLATION` naming the plugin and the first violated key.
583
+ * `type: 'ui'` additionally owes `staticPath` and `slug` (#16334,
584
+ * `PLUGIN_UI_REQUIRED_KEY_MISSING`), refused on the same path.
585
+ *
586
+ * ⚠️ This comment used to say a bad `type` was refused "at parse". It was
587
+ * measured false (#16049, from #15638): `PluginSchema` had no runtime caller,
588
+ * kernel plugin objects were never parsed, and a `type` outside the set was
589
+ * accepted and stored verbatim. The refusal described here is the one that
590
+ * now exists, on the boot path, and the compiler's arm is the second half
591
+ * rather than the only one — `kernel.use(plugin as any)` is a shipped
592
+ * in-repo pattern, and externally authored plugins never meet this compiler
593
+ * at all.
594
+ */
595
+ interface Plugin extends PluginDefinition {
479
596
  /**
480
597
  * Unique plugin name (e.g., 'com.objectstack.engine.objectql')
481
598
  */
482
599
  name: string;
483
- /**
484
- * Plugin version
485
- */
486
- version?: string;
487
- /**
488
- * Plugin type categorisation for runtime behaviour — a {@link PluginType},
489
- * the closed set the spec declares. The enumeration lives on that type
490
- * (derived from `CORE_PLUGIN_TYPES`), not in this comment: a value outside
491
- * it no longer type-checks, and `PluginSchema.type` refuses it at parse.
492
- * @default 'standard'
493
- */
494
- type?: PluginType;
495
600
  /**
496
601
  * List of other plugin names that this plugin depends on.
497
602
  * The kernel ensures these plugins are initialized before this one.
@@ -864,6 +969,26 @@ declare class LiteKernel extends ObjectKernelBase {
864
969
  * Register a plugin
865
970
  * @param plugin - Plugin instance
866
971
  *
972
+ * A plugin object the DECLARED plugin contract refuses is refused here,
973
+ * with `PLUGIN_CONTRACT_VIOLATION` — the same check, the same envelope,
974
+ * that `ObjectKernel.use()` runs through `PluginLoader` (`plugin-contract.ts`
975
+ * is the one statement both kernels call; #16721, maintainer ruling
976
+ * 2026-09-08, option A under #9864's precedent that the kernels converge).
977
+ *
978
+ * This method used to write the object straight into the registry, so the
979
+ * same plugin was accepted by this kernel and refused by `ObjectKernel` —
980
+ * and `AGENTS.md` names THIS kernel for tests, so a plugin could be green
981
+ * in vitest and refused at production boot. Measured before converging
982
+ * (#16721 step 1): of 813 `LiteKernel.use()` calls reachable in this
983
+ * repository's suites, 807 were accepted by the schema unchanged and the
984
+ * six refusals came from three test-local fixture objects, none of them
985
+ * product code.
986
+ *
987
+ * Ordering, and why it is pinned: state first (`validateIdle`), then the
988
+ * contract, then registration — a refused plugin never reaches the
989
+ * registry, so it can neither be booted nor supersede an earlier
990
+ * registration under its name.
991
+ *
867
992
  * Duplicate names OVERWRITE, with one `warn` naming both versions — the
868
993
  * declared contract in `plugin-registration.ts`, applied identically by
869
994
  * `ObjectKernel.use()` (#9864, maintainer ruling 2026-08-19).
@@ -1755,96 +1880,6 @@ declare class PluginSandboxRuntime {
1755
1880
  shutdown(): void;
1756
1881
  }
1757
1882
 
1758
- /**
1759
- * Scan Target
1760
- */
1761
- interface ScanTarget {
1762
- pluginId: string;
1763
- version: string;
1764
- files?: string[];
1765
- dependencies?: Record<string, string>;
1766
- }
1767
- /**
1768
- * Security Issue
1769
- */
1770
- interface SecurityIssue {
1771
- id: string;
1772
- severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
1773
- category: 'vulnerability' | 'malware' | 'license' | 'code-quality' | 'configuration';
1774
- title: string;
1775
- description: string;
1776
- location?: {
1777
- file?: string;
1778
- line?: number;
1779
- column?: number;
1780
- };
1781
- remediation?: string;
1782
- cve?: string;
1783
- cvss?: number;
1784
- }
1785
- /**
1786
- * Plugin Security Scanner
1787
- *
1788
- * Scans plugins for security vulnerabilities, malware, and license issues
1789
- */
1790
- declare class PluginSecurityScanner {
1791
- private logger;
1792
- private vulnerabilityDb;
1793
- private scanResults;
1794
- private passThreshold;
1795
- constructor(logger: ObjectLogger, config?: {
1796
- passThreshold?: number;
1797
- });
1798
- /**
1799
- * Perform a comprehensive security scan on a plugin
1800
- */
1801
- scan(target: ScanTarget): Promise<KernelSecurityScanResult>;
1802
- /**
1803
- * Scan code for vulnerabilities
1804
- */
1805
- private scanCode;
1806
- /**
1807
- * Scan dependencies for known vulnerabilities
1808
- */
1809
- private scanDependencies;
1810
- /**
1811
- * Scan for malware patterns
1812
- */
1813
- private scanMalware;
1814
- /**
1815
- * Check license compliance
1816
- */
1817
- private scanLicenses;
1818
- /**
1819
- * Check configuration security
1820
- */
1821
- private scanConfiguration;
1822
- /**
1823
- * Calculate security score based on issues
1824
- */
1825
- private calculateSecurityScore;
1826
- /**
1827
- * Add a vulnerability to the database
1828
- */
1829
- addVulnerability(packageName: string, version: string, vulnerability: KernelSecurityVulnerability): void;
1830
- /**
1831
- * Get scan result from cache
1832
- */
1833
- getScanResult(pluginId: string, version: string): KernelSecurityScanResult | undefined;
1834
- /**
1835
- * Clear scan results cache
1836
- */
1837
- clearCache(): void;
1838
- /**
1839
- * Update vulnerability database from external source
1840
- */
1841
- updateVulnerabilityDatabase(): Promise<void>;
1842
- /**
1843
- * Shutdown security scanner
1844
- */
1845
- shutdown(): void;
1846
- }
1847
-
1848
1883
  /** Default visible prefix for generated keys (helps users identify a key). */
1849
1884
  declare const API_KEY_PREFIX = "osk_";
1850
1885
  /**
@@ -1888,6 +1923,21 @@ declare function isExpired(value: unknown, nowMs: number): boolean;
1888
1923
  /** The principal resolved from a valid `sys_api_key`. */
1889
1924
  interface ApiKeyPrincipal {
1890
1925
  userId: string;
1926
+ /**
1927
+ * [#15256 / 2A] The `sys_api_key` ROW id — a non-secret handle an operator
1928
+ * can look the credential up by. Carried so the posture-conditional refusal
1929
+ * log in `resolve-authz-context.ts` can name WHICH key was refused without
1930
+ * naming the credential.
1931
+ *
1932
+ * ⛔ Never the raw key and never its hash: the raw key is returned exactly
1933
+ * once by {@link generateApiKey} and only `sha256(raw)` is ever stored, and
1934
+ * neither may enter a log line (see this module's SECURITY header). The row
1935
+ * id is not derived from either.
1936
+ *
1937
+ * Optional because a row is only required to identify its owner; a store
1938
+ * that answers without an `id` still yields a usable principal.
1939
+ */
1940
+ keyId?: string;
1891
1941
  /**
1892
1942
  * The organization this key authenticates INTO — read from the row's
1893
1943
  * `active_organization_id` and adopted by `resolveAuthzContext` as the
@@ -1926,6 +1976,19 @@ type ApiKeyAdmission = {
1926
1976
  outcome: 'refused';
1927
1977
  reason: ApiKeyRefusalReason;
1928
1978
  message: string;
1979
+ /**
1980
+ * [#15256 / 2A] The refused key's `sys_api_key` row id — same non-secret
1981
+ * handle as {@link ApiKeyPrincipal.keyId}, carried on this arm too so the
1982
+ * refusal log can name the credential the operator must go look at. ⛔
1983
+ * Never the raw key or its hash. The WIRE answer is unchanged (a generic
1984
+ * `401 UNAUTHENTICATED`, no reason and no id), so nothing here reaches a
1985
+ * caller holding someone else's key.
1986
+ */
1987
+ keyId?: string;
1988
+ /** The owner this refused key authenticates as — for the same log line. */
1989
+ userId?: string;
1990
+ /** The organization the refusal is about, when the key names one. */
1991
+ organizationId?: string;
1929
1992
  };
1930
1993
  /**
1931
1994
  * The shape of the kernel's `tenancy` service this module reads a posture from.
@@ -2029,13 +2092,13 @@ declare function resolveApiKeyAdmission(ql: any, headers: any, nowMs?: number, t
2029
2092
  * ## Why a THROW, and not a field on the envelope
2030
2093
  *
2031
2094
  * The alternative was a discriminator field on `ResolvedAuthzContext` — the
2032
- * shape `authRefusal` already has. That was rejected on a MEASUREMENT, not a
2033
- * preference: `authRefusal` has existed since #8287 and, outside this module
2034
- * and its own unit test, has **zero** consumers anywhere in the repo. A
2035
- * diagnostic field on this envelope is demonstrably not read by any door. Every
2036
- * transport reads `userId` and `systemPermissions`; a new sibling field would
2037
- * have to be taught to eight separate call sites before it made a single door
2038
- * louder, and would answer the old quiet 403 at every site that was missed.
2095
+ * shape `authRefusal` had (#8287). That was rejected on a MEASUREMENT, not a
2096
+ * preference: from #8287 until #14273 removed it, `authRefusal` had **zero**
2097
+ * consumers anywhere in the repo outside this module and test assertions a
2098
+ * reading #14273 acted on by deleting the field. Every transport reads `userId`
2099
+ * and `systemPermissions`; a new sibling field would have to be taught to eight
2100
+ * separate call sites before it made a single door louder, and would answer
2101
+ * the old quiet 403 at every site that was missed.
2039
2102
  *
2040
2103
  * A field is quiet by default and must be deliberately made loud. A throw is
2041
2104
  * loud by default and must be deliberately silenced. On a security surface
@@ -2168,6 +2231,15 @@ declare function rethrowAuthzStoreUnavailable(err: unknown): undefined;
2168
2231
  /** The transport-agnostic authorization envelope produced from a request. */
2169
2232
  interface ResolvedAuthzContext {
2170
2233
  userId?: string;
2234
+ /**
2235
+ * The ACTIVE organization this request operates in.
2236
+ *
2237
+ * ⚠️ [#15409] For a session principal under a wall-enforcing posture this is
2238
+ * a VETTED value, never the stored `activeOrganizationId` as read: a claim
2239
+ * that is not in {@link accessible_org_ids} is dropped and the context
2240
+ * resolves with no active organization at all. Absent here is the fail-closed
2241
+ * state, not a missing lookup — Layer 0 denies on it.
2242
+ */
2171
2243
  tenantId?: string;
2172
2244
  email?: string;
2173
2245
  accessToken?: string;
@@ -2197,24 +2269,6 @@ interface ResolvedAuthzContext {
2197
2269
  * anonymous requests carry no rung.
2198
2270
  */
2199
2271
  posture?: AuthzPosture;
2200
- /**
2201
- * [#8287] Set when an inbound API key was REFUSED — a real, intact
2202
- * credential this deployment's tenancy posture cannot admit. The context is
2203
- * otherwise EMPTY (no `userId`), so every transport already fails it closed
2204
- * to 401 with no change; this field only lets a transport that wants to say
2205
- * WHY do so, instead of answering the operator with a bare "unauthenticated"
2206
- * for a key they can see is neither revoked nor expired.
2207
- *
2208
- * ⚠️ `reason` is NOT an `error.code`. The wire vocabulary is closed
2209
- * (ADR-0112: `StandardErrorCode ∪ ERROR_CODE_LEDGER`, both in `packages/spec`)
2210
- * and a refused credential's standard member is `UNAUTHENTICATED`. This is a
2211
- * diagnostic discriminator for the message, deliberately lowercase so it can
2212
- * never be mistaken for one.
2213
- */
2214
- authRefusal?: {
2215
- reason: ApiKeyRefusalReason;
2216
- message: string;
2217
- };
2218
2272
  }
2219
2273
  interface ResolveAuthzInput {
2220
2274
  /** Data engine (ObjectQL) exposing `find(object, { where, limit, context })`. */
@@ -4108,6 +4162,71 @@ declare function runMigrationJournal(engine: IObjectQLEngine, plan: MigrationPla
4108
4162
  /** Resume a run the journal says was interrupted. Thin alias for intent at call sites. */
4109
4163
  declare function resumeMigrationJournal(engine: IObjectQLEngine, plan: MigrationPlan, runId: string, options?: Omit<RunMigrationJournalOptions, 'runId'>): Promise<MigrationRunResult>;
4110
4164
 
4165
+ /** Example row references a group carries, so the summary can point at real rows. */
4166
+ declare const ADVISORY_SAMPLE_ROWS = 5;
4167
+ /** One advisory rule hit, as the evaluator reports it. */
4168
+ interface AdvisoryHit {
4169
+ /** Object the row belongs to. */
4170
+ object: string;
4171
+ /** The declared rule's `name`. */
4172
+ rule: string;
4173
+ /** The rule's declared severity — `'warning'` or `'info'`; never `'error'`. */
4174
+ severity: string;
4175
+ /** The rule's author-written message, in the caller's locale. */
4176
+ message: string;
4177
+ /**
4178
+ * A reference to the row, when the write carries one.
4179
+ *
4180
+ * NOT necessarily an id: on the path this exists for — a seed INSERT — the
4181
+ * driver has not issued an id yet at validation time, so an id-only reference
4182
+ * would be empty for exactly the case the aggregation was built for. The
4183
+ * producer sends the best stable handle it has (`id`, else `name=<value>`,
4184
+ * the same way the seed loader names a row in its own errors).
4185
+ */
4186
+ recordRef?: string;
4187
+ }
4188
+ /** Every hit for one `(object, rule)` pair, folded. */
4189
+ interface AdvisoryGroup {
4190
+ object: string;
4191
+ rule: string;
4192
+ severity: string;
4193
+ /** The first message seen for this group (they differ only by interpolation). */
4194
+ message: string;
4195
+ /** How many ROWS tripped this rule during the scope. */
4196
+ rows: number;
4197
+ /** Up to {@link ADVISORY_SAMPLE_ROWS} example row references. */
4198
+ sampleRows: string[];
4199
+ }
4200
+ /**
4201
+ * Offer one advisory hit to the active aggregation scope.
4202
+ *
4203
+ * @returns `true` when a scope captured it — the caller must then NOT log its
4204
+ * own per-row line, because the scope owner reports the whole group. `false`
4205
+ * when no scope is active, which is the ordinary interactive case: the caller
4206
+ * logs exactly as it always did. A caller that ignores the return value
4207
+ * degrades to today's behaviour rather than losing the report.
4208
+ */
4209
+ declare function recordAdvisoryHit(hit: AdvisoryHit): boolean;
4210
+ /**
4211
+ * Whether an advisory aggregation scope is active on this async context.
4212
+ *
4213
+ * Exported for tests and for a caller that wants to skip building a message it
4214
+ * is about to discard; {@link recordAdvisoryHit}'s return value is the one that
4215
+ * decides.
4216
+ */
4217
+ declare function isAggregatingAdvisories(): boolean;
4218
+ /**
4219
+ * Run `fn` with advisory hits aggregated, then hand the folded groups to
4220
+ * `report`.
4221
+ *
4222
+ * `report` runs in a `finally`, so a load that throws still reports what it
4223
+ * tripped before failing — the diagnostics of a half-finished seed are the ones
4224
+ * most worth having. It is called only when there is something to report, and
4225
+ * its own failure is never allowed to replace the caller's outcome: a reporting
4226
+ * bug must not turn a successful seed load into a failed one.
4227
+ */
4228
+ declare function runWithAdvisoryAggregation<T>(fn: () => Promise<T>, report: (groups: AdvisoryGroup[]) => void): Promise<T>;
4229
+
4111
4230
  /**
4112
4231
  * The slice of an execution context the resolver reads. Structural on purpose —
4113
4232
  * see {@link filterTokenContextFrom}.
@@ -4633,6 +4752,19 @@ declare function createMemoryI18n(): {
4633
4752
  setSupportedLocales(locales: readonly string[] | undefined): void;
4634
4753
  getDefaultLocale(): string;
4635
4754
  setDefaultLocale(locale: string): void;
4755
+ /**
4756
+ * @see II18nService.setFallbackLocale — [#15694]
4757
+ *
4758
+ * ⛔ There is deliberately NO `getFallbackLocale()` beside this. The two
4759
+ * are different questions: this one is what the provider was TOLD, the
4760
+ * accessor is what the serving layer ASKS it in order to build the
4761
+ * metadata-document translators' fallback chain (#14882). Answering the
4762
+ * second from `defaultLocale` — the only value that was always available
4763
+ * here — would settle the default-locale contract question #14882 leaves
4764
+ * deliberately open, from a degraded provider. Without the accessor those
4765
+ * reads keep the resolvers' own default, which is known and intentional.
4766
+ */
4767
+ setFallbackLocale(locale: string): void;
4636
4768
  };
4637
4769
 
4638
4770
  /**
@@ -5133,4 +5265,4 @@ declare class NamespaceResolver {
5133
5265
  private suggestAlternative;
5134
5266
  }
5135
5267
 
5136
- export { ADMIN_STANDING_NON_TABLE_INPUTS, 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, AUTHZ_GRANTS_CACHE_TTL_ENV, AUTHZ_INVALIDATED_CHANNEL, AUTHZ_STORE_UNAVAILABLE_CODE, AUTHZ_STORE_UNAVAILABLE_MESSAGE, AUTHZ_STORE_UNAVAILABLE_STATUS, type ActivatableRow, type AdminStandingNonTableInput, type AdminStandingTable, type AnonymousDenyInput, type ApiKeyAdmission, type ApiKeyPrincipal, type ApiKeyRefusalReason, type ArtifactPackageError, type AudienceBindingSuggestionStatus, type AuthGate, type AuthzCachePosture, type AuthzCachePostureInput, type AuthzCachePostureStatement, type AuthzGrantsCacheTtlReading, type AuthzInvalidatedPayload, type AuthzInvalidationBusState, type AuthzInvalidationReason, type AuthzPostureSink, AuthzStoreUnavailableError, 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, InMemoryMetadataActivationStore, type IntegrityFile, type IntegrityViolation, type IntegrityViolationKind, type InterruptedRun, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, METADATA_ACTIVATION_TABLE, type MetadataActivationRow, type MetadataActivationStore, type MetadataActivationStoreEngine, 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, ObjectStoreMetadataActivationStore, type OrderablePlugin, PLATFORM_ADMIN_EMAIL_SEPARATOR, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type PlatformAdminConfigSink, type PlatformAdminEmailConfig, type Plugin, type PluginArtifactVerifyResult, 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 PluginType, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, type RunMigrationJournalOptions, SERVICE_NOT_REGISTERED_CODE, 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 VerifyIntegrityResult, type VersionCompatibility, type WallClockParts, adminStandingColumns, adminStandingTables, artifactPackageId, assembleExecutionContext, assembleExecutionContextOrGuest, assertInitServiceRequirements, assertMetadataRegisterContract, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, canonicalMetadataServiceType, collectInternalWriteResponseFields, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, effectiveTenancyPosture, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, formatIntegrityViolation, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hasPlatformAdminStanding, hashApiKey, hashMigrationPlan, isAudienceBindingSuggestionStatus, isAuthGateAllowlisted, isAuthzStoreUnavailableError, isConfiguredPlatformAdminEmail, isExpired, isGrantActive, isGrantExpired, isNode, isRowActive, isServiceNotRegisteredError, isUninterpretableTemporalComparand, matchesConfiguredPlatformAdmin, normalizeAuthGate, normalizePlatformAdminEmail, omitInternalFieldsFromWriteResponse, parsePlatformAdminEmails, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readAuthzGrantsCacheTtlMs, readRunJournal, recordNotFoundError, reportAuthzCachePosture, reportLegacyPlatformAdminGrant, resetLegacyPlatformAdminGrantReport, resetPlatformAdminEmailMemo, resolveApiKeyAdmission, resolveApiKeyPrincipal, resolveArtifactPackageOrder, resolveAuthzCachePosture, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePlatformAdminEmails, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, rethrowAuthzStoreUnavailable, runMigrationJournal, safeExit, setPlatformAdminConfigSink, shouldDenyAnonymous, signPayload, temporalComparandKind, unknownAudienceBindingSuggestionStatusMessage, validateInitServiceContract, verifyIntegrity, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, withoutOperationPrivateKeys, zonedDateStartToUtcMs, zonedWallClockToUtcMs };
5268
+ export { ADMIN_STANDING_NON_TABLE_INPUTS, ADMIN_STANDING_SURFACE, ADVISORY_SAMPLE_ROWS, ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, AUDIENCE_BINDING_SUGGESTION_STATUSES, AUDIENCE_BINDING_SUGGESTION_STATUS_VALUES, AUTHZ_GRANTS_CACHE_TTL_ENV, AUTHZ_INVALIDATED_CHANNEL, AUTHZ_STORE_UNAVAILABLE_CODE, AUTHZ_STORE_UNAVAILABLE_MESSAGE, AUTHZ_STORE_UNAVAILABLE_STATUS, type ActivatableRow, type AdminStandingNonTableInput, type AdminStandingTable, type AdvisoryGroup, type AdvisoryHit, type AnonymousDenyInput, type ApiKeyAdmission, type ApiKeyPrincipal, type ApiKeyRefusalReason, type ArtifactPackageError, type AudienceBindingSuggestionStatus, type AuthGate, type AuthzCachePosture, type AuthzCachePostureInput, type AuthzCachePostureStatement, type AuthzGrantsCacheTtlReading, type AuthzInvalidatedPayload, type AuthzInvalidationBusState, type AuthzInvalidationReason, type AuthzPostureSink, AuthzStoreUnavailableError, 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, InMemoryMetadataActivationStore, type IntegrityFile, type IntegrityViolation, type IntegrityViolationKind, type InterruptedRun, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, METADATA_ACTIVATION_TABLE, type MetadataActivationRow, type MetadataActivationStore, type MetadataActivationStoreEngine, 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, ObjectStoreMetadataActivationStore, type OrderablePlugin, PLATFORM_ADMIN_EMAIL_SEPARATOR, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type PlatformAdminConfigSink, type PlatformAdminEmailConfig, type Plugin, type PluginArtifactVerifyResult, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PluginType, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, type RunMigrationJournalOptions, SERVICE_NOT_REGISTERED_CODE, SIGNATURE_ALG, type SandboxContext, SecurePluginContext, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type TemporalComparandKind, type TenancyPostureSource, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VerifyIntegrityResult, type VersionCompatibility, type WallClockParts, adminStandingColumns, adminStandingTables, artifactPackageId, assembleExecutionContext, assembleExecutionContextOrGuest, assertInitServiceRequirements, assertMetadataRegisterContract, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, canonicalMetadataServiceType, collectInternalWriteResponseFields, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, effectiveTenancyPosture, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, formatIntegrityViolation, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hasPlatformAdminStanding, hashApiKey, hashMigrationPlan, isAggregatingAdvisories, isAudienceBindingSuggestionStatus, isAuthGateAllowlisted, isAuthzStoreUnavailableError, isConfiguredPlatformAdminEmail, isExpired, isGrantActive, isGrantExpired, isNode, isRowActive, isServiceNotRegisteredError, isUninterpretableTemporalComparand, matchesConfiguredPlatformAdmin, normalizeAuthGate, normalizePlatformAdminEmail, omitInternalFieldsFromWriteResponse, parsePlatformAdminEmails, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readAuthzGrantsCacheTtlMs, readRunJournal, recordAdvisoryHit, recordNotFoundError, reportAuthzCachePosture, reportLegacyPlatformAdminGrant, resetLegacyPlatformAdminGrantReport, resetPlatformAdminEmailMemo, resolveApiKeyAdmission, resolveApiKeyPrincipal, resolveArtifactPackageOrder, resolveAuthzCachePosture, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePlatformAdminEmails, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, rethrowAuthzStoreUnavailable, runMigrationJournal, runWithAdvisoryAggregation, safeExit, setPlatformAdminConfigSink, shouldDenyAnonymous, signPayload, temporalComparandKind, unknownAudienceBindingSuggestionStatusMessage, validateInitServiceContract, verifyIntegrity, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, withoutOperationPrivateKeys, zonedDateStartToUtcMs, zonedWallClockToUtcMs };