@omnicross/daemon 0.1.10 → 0.2.1
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/LICENSE +21 -21
- package/README.md +19 -19
- package/dist/cli.cjs +12242 -4667
- package/dist/cli.js +11372 -3629
- package/dist/index.cjs +8444 -1232
- package/dist/index.d.cts +1374 -20
- package/dist/index.d.ts +1374 -20
- package/dist/index.js +8524 -1157
- package/package.json +63 -63
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { Logger, OutboundApiServerConfig, ProviderConfigSource, TransformerService, Transformer, ResolvedTransformerChain, ApiServerSettingsStore, PricingStore, AutomaticPricingSource, OutboundPermission, OutboundKeyDb, OutboundKeyDbRow, OutboundKeyPolicy, PricingEngine as PricingEngine$1, OpenAIOperationRegistry } from '@omnicross/core';
|
|
2
|
+
import { SearchRuntime, SearchFrontendModes } from '@omnicross/core/search';
|
|
3
3
|
import { ApiKeyPoolService } from '@omnicross/core/completion/ApiKeyPoolService';
|
|
4
|
-
import { AllowanceSchedulingConfig, AccountProbeConfig, OutboundKeyDb as OutboundKeyDb$1, VoucherDb, KeySpendReader, OutboundApiServer } from '@omnicross/core/outbound-api';
|
|
4
|
+
import { AllowanceSchedulingConfig, AccountProbeConfig, OutboundKeyDb as OutboundKeyDb$1, VoucherDb, KeySpendReader, OutboundApiServer, ImagesServerConfig } from '@omnicross/core/outbound-api';
|
|
5
5
|
import { RouteLeaseManager, ProviderProxy } from '@omnicross/core/provider-proxy';
|
|
6
6
|
import { UsageRecorder, PricingEngine } from '@omnicross/core/usage';
|
|
7
|
-
import { SubscriptionCredentialStore, FetchLike,
|
|
7
|
+
import { SubscriptionCredentialStore, FetchLike, CodexImageCapabilityEvidenceSource, CodexImageCapabilityEvidenceRequest, CodexImageCapabilityEvidence, CodexImageCapabilityObservation, ImageExecutionScheduler, ImageExecutionAccountKey, ImageExecutionSchedulerRequest, ImageExecutionSchedulerGrant, SubscriptionAccountService, SubscriptionProviderRegistry } from '@omnicross/subscriptions';
|
|
8
8
|
import { AccountAllowanceSnapshot } from '@omnicross/contracts/account-allowance-types';
|
|
9
9
|
import { ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, AccountTokensConfig, ProxyConfig, SubscriptionAccountSanitized, AccountClientIdentity, SubscriptionAccountEntry } from '@omnicross/contracts/account-tokens-types';
|
|
10
10
|
import * as _omnicross_contracts_subscription_types from '@omnicross/contracts/subscription-types';
|
|
@@ -15,12 +15,17 @@ import { SubscriptionIdentityStore } from '@omnicross/core/provider-proxy/identi
|
|
|
15
15
|
import { LoggingConfig, HealthReport } from '@omnicross/contracts/health-logging-types';
|
|
16
16
|
import { SubscriptionAccountHealth } from '@omnicross/core/pipeline/SubscriptionAccountHealth';
|
|
17
17
|
import { fetchUpstream } from '@omnicross/core/pipeline/upstreamFetch';
|
|
18
|
+
import { UsageTotals, ModelUsageRow, ApiKeyUsageRow } from '@omnicross/contracts/usage-stats-types';
|
|
18
19
|
import { ThinkLevel } from '@omnicross/contracts/completion-types';
|
|
19
20
|
import { AuditRecord, AuditStats, AuditBodyResult, AuditConfig } from '@omnicross/contracts/audit-types';
|
|
20
21
|
import { BillingDeliveryStatus, BillingConfig, BillingEvent } from '@omnicross/contracts/billing-types';
|
|
21
22
|
import http from 'node:http';
|
|
23
|
+
import * as _omnicross_contracts_image_generation_types from '@omnicross/contracts/image-generation-types';
|
|
24
|
+
import { ImageCapabilityUnavailableReason, ImageCapabilities, ImageGenerationErrorCode, ImageReferenceMetadata, ImageReferenceId } from '@omnicross/contracts/image-generation-types';
|
|
25
|
+
import { ImageApiContributions, ResponsesImageGenerationContribution, ResponsesImageInspectionInput, ResponsesImageAdmission, ResponsesHostedToolSelection, ResponsesImageRequestScope, ImageTelemetrySink, ImageApiAuditRecord, ImageTelemetryRecord, ImageReferenceStore, ImageReferenceSaveInput, ImageReferenceResolution, ImageTemporaryResourceBudget, ImageTemporaryResourceBudgetLease, ImageApiLimits, ImageRequestResourceScope, ImageApiRuntimeResolver, RemoteImageAssetResolver, ImageProvider, ImageProviderRegistry, ImageOrchestrator } from '@omnicross/core/image-generation';
|
|
22
26
|
import { LLMProvider, AgentDefaultModels, GlobalModelParameters } from '@omnicross/contracts/llm-config';
|
|
23
27
|
import { PricingEntry, PricingEntryInput, PricingResolution, PricingSourceRefreshResult } from '@omnicross/contracts/pricing-types';
|
|
28
|
+
import { ResponsesImageStateStore, ResponsesImageStateCommitInput, ResponsesImageCallBinding, ResponsesImageCallId, ResponsesImageCallResolution, ResponsesImageResponseResolution } from '@omnicross/core/image-generation/responses';
|
|
24
29
|
import { WebhookConfig, WebhookEvent } from '@omnicross/contracts/webhook-types';
|
|
25
30
|
|
|
26
31
|
/**
|
|
@@ -86,6 +91,193 @@ declare class SecretBox {
|
|
|
86
91
|
encryptMaybe(value: string): string;
|
|
87
92
|
}
|
|
88
93
|
|
|
94
|
+
/**
|
|
95
|
+
* usageRollup — the immutable per-day aggregate that lets a range query skip a
|
|
96
|
+
* day's rows entirely.
|
|
97
|
+
*
|
|
98
|
+
* A rollup is computed ONCE, when a day is closed (strictly before today's local
|
|
99
|
+
* date), and is then never rewritten. It is deliberately kept FOREVER, outliving
|
|
100
|
+
* the raw shard it was built from, for one load-bearing reason:
|
|
101
|
+
* `getSpendByKey().totalUsd` is a LIFETIME number that seeds the outbound key
|
|
102
|
+
* spend policy (`core/outbound-api/keySpendTracker`). Pruning raw rows without
|
|
103
|
+
* keeping a per-key aggregate behind would silently reset every key's lifetime
|
|
104
|
+
* spend and quietly re-open budgets the operator had already spent.
|
|
105
|
+
*
|
|
106
|
+
* WHAT IS EXACT AND WHAT IS NOT
|
|
107
|
+
*
|
|
108
|
+
* Every count, token sum and cost in a rollup is exact — it is a plain sum of
|
|
109
|
+
* the same rows a raw scan would have visited. The ONE approximation is
|
|
110
|
+
* `medianCacheHitRate`: a median cannot be composed from per-day medians, so
|
|
111
|
+
* each day stores a 1000-bin histogram of its per-event hit rates instead. The
|
|
112
|
+
* median recovered from bins is off by at most half a bin — 0.0005, i.e. well
|
|
113
|
+
* under a twentieth of a percentage point. Storing the raw rates instead would
|
|
114
|
+
* make a "permanent" sidecar grow with traffic, which is the property this whole
|
|
115
|
+
* layout exists to avoid.
|
|
116
|
+
*
|
|
117
|
+
* STALENESS: a rollup records the byte size of the shard it was built from.
|
|
118
|
+
* Because a shard is append-only, a size change means rows were added after the
|
|
119
|
+
* rollup was computed (only reachable by inserting into a past day — the tests
|
|
120
|
+
* do it, production does not) and the rollup is recomputed. A shard that is GONE
|
|
121
|
+
* is the pruned case, where the rollup is the sole surviving authority.
|
|
122
|
+
*
|
|
123
|
+
* @module @omnicross/daemon/usage/usageRollup
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/** Everything in `UsageTotals` except the one field that cannot be summed. */
|
|
127
|
+
type SummableTotals = Omit<UsageTotals, 'medianCacheHitRate'>;
|
|
128
|
+
/** Per-model group inside a rollup. `unpriced` is deliberately absent — it is
|
|
129
|
+
* derived at query time from the injected pricing lookup, so a pricing change
|
|
130
|
+
* never requires rewriting an immutable rollup. */
|
|
131
|
+
type RollupModelRow = Omit<ModelUsageRow, 'unpriced'>;
|
|
132
|
+
/** Per-key group inside a rollup. `label` is absent for the same reason: it is
|
|
133
|
+
* resolved by the admin handler against the live key registry. */
|
|
134
|
+
type RollupApiKeyRow = Omit<ApiKeyUsageRow, 'label'>;
|
|
135
|
+
/** One hour of a day. Only hours that saw traffic are stored. */
|
|
136
|
+
interface RollupHourRow {
|
|
137
|
+
/** LOCAL hour of day, 0–23. */
|
|
138
|
+
hour: number;
|
|
139
|
+
requests: number;
|
|
140
|
+
inputTokens: number;
|
|
141
|
+
outputTokens: number;
|
|
142
|
+
cacheReadTokens: number;
|
|
143
|
+
cacheCreationTokens: number;
|
|
144
|
+
costUsd: number;
|
|
145
|
+
}
|
|
146
|
+
/** The on-disk `usage-YYYY-MM-DD.rollup.json` document. */
|
|
147
|
+
interface UsageDayRollup {
|
|
148
|
+
version: 1;
|
|
149
|
+
/** `YYYY-MM-DD`, LOCAL. Must match the file name. */
|
|
150
|
+
date: string;
|
|
151
|
+
/** Byte size of the shard this was built from; the staleness guard. */
|
|
152
|
+
sourceBytes: number;
|
|
153
|
+
totals: SummableTotals;
|
|
154
|
+
/** Sparse `binIndex -> count` over per-event cache-hit rates. */
|
|
155
|
+
hitRateBins: Record<string, number>;
|
|
156
|
+
byModel: RollupModelRow[];
|
|
157
|
+
byApiKey: RollupApiKeyRow[];
|
|
158
|
+
byHour: RollupHourRow[];
|
|
159
|
+
/** Distinct non-null session ids seen that day (drilldown index). */
|
|
160
|
+
sessionIds: string[];
|
|
161
|
+
/** True when `sessionIds` hit {@link SESSION_INDEX_LIMIT} and is incomplete. */
|
|
162
|
+
sessionIdsTruncated: boolean;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* usageRollupStore — read-or-build the per-day rollup sidecars.
|
|
167
|
+
*
|
|
168
|
+
* A rollup is built LAZILY, the first time a query needs a closed day, and then
|
|
169
|
+
* reused forever. Building it is the only time that day's rows are ever parsed
|
|
170
|
+
* again; every subsequent query for any range containing that day reads a few KB
|
|
171
|
+
* of JSON instead of megabytes of JSONL.
|
|
172
|
+
*
|
|
173
|
+
* STALENESS is checked against the shard's byte size, not its mtime. Shards are
|
|
174
|
+
* append-only, so a size that no longer matches what the rollup was built from
|
|
175
|
+
* means rows were added afterwards — only reachable by inserting an event with a
|
|
176
|
+
* past `ts`, which the store API permits and the tests exercise. A shard that is
|
|
177
|
+
* absent entirely is the PRUNED case: the rollup is then the sole surviving
|
|
178
|
+
* record of that day and is trusted unconditionally.
|
|
179
|
+
*
|
|
180
|
+
* Writes are atomic (temp file + rename) so a crash mid-write cannot leave a
|
|
181
|
+
* half-JSON sidecar that later reads as a corrupt day.
|
|
182
|
+
*
|
|
183
|
+
* @module @omnicross/daemon/usage/usageRollupStore
|
|
184
|
+
*/
|
|
185
|
+
|
|
186
|
+
declare class UsageRollupStore {
|
|
187
|
+
private readonly usageDir;
|
|
188
|
+
private readonly maxCached;
|
|
189
|
+
private readonly cache;
|
|
190
|
+
/** In-flight builds, so a burst of concurrent queries builds a day ONCE. */
|
|
191
|
+
private readonly inFlight;
|
|
192
|
+
constructor(usageDir: string, maxCached?: number);
|
|
193
|
+
/**
|
|
194
|
+
* The rollup for a CLOSED day, building it from the shard when absent or
|
|
195
|
+
* stale. `null` means the day has neither a usable rollup nor a shard — i.e.
|
|
196
|
+
* nothing was ever recorded for it.
|
|
197
|
+
*
|
|
198
|
+
* Callers must not ask for TODAY: today's rows are still arriving, so a rollup
|
|
199
|
+
* of them would be wrong the moment it was written.
|
|
200
|
+
*/
|
|
201
|
+
get(dayKey: string, hasShard?: boolean): Promise<UsageDayRollup | null>;
|
|
202
|
+
/** Forget a day — used when an insert lands in an already-rolled-up day. */
|
|
203
|
+
invalidate(dayKey?: string): void;
|
|
204
|
+
/**
|
|
205
|
+
* Build (or rebuild) a day's rollup from its shard and persist it. Exposed for
|
|
206
|
+
* the prune sweeper, which must guarantee a rollup exists BEFORE it deletes
|
|
207
|
+
* the rows that rollup is derived from.
|
|
208
|
+
*/
|
|
209
|
+
ensure(dayKey: string): Promise<UsageDayRollup | null>;
|
|
210
|
+
private resolve;
|
|
211
|
+
private readSidecar;
|
|
212
|
+
private writeSidecar;
|
|
213
|
+
private remember;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* UsagePruneSweeper — retention for the sharded usage store.
|
|
218
|
+
*
|
|
219
|
+
* Prunes RAW day shards past `retentionDays` and NEVER touches a rollup. That
|
|
220
|
+
* asymmetry is the whole design: aggregates (totals, per-model, per-key, hourly
|
|
221
|
+
* trend) stay complete for the lifetime of the install, while the per-row detail
|
|
222
|
+
* that costs 5 MB a day is bounded. In particular `getSpendByKey().totalUsd` —
|
|
223
|
+
* the LIFETIME figure seeding the outbound key spend policy — keeps summing
|
|
224
|
+
* correctly across pruned days, which a naive "delete old rows" would silently
|
|
225
|
+
* zero, reopening budgets the operator had already spent.
|
|
226
|
+
*
|
|
227
|
+
* ORDERING IS LOAD-BEARING: a shard is only ever deleted AFTER its rollup exists
|
|
228
|
+
* on disk. If the rollup cannot be built, the shard is kept and the day is
|
|
229
|
+
* retried on the next tick. Deleting rows whose aggregate was never computed
|
|
230
|
+
* would destroy that day permanently.
|
|
231
|
+
*
|
|
232
|
+
* Shaped like `audit/AuditPruneSweeper`: `start()` arms an `unref()`ed interval
|
|
233
|
+
* plus one immediate pass, `dispose()` clears it, a re-entrancy guard prevents
|
|
234
|
+
* overlap, and nothing throws — a failed sweep is logged and retried, never
|
|
235
|
+
* fatal to the daemon.
|
|
236
|
+
*
|
|
237
|
+
* @module @omnicross/daemon/usage/UsagePruneSweeper
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
/** The `usage` config segment. */
|
|
241
|
+
interface UsageRetentionConfig {
|
|
242
|
+
/** Days of RAW rows to keep. `0` or absent ⇒ keep everything. */
|
|
243
|
+
retentionDays?: number;
|
|
244
|
+
}
|
|
245
|
+
declare class UsagePruneSweeper {
|
|
246
|
+
private readonly usageDir;
|
|
247
|
+
private readonly rollups;
|
|
248
|
+
private readonly logger;
|
|
249
|
+
private config;
|
|
250
|
+
private readonly intervalMs;
|
|
251
|
+
/** Injectable clock (ms) for deterministic tests. */
|
|
252
|
+
private readonly now;
|
|
253
|
+
private timer;
|
|
254
|
+
private sweeping;
|
|
255
|
+
constructor(usageDir: string, rollups: UsageRollupStore, logger: Logger, config?: UsageRetentionConfig, intervalMs?: number,
|
|
256
|
+
/** Injectable clock (ms) for deterministic tests. */
|
|
257
|
+
now?: () => number);
|
|
258
|
+
/** Whether raw rows are pruned at all. */
|
|
259
|
+
get enabled(): boolean;
|
|
260
|
+
/** Re-apply config to the live instance (boot + admin PUT hot-reload). */
|
|
261
|
+
configure(config: UsageRetentionConfig): void;
|
|
262
|
+
/**
|
|
263
|
+
* Arm the interval AND run one pass immediately (boot cleanup). No-op when
|
|
264
|
+
* retention is off (keep-everything is the zero-regression default).
|
|
265
|
+
* Idempotent.
|
|
266
|
+
*/
|
|
267
|
+
start(): void;
|
|
268
|
+
/** Clear the interval (daemon shutdown / test teardown). Idempotent. */
|
|
269
|
+
dispose(): void;
|
|
270
|
+
/**
|
|
271
|
+
* One prune pass: for every day strictly OLDER than the retention cutoff that
|
|
272
|
+
* still has a shard, make sure its rollup exists and only then delete the
|
|
273
|
+
* shard. Exposed for tests; never throws. Returns the number of shards
|
|
274
|
+
* removed.
|
|
275
|
+
*/
|
|
276
|
+
sweep(): Promise<number>;
|
|
277
|
+
/** The LOCAL-midnight epoch ms of the current day. */
|
|
278
|
+
private todayMidnight;
|
|
279
|
+
}
|
|
280
|
+
|
|
89
281
|
/**
|
|
90
282
|
* config.ts — the daemon's `config.json` schema + load/save (design D9).
|
|
91
283
|
*
|
|
@@ -411,6 +603,12 @@ interface DaemonConfig {
|
|
|
411
603
|
* so it is never walked by `decryptConfigSecrets`/`encryptConfigSecrets`.
|
|
412
604
|
*/
|
|
413
605
|
logging?: LoggingConfig;
|
|
606
|
+
/**
|
|
607
|
+
* Optional usage-retention config. Absent ⇒ the default 90-day window on RAW
|
|
608
|
+
* usage rows. Per-day ROLLUPS are never pruned regardless — they carry the
|
|
609
|
+
* lifetime per-key spend the outbound key policy seeds from.
|
|
610
|
+
*/
|
|
611
|
+
usage?: UsageRetentionConfig;
|
|
414
612
|
}
|
|
415
613
|
/** Apply defaults to a (possibly absent) admin block: enabled, port 8766,
|
|
416
614
|
* loopback, no token. NOTE: an EXPLICIT `port: 0` is honored as "bind an
|
|
@@ -1545,6 +1743,254 @@ type AuditCompactor = () => {
|
|
|
1545
1743
|
/** The read surface the AdminServer consumes (bootstrap binds it to the ledger dir). */
|
|
1546
1744
|
type BillingStatusReader = () => BillingDeliveryStatus;
|
|
1547
1745
|
|
|
1746
|
+
type PreparedImageRuntimeGeneration = {
|
|
1747
|
+
readonly id: string;
|
|
1748
|
+
readonly enabled: true;
|
|
1749
|
+
readonly imageApi: ImageApiContributions;
|
|
1750
|
+
readonly hosted: ResponsesImageGenerationContribution;
|
|
1751
|
+
readonly hostedRuntime: HostedImageRuntimePolicy;
|
|
1752
|
+
readonly inspectCapability?: (apiKeyId: string) => Promise<Omit<ImageRuntimeCapabilityInspection, 'generationId'>>;
|
|
1753
|
+
readonly readRuntimeStatus?: () => ImageRuntimeResourceStatus;
|
|
1754
|
+
dispose(): void | Promise<void>;
|
|
1755
|
+
} | {
|
|
1756
|
+
readonly id: string;
|
|
1757
|
+
readonly enabled: false;
|
|
1758
|
+
dispose(): void | Promise<void>;
|
|
1759
|
+
};
|
|
1760
|
+
interface HostedImageRuntimeGenerationLease {
|
|
1761
|
+
readonly generationId: string;
|
|
1762
|
+
/** Compatibility/debug view; callers should prefer the deep methods below. */
|
|
1763
|
+
readonly contribution: ResponsesImageGenerationContribution;
|
|
1764
|
+
inspectRequest(input: ResponsesImageInspectionInput): ResponsesImageAdmission;
|
|
1765
|
+
validateSelection(admission: ResponsesImageAdmission, selection: ResponsesHostedToolSelection): void;
|
|
1766
|
+
openRequest(input: HostedImageOpenRequestInput): Promise<ResponsesImageRequestScope>;
|
|
1767
|
+
release(): Promise<void>;
|
|
1768
|
+
}
|
|
1769
|
+
interface HostedImageRuntimePolicy {
|
|
1770
|
+
readonly providerId: string;
|
|
1771
|
+
readonly imageModel: string;
|
|
1772
|
+
readonly referenceTtlMs: number;
|
|
1773
|
+
readonly maxOutputBytes: number;
|
|
1774
|
+
readonly maxTotalOutputBytes: number;
|
|
1775
|
+
readonly preferredAccountId?: string;
|
|
1776
|
+
readonly preferredAccountGroup?: string;
|
|
1777
|
+
readonly boundAccountFallbackPolicy?: 'strict' | 'pool';
|
|
1778
|
+
}
|
|
1779
|
+
interface HostedImageOpenRequestInput {
|
|
1780
|
+
readonly admission: ResponsesImageAdmission;
|
|
1781
|
+
readonly tenantId: string;
|
|
1782
|
+
readonly requestId: string;
|
|
1783
|
+
readonly sessionKey: string;
|
|
1784
|
+
readonly signal: AbortSignal;
|
|
1785
|
+
readonly authorizedPreviousResponseId?: string;
|
|
1786
|
+
/** Trusted affinity fact forwarded unchanged into the contribution scope. */
|
|
1787
|
+
readonly authorizedPreviousResponseKnownEmpty?: boolean;
|
|
1788
|
+
readonly mainProviderId: string;
|
|
1789
|
+
readonly selectedMainAccountId?: string;
|
|
1790
|
+
}
|
|
1791
|
+
/** Dormant integration seam for a later Native Responses owner. */
|
|
1792
|
+
interface HostedImageContributionFactory {
|
|
1793
|
+
acquire(): Promise<HostedImageRuntimeGenerationLease>;
|
|
1794
|
+
}
|
|
1795
|
+
/** Bind a stable factory to one app-session runtime manager without acquiring. */
|
|
1796
|
+
declare function createHostedImageContributionFactory(manager: ImageRuntimeManager): HostedImageContributionFactory;
|
|
1797
|
+
interface ImageRuntimeGenerationStatus {
|
|
1798
|
+
readonly generationId: string;
|
|
1799
|
+
readonly enabled: boolean;
|
|
1800
|
+
readonly httpLeases: number;
|
|
1801
|
+
readonly hostedLeases: number;
|
|
1802
|
+
}
|
|
1803
|
+
interface ImageRuntimeManagerStatus {
|
|
1804
|
+
readonly disposed: boolean;
|
|
1805
|
+
readonly current: ImageRuntimeGenerationStatus;
|
|
1806
|
+
readonly draining: readonly ImageRuntimeGenerationStatus[];
|
|
1807
|
+
}
|
|
1808
|
+
type ImageRuntimeSafeUnavailableReason = ImageCapabilityUnavailableReason | 'disabled' | 'runtime_unavailable';
|
|
1809
|
+
interface ImageRuntimeCapabilityInspection {
|
|
1810
|
+
readonly generationId: string;
|
|
1811
|
+
readonly enabled: boolean;
|
|
1812
|
+
readonly available: boolean;
|
|
1813
|
+
readonly providerId?: 'codex-subscription';
|
|
1814
|
+
readonly model?: string;
|
|
1815
|
+
readonly reason?: ImageRuntimeSafeUnavailableReason;
|
|
1816
|
+
readonly capabilities?: ImageCapabilities;
|
|
1817
|
+
}
|
|
1818
|
+
interface ImageRuntimeResourceStatus {
|
|
1819
|
+
readonly queue: Readonly<{
|
|
1820
|
+
activeJobs: number;
|
|
1821
|
+
waitingJobs: number;
|
|
1822
|
+
activeAccounts: number;
|
|
1823
|
+
waitingAccounts: number;
|
|
1824
|
+
waitingTenants: number;
|
|
1825
|
+
maxConcurrentJobsPerAccount: number;
|
|
1826
|
+
maxQueuedJobs: number;
|
|
1827
|
+
accepting: boolean;
|
|
1828
|
+
shuttingDown: boolean;
|
|
1829
|
+
}>;
|
|
1830
|
+
readonly temporary: Readonly<{
|
|
1831
|
+
activeScopes: number;
|
|
1832
|
+
totalBytes: number;
|
|
1833
|
+
tenantCount: number;
|
|
1834
|
+
maxActiveScopes: number;
|
|
1835
|
+
maxTotalBytes: number;
|
|
1836
|
+
maxTenantBytes: number;
|
|
1837
|
+
}>;
|
|
1838
|
+
readonly storage: Readonly<{
|
|
1839
|
+
mounts: number;
|
|
1840
|
+
retiredMounts: number;
|
|
1841
|
+
referenceEntries: number;
|
|
1842
|
+
referenceBytes: number;
|
|
1843
|
+
referenceTombstones: number;
|
|
1844
|
+
stateCalls: number;
|
|
1845
|
+
stateResponses: number;
|
|
1846
|
+
stateTombstones: number;
|
|
1847
|
+
pendingReferenceDeletes: number;
|
|
1848
|
+
maxReferenceEntries: number;
|
|
1849
|
+
maxReferenceBytes: number;
|
|
1850
|
+
maxTenantReferenceBytes: number;
|
|
1851
|
+
maxStateCalls: number;
|
|
1852
|
+
maxStateResponses: number;
|
|
1853
|
+
}>;
|
|
1854
|
+
}
|
|
1855
|
+
interface PreparedImageRuntimeChange {
|
|
1856
|
+
readonly generationId: string;
|
|
1857
|
+
publish(): void;
|
|
1858
|
+
rollback(): void;
|
|
1859
|
+
dispose(): Promise<void>;
|
|
1860
|
+
}
|
|
1861
|
+
/** App-session owner for stable forwarders and generation-pinned work. */
|
|
1862
|
+
declare class ImageRuntimeManager {
|
|
1863
|
+
#private;
|
|
1864
|
+
readonly contributions: ImageApiContributions;
|
|
1865
|
+
constructor(initial?: PreparedImageRuntimeGeneration);
|
|
1866
|
+
prepare(generation: PreparedImageRuntimeGeneration): PreparedImageRuntimeChange;
|
|
1867
|
+
acquireHosted(): Promise<HostedImageRuntimeGenerationLease>;
|
|
1868
|
+
inspectCapability(apiKeyId: string): Promise<ImageRuntimeCapabilityInspection>;
|
|
1869
|
+
listAvailableModels(apiKeyId: string): Promise<readonly string[]>;
|
|
1870
|
+
resourceStatus(): ImageRuntimeResourceStatus | undefined;
|
|
1871
|
+
status(): ImageRuntimeManagerStatus;
|
|
1872
|
+
dispose(): Promise<void>;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
type SafeProvider = 'codex-subscription' | 'unknown' | 'other';
|
|
1876
|
+
type SafeModel = 'gpt-image-2' | 'unknown' | 'other';
|
|
1877
|
+
type SafeErrorCode = ImageGenerationErrorCode | 'none' | 'other';
|
|
1878
|
+
type SafeCountOption = 'unknown' | '0' | '1' | '2-4' | '5+';
|
|
1879
|
+
type SafeBooleanOption = boolean | 'unknown';
|
|
1880
|
+
type SafeQuality = 'auto' | 'low' | 'medium' | 'high' | 'unknown' | 'other';
|
|
1881
|
+
type SafeBackground = 'auto' | 'opaque' | 'transparent' | 'unknown' | 'other';
|
|
1882
|
+
type SafeOutputFormat = 'png' | 'jpeg' | 'webp' | 'unknown' | 'other';
|
|
1883
|
+
declare const IMAGE_CONFIGURATION_AUDIT_FIELDS: readonly ["enablement", "provider", "model", "account", "queue", "temporary", "limits", "retention", "storage", "remote", "evidence"];
|
|
1884
|
+
type ImageConfigurationAuditField = typeof IMAGE_CONFIGURATION_AUDIT_FIELDS[number];
|
|
1885
|
+
/** Values are deliberately limited to safe categories and internal generation ids. */
|
|
1886
|
+
interface ImageConfigurationAuditRecord {
|
|
1887
|
+
readonly outcome: 'applied';
|
|
1888
|
+
readonly fields: readonly ImageConfigurationAuditField[];
|
|
1889
|
+
readonly previousGenerationId?: string;
|
|
1890
|
+
readonly generationId?: string;
|
|
1891
|
+
}
|
|
1892
|
+
interface ImageHistogramSnapshot {
|
|
1893
|
+
readonly count: number;
|
|
1894
|
+
readonly sum: number;
|
|
1895
|
+
/** Non-cumulative fixed buckets; `upperBound:null` is the overflow bucket. */
|
|
1896
|
+
readonly buckets: readonly {
|
|
1897
|
+
readonly upperBound: number | null;
|
|
1898
|
+
readonly count: number;
|
|
1899
|
+
}[];
|
|
1900
|
+
}
|
|
1901
|
+
interface ImageApiMetricDimensions {
|
|
1902
|
+
readonly endpoint: 'images.generate' | 'images.edit';
|
|
1903
|
+
readonly provider: SafeProvider;
|
|
1904
|
+
readonly model: SafeModel;
|
|
1905
|
+
readonly action: 'generate' | 'edit';
|
|
1906
|
+
readonly quality: SafeQuality;
|
|
1907
|
+
readonly background: SafeBackground;
|
|
1908
|
+
readonly outputFormat: SafeOutputFormat;
|
|
1909
|
+
readonly streaming: SafeBooleanOption;
|
|
1910
|
+
readonly requestedOutputs: SafeCountOption;
|
|
1911
|
+
readonly partialImages: SafeCountOption;
|
|
1912
|
+
readonly terminal: 'completed' | 'failed' | 'cancelled';
|
|
1913
|
+
readonly errorCode: SafeErrorCode;
|
|
1914
|
+
}
|
|
1915
|
+
interface ImageExecutionMetricDimensions {
|
|
1916
|
+
readonly provider: SafeProvider;
|
|
1917
|
+
readonly model: SafeModel;
|
|
1918
|
+
readonly action: 'generate' | 'edit' | 'other';
|
|
1919
|
+
readonly quality: SafeQuality;
|
|
1920
|
+
readonly background: SafeBackground;
|
|
1921
|
+
readonly outputFormat: SafeOutputFormat;
|
|
1922
|
+
readonly streaming: SafeBooleanOption;
|
|
1923
|
+
readonly requestedOutputs: SafeCountOption;
|
|
1924
|
+
readonly terminal: 'completed' | 'failed' | 'cancelled' | 'other';
|
|
1925
|
+
readonly errorCode: SafeErrorCode;
|
|
1926
|
+
}
|
|
1927
|
+
interface ImageApiMetricSnapshot {
|
|
1928
|
+
readonly dimensions: ImageApiMetricDimensions;
|
|
1929
|
+
readonly requests: number;
|
|
1930
|
+
readonly inputCount?: ImageHistogramSnapshot;
|
|
1931
|
+
readonly inputBytes?: ImageHistogramSnapshot;
|
|
1932
|
+
readonly referenceOutcomes: Readonly<{
|
|
1933
|
+
hits: number;
|
|
1934
|
+
notFound: number;
|
|
1935
|
+
expired: number;
|
|
1936
|
+
failed: number;
|
|
1937
|
+
}>;
|
|
1938
|
+
readonly cleanupOutcomes: Readonly<{
|
|
1939
|
+
completed: number;
|
|
1940
|
+
failed: number;
|
|
1941
|
+
}>;
|
|
1942
|
+
}
|
|
1943
|
+
interface ImageExecutionMetricSnapshot {
|
|
1944
|
+
readonly dimensions: ImageExecutionMetricDimensions;
|
|
1945
|
+
readonly executions: number;
|
|
1946
|
+
readonly finalLatencyMs: ImageHistogramSnapshot;
|
|
1947
|
+
readonly queueWaitMs?: ImageHistogramSnapshot;
|
|
1948
|
+
readonly generationDurationMs?: ImageHistogramSnapshot;
|
|
1949
|
+
readonly firstPartialLatencyMs?: ImageHistogramSnapshot;
|
|
1950
|
+
readonly inputCount: ImageHistogramSnapshot;
|
|
1951
|
+
readonly inputBytes: ImageHistogramSnapshot;
|
|
1952
|
+
readonly outputCount: ImageHistogramSnapshot;
|
|
1953
|
+
readonly outputBytes: ImageHistogramSnapshot;
|
|
1954
|
+
readonly retryCount?: ImageHistogramSnapshot;
|
|
1955
|
+
readonly authRefreshCount?: ImageHistogramSnapshot;
|
|
1956
|
+
readonly referenceSaveCount?: ImageHistogramSnapshot;
|
|
1957
|
+
readonly retentionRollbackFailures?: ImageHistogramSnapshot;
|
|
1958
|
+
}
|
|
1959
|
+
interface ImageObservabilitySnapshot {
|
|
1960
|
+
readonly apiRequests: readonly ImageApiMetricSnapshot[];
|
|
1961
|
+
readonly executions: readonly ImageExecutionMetricSnapshot[];
|
|
1962
|
+
readonly configurationChanges: readonly ImageConfigurationAuditRecord[];
|
|
1963
|
+
readonly overflow: Readonly<{
|
|
1964
|
+
apiRecords: number;
|
|
1965
|
+
telemetryRecords: number;
|
|
1966
|
+
}>;
|
|
1967
|
+
}
|
|
1968
|
+
interface ImageObservabilityOptions {
|
|
1969
|
+
/** Hard cap applied independently to API and execution dimension maps. */
|
|
1970
|
+
readonly maxDimensionSets?: number;
|
|
1971
|
+
}
|
|
1972
|
+
/** Process-local, metadata-only aggregation for HTTP and hosted Images work. */
|
|
1973
|
+
declare class ImageObservability {
|
|
1974
|
+
#private;
|
|
1975
|
+
readonly telemetrySink: ImageTelemetrySink;
|
|
1976
|
+
readonly audit: (record: ImageApiAuditRecord) => void;
|
|
1977
|
+
constructor(options?: ImageObservabilityOptions);
|
|
1978
|
+
recordApiAudit(record: ImageApiAuditRecord): void;
|
|
1979
|
+
recordTelemetry(record: ImageTelemetryRecord): void;
|
|
1980
|
+
recordConfigurationAudit(record: ImageConfigurationAuditRecord): void;
|
|
1981
|
+
snapshot(): ImageObservabilitySnapshot;
|
|
1982
|
+
reset(): void;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
interface PreparedServerConfigChange {
|
|
1986
|
+
/** Publish the prepared snapshot. Implementations should make this an infallible swap. */
|
|
1987
|
+
publish(): void | Promise<void>;
|
|
1988
|
+
/** Restore the exact runtime snapshot that preceded publish. */
|
|
1989
|
+
rollback(): void | Promise<void>;
|
|
1990
|
+
/** Release an unpublished or rolled-back replacement. */
|
|
1991
|
+
dispose(): void | Promise<void>;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1548
1994
|
/**
|
|
1549
1995
|
* autoDisableStore.ts — the daemon's PROCESS-IN-MEMORY auto-disable store.
|
|
1550
1996
|
*
|
|
@@ -1684,9 +2130,16 @@ declare class ConfigFileProviderConfigSource implements ProviderConfigSource {
|
|
|
1684
2130
|
* @module @omnicross/daemon/ports/JsonApiServerSettingsStore
|
|
1685
2131
|
*/
|
|
1686
2132
|
|
|
2133
|
+
interface JsonSettingsDocumentSnapshot {
|
|
2134
|
+
readonly existed: boolean;
|
|
2135
|
+
/** Raw persisted bytes; may contain encrypted secrets and must never enter a DTO or log. */
|
|
2136
|
+
readonly bytes?: Uint8Array;
|
|
2137
|
+
}
|
|
2138
|
+
type AtomicDocumentReplace = (targetPath: string, contents: Uint8Array) => void;
|
|
1687
2139
|
declare class JsonApiServerSettingsStore implements ApiServerSettingsStore {
|
|
1688
2140
|
private readonly configPath;
|
|
1689
2141
|
private readonly box;
|
|
2142
|
+
private readonly atomicReplace;
|
|
1690
2143
|
/**
|
|
1691
2144
|
* @param configPath the daemon config.json whose `server` field is backed.
|
|
1692
2145
|
* @param box OPTIONAL at-rest `SecretBox` (upstream-proxy). When set, the
|
|
@@ -1695,9 +2148,13 @@ declare class JsonApiServerSettingsStore implements ApiServerSettingsStore {
|
|
|
1695
2148
|
* secret-aware — every OTHER server field is non-secret). Null
|
|
1696
2149
|
* ⇒ passthrough (legacy/pure tests unchanged).
|
|
1697
2150
|
*/
|
|
1698
|
-
constructor(configPath: string, box?: SecretBox | null);
|
|
2151
|
+
constructor(configPath: string, box?: SecretBox | null, atomicReplace?: AtomicDocumentReplace);
|
|
1699
2152
|
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
1700
2153
|
set<T = unknown>(key: string, value: T): Promise<void>;
|
|
2154
|
+
/** Capture the exact prior document for an admin transaction rollback. */
|
|
2155
|
+
captureDocumentSnapshot(): JsonSettingsDocumentSnapshot;
|
|
2156
|
+
/** Restore exact prior bytes (including unrelated fields and encrypted secrets). */
|
|
2157
|
+
restoreDocumentSnapshot(snapshot: JsonSettingsDocumentSnapshot): void;
|
|
1701
2158
|
/** Encrypt the proxy passwords + webhook + billing secrets before persisting (no-op without a box). */
|
|
1702
2159
|
private encryptSecrets;
|
|
1703
2160
|
/** Decrypt the proxy passwords + webhook + billing secrets on read (no-op without a box). */
|
|
@@ -1779,7 +2236,31 @@ declare class JsonPricingStore implements PricingStore {
|
|
|
1779
2236
|
private replaceFile;
|
|
1780
2237
|
}
|
|
1781
2238
|
|
|
2239
|
+
interface CodexAuthHelperConfig {
|
|
2240
|
+
command: string;
|
|
2241
|
+
args: string[];
|
|
2242
|
+
}
|
|
2243
|
+
|
|
1782
2244
|
type IntegrationClientId = 'codex' | 'claude';
|
|
2245
|
+
type IntegrationKeyOwnership = 'managed' | 'selected';
|
|
2246
|
+
/** Secret-free pointer to an access key. The plaintext remains in the encrypted key store. */
|
|
2247
|
+
interface IntegrationKeyBinding {
|
|
2248
|
+
keyId: string;
|
|
2249
|
+
ownership: IntegrationKeyOwnership;
|
|
2250
|
+
}
|
|
2251
|
+
/** Redacted access-key state exposed by the integrations admin API. */
|
|
2252
|
+
interface IntegrationKeyBindingStatus {
|
|
2253
|
+
id: string;
|
|
2254
|
+
name: string;
|
|
2255
|
+
keyPrefix: string;
|
|
2256
|
+
ownership: IntegrationKeyOwnership;
|
|
2257
|
+
revealable: boolean;
|
|
2258
|
+
enabled: boolean;
|
|
2259
|
+
revoked: boolean;
|
|
2260
|
+
allowedEndpoints: OutboundPermission[];
|
|
2261
|
+
requiredEndpoints: OutboundPermission[];
|
|
2262
|
+
loopbackOnly: boolean;
|
|
2263
|
+
}
|
|
1783
2264
|
type IntegrationStatusKind = 'not-installed' | 'enabled' | 'configuration-drift' | 'configuration-missing' | 'key-missing';
|
|
1784
2265
|
interface IntegrationClientStatus {
|
|
1785
2266
|
client: IntegrationClientId;
|
|
@@ -1788,6 +2269,8 @@ interface IntegrationClientStatus {
|
|
|
1788
2269
|
installedAt?: number;
|
|
1789
2270
|
gatewayBaseUrl?: string;
|
|
1790
2271
|
message?: string;
|
|
2272
|
+
/** Selected key metadata only; never contains plaintext or the encrypted envelope. */
|
|
2273
|
+
key?: IntegrationKeyBindingStatus;
|
|
1791
2274
|
}
|
|
1792
2275
|
interface IntegrationChangePlan {
|
|
1793
2276
|
client: IntegrationClientId;
|
|
@@ -1827,7 +2310,9 @@ interface IntegrationGatewayKeyRecord {
|
|
|
1827
2310
|
}
|
|
1828
2311
|
interface IntegrationState {
|
|
1829
2312
|
version: 1;
|
|
2313
|
+
/** Legacy shared-key layout. New installs use `keyBindings`; retained for safe migration. */
|
|
1830
2314
|
gatewayKey?: IntegrationGatewayKeyRecord;
|
|
2315
|
+
keyBindings?: Partial<Record<IntegrationClientId, IntegrationKeyBinding>>;
|
|
1831
2316
|
clients: Partial<Record<IntegrationClientId, IntegrationInstallRecord>>;
|
|
1832
2317
|
}
|
|
1833
2318
|
|
|
@@ -1845,27 +2330,38 @@ interface IntegrationManagerOptions {
|
|
|
1845
2330
|
gatewayBaseUrl: string;
|
|
1846
2331
|
keyDb: OutboundKeyDb;
|
|
1847
2332
|
stateStore: IntegrationStateStore;
|
|
2333
|
+
codexAuthHelper?: CodexAuthHelperConfig;
|
|
1848
2334
|
homeDir?: string;
|
|
1849
2335
|
}
|
|
1850
|
-
/** Coordinates
|
|
2336
|
+
/** Coordinates per-client least-privilege keys with reversible native CLI config edits. */
|
|
1851
2337
|
declare class IntegrationManager {
|
|
1852
2338
|
private readonly options;
|
|
1853
2339
|
private readonly homeDir;
|
|
2340
|
+
private readonly codexAuthHelper;
|
|
1854
2341
|
constructor(options: IntegrationManagerOptions);
|
|
1855
2342
|
listStatus(): Promise<IntegrationClientStatus[]>;
|
|
1856
2343
|
plan(client: IntegrationClientId, configPath?: string): Promise<IntegrationChangePlan>;
|
|
1857
2344
|
install(client: IntegrationClientId, configPath?: string): Promise<IntegrationClientStatus>;
|
|
1858
2345
|
repair(client: IntegrationClientId): Promise<IntegrationClientStatus>;
|
|
1859
2346
|
remove(client: IntegrationClientId): Promise<IntegrationClientStatus>;
|
|
2347
|
+
/** Bind a user-confirmed access key and grant only this client's required endpoints. */
|
|
2348
|
+
bindIntegrationKey(client: IntegrationClientId, keyId: string): Promise<IntegrationClientStatus>;
|
|
2349
|
+
/** Rotate every Omnicross-managed client binding; user-selected keys remain untouched. */
|
|
1860
2350
|
rotateGatewayKey(): Promise<{
|
|
1861
|
-
|
|
2351
|
+
keyIds: Partial<Record<IntegrationClientId, string>>;
|
|
1862
2352
|
}>;
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
2353
|
+
/** Resolve the plaintext only for the command-auth helper; callers must not log it. */
|
|
2354
|
+
getIntegrationToken(client: IntegrationClientId): Promise<string>;
|
|
2355
|
+
/** Compatibility alias for callers predating per-client bindings. */
|
|
2356
|
+
getGatewayToken(client?: IntegrationClientId): Promise<string>;
|
|
2357
|
+
private ensureClientKey;
|
|
2358
|
+
private createManagedClientKey;
|
|
2359
|
+
private installedSecret;
|
|
2360
|
+
private rebindInstalledClient;
|
|
1866
2361
|
private statusFor;
|
|
2362
|
+
private boundKeyDetails;
|
|
2363
|
+
private retireManagedKeys;
|
|
1867
2364
|
private defaultConfigPath;
|
|
1868
|
-
private codexAuthPathForConfig;
|
|
1869
2365
|
private renderInstalled;
|
|
1870
2366
|
}
|
|
1871
2367
|
|
|
@@ -1911,6 +2407,60 @@ type CommandRunner = (command: string) => Promise<{
|
|
|
1911
2407
|
error?: string;
|
|
1912
2408
|
}>;
|
|
1913
2409
|
|
|
2410
|
+
/**
|
|
2411
|
+
* searchAdminApi — the admin API's search surface (search-settings-ui D3 +
|
|
2412
|
+
* search-settings-tab D4).
|
|
2413
|
+
*
|
|
2414
|
+
* Three routes over the daemon's search state, dispatched from `adminApi.ts`'s
|
|
2415
|
+
* `case 'search'`:
|
|
2416
|
+
*
|
|
2417
|
+
* - `GET /admin/api/search/diagnostics` — a READ-ONLY, secret-free, network-free
|
|
2418
|
+
* snapshot: one row per provider the daemon can run (the ONE runtime's
|
|
2419
|
+
* descriptors, plus `unconfigured` rows for known API providers the persisted
|
|
2420
|
+
* config does not name — the doctor's classification), the effective frontend
|
|
2421
|
+
* modes, and the explicit apply semantics (codex immediate, rest restart).
|
|
2422
|
+
* - `POST /admin/api/search/test { providerId }` — ONE live fixed-query check on
|
|
2423
|
+
* a configured provider, classified by the doctor's pure functions. The
|
|
2424
|
+
* machine-facing health probe: it sends exactly `SEARCH_DOCTOR_QUERY`, never a
|
|
2425
|
+
* caller-supplied query, and never returns result content (plan §11.3 — its
|
|
2426
|
+
* contract is the automated doctor's fixed-query discipline).
|
|
2427
|
+
* - `POST /admin/api/search/query { providerId, query }` — the INTERACTIVE
|
|
2428
|
+
* channel for the settings page's per-provider test panel (owner feedback
|
|
2429
|
+
* 2026-09-02): ONE operator-typed query through ONE provider's contribution
|
|
2430
|
+
* built from the PERSISTED config, returning the doctor-classified diagnostic
|
|
2431
|
+
* PLUS the sanitized results. The two disciplines stay separate routes on
|
|
2432
|
+
* purpose: bending `/test` to accept a query would erase the boundary its
|
|
2433
|
+
* pinned tests and consumers depend on.
|
|
2434
|
+
*
|
|
2435
|
+
* SECRET SPINE (all three routes): no response ever carries a configured VALUE,
|
|
2436
|
+
* and a failure response carries only the doctor's SANITIZED error shape — raw
|
|
2437
|
+
* upstream error bodies (which may quote the stored key) never serialize. The
|
|
2438
|
+
* query endpoint additionally sanitizes every returned result field BEFORE
|
|
2439
|
+
* serialization (plan §11.1: search results are untrusted input), and the
|
|
2440
|
+
* operator's query is never logged anywhere.
|
|
2441
|
+
*
|
|
2442
|
+
* The diagnostics dep is OPTIONAL (`AdminApiDeps.searchStatus`): light embedders
|
|
2443
|
+
* that wire no search runtime get 501 for all routes (the voucher/allowance
|
|
2444
|
+
* optionality precedent) rather than a fabricated snapshot.
|
|
2445
|
+
*
|
|
2446
|
+
* @module @omnicross/daemon/admin/searchAdminApi
|
|
2447
|
+
*/
|
|
2448
|
+
|
|
2449
|
+
/**
|
|
2450
|
+
* The daemon search state the admin surface needs. Structurally satisfied by
|
|
2451
|
+
* what `bootstrap.ts` already holds (the ONE runtime + its captured modes);
|
|
2452
|
+
* `testFetch` is a TEST SEAM so route tests can intercept the one live probe
|
|
2453
|
+
* without any network.
|
|
2454
|
+
*/
|
|
2455
|
+
interface SearchAdminRuntimeStatus {
|
|
2456
|
+
/** The daemon's ONE assembled search runtime (provider descriptors). */
|
|
2457
|
+
readonly runtime: SearchRuntime;
|
|
2458
|
+
/** Modes as captured at bootstrap (responses/anthropic are these, live). */
|
|
2459
|
+
readonly modes: SearchFrontendModes;
|
|
2460
|
+
/** TEST SEAM: fetch primitive for the live-test probe. Absent ⇒ real transport. */
|
|
2461
|
+
readonly testFetch?: (url: string, init: RequestInit) => Promise<Response>;
|
|
2462
|
+
}
|
|
2463
|
+
|
|
1914
2464
|
/**
|
|
1915
2465
|
* migration.ts — the export gather + import apply logic for the passphrase pack
|
|
1916
2466
|
* (app-parity child 6, design D2/D3/D5).
|
|
@@ -1985,6 +2535,11 @@ interface PoolKeyHealth {
|
|
|
1985
2535
|
interface PoolHealthReader {
|
|
1986
2536
|
getKeyHealth(providerId: string): Promise<Record<string, PoolKeyHealth>>;
|
|
1987
2537
|
}
|
|
2538
|
+
interface AdminImagesStatusReader {
|
|
2539
|
+
inspectCapability(apiKeyId: string): Promise<ImageRuntimeCapabilityInspection>;
|
|
2540
|
+
status(): ImageRuntimeManagerStatus;
|
|
2541
|
+
resourceStatus(): ImageRuntimeResourceStatus | undefined;
|
|
2542
|
+
}
|
|
1988
2543
|
/** The live daemon handles the management API operates over. */
|
|
1989
2544
|
interface AdminApiDeps {
|
|
1990
2545
|
/** Path to the daemon's `config.json` (provider catalog + `server` field). */
|
|
@@ -2009,6 +2564,16 @@ interface AdminApiDeps {
|
|
|
2009
2564
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
2010
2565
|
/** The running outbound server (status + live applyConfig). */
|
|
2011
2566
|
readonly outboundApiServer: OutboundApiServer;
|
|
2567
|
+
/** True only when production composed the hardened per-hop remote resolver. */
|
|
2568
|
+
readonly imageRemoteResolverAvailable?: boolean;
|
|
2569
|
+
/** Optional production Images runtime generation participant. */
|
|
2570
|
+
readonly imageRuntimeConfig?: {
|
|
2571
|
+
prepareConfig(config: ImagesServerConfig): Promise<PreparedServerConfigChange>;
|
|
2572
|
+
};
|
|
2573
|
+
/** Narrow metadata-only reader for authenticated Images capability/status. */
|
|
2574
|
+
readonly imageRuntimeStatus?: AdminImagesStatusReader;
|
|
2575
|
+
/** Metadata-only successful Images configuration audit sink. */
|
|
2576
|
+
readonly imageConfigAudit?: (record: ImageConfigurationAuditRecord) => void;
|
|
2012
2577
|
/** Process-local machine-managed routing leases (optional for light embedders). */
|
|
2013
2578
|
readonly routeLeaseManager?: RouteLeaseManager;
|
|
2014
2579
|
/** Subscription accounts (token-free `listAll`). */
|
|
@@ -2117,6 +2682,13 @@ interface AdminApiDeps {
|
|
|
2117
2682
|
readonly cliCommandRunner?: CommandRunner;
|
|
2118
2683
|
/** Factory so each request observes the outbound server's current loopback port. */
|
|
2119
2684
|
readonly integrationManagerFactory?: () => IntegrationManager;
|
|
2685
|
+
/**
|
|
2686
|
+
* search-settings-ui D3: the daemon's ONE search runtime plus its
|
|
2687
|
+
* bootstrap-captured frontend modes. Optional for lightweight embedders; the
|
|
2688
|
+
* standalone daemon wires it and the `/admin/api/search` diagnostics/test
|
|
2689
|
+
* routes return 501 when absent (the voucher/allowance optionality precedent).
|
|
2690
|
+
*/
|
|
2691
|
+
readonly searchStatus?: SearchAdminRuntimeStatus;
|
|
2120
2692
|
}
|
|
2121
2693
|
/**
|
|
2122
2694
|
* Dispatch one `/admin/api/*` request. `path` is the already-extracted pathname
|
|
@@ -2233,9 +2805,673 @@ declare class AdminServer {
|
|
|
2233
2805
|
getStatus(): AdminServerStatus;
|
|
2234
2806
|
}
|
|
2235
2807
|
|
|
2808
|
+
type DaemonImagePathArea = 'temporary' | 'artifacts' | 'state' | 'evidence' | 'mountManifest';
|
|
2809
|
+
interface DaemonImagePaths {
|
|
2810
|
+
readonly applicationDataRoot: string;
|
|
2811
|
+
readonly imagesRoot: string;
|
|
2812
|
+
readonly temporaryRoot: string;
|
|
2813
|
+
readonly durableRoot: string;
|
|
2814
|
+
readonly artifactsRoot: string;
|
|
2815
|
+
readonly stateRoot: string;
|
|
2816
|
+
readonly evidenceRoot: string;
|
|
2817
|
+
readonly mountManifestRoot: string;
|
|
2818
|
+
readonly mountManifestPath: string;
|
|
2819
|
+
}
|
|
2820
|
+
interface ImageRootValidationOptions {
|
|
2821
|
+
readonly label?: string;
|
|
2822
|
+
readonly processDirectory?: string;
|
|
2823
|
+
readonly userHome?: string;
|
|
2824
|
+
readonly temporaryDirectory?: string;
|
|
2825
|
+
}
|
|
2826
|
+
interface CreateDaemonImagePathResolverOptions extends ImageRootValidationOptions {
|
|
2827
|
+
readonly configPath: string;
|
|
2828
|
+
readonly storageRoot?: string;
|
|
2829
|
+
}
|
|
2830
|
+
interface VerifiedDaemonImagePath {
|
|
2831
|
+
readonly area: DaemonImagePathArea;
|
|
2832
|
+
readonly absolutePath: string;
|
|
2833
|
+
readonly kind: 'opaque-file' | 'opaque-directory' | 'mount-manifest';
|
|
2834
|
+
}
|
|
2835
|
+
/**
|
|
2836
|
+
* Owns all daemon Images filesystem names. Callers receive opaque capabilities,
|
|
2837
|
+
* never a filename-accepting delete primitive; destructive methods revalidate
|
|
2838
|
+
* the root identity, descendant relationship, basename, and symlink state.
|
|
2839
|
+
*/
|
|
2840
|
+
declare class DaemonImagePathResolver {
|
|
2841
|
+
#private;
|
|
2842
|
+
readonly paths: DaemonImagePaths;
|
|
2843
|
+
constructor(options: CreateDaemonImagePathResolverOptions);
|
|
2844
|
+
createOpaqueFile(area: Exclude<DaemonImagePathArea, 'temporary' | 'mountManifest'>, format?: 'bin' | 'json' | 'tmp'): VerifiedDaemonImagePath;
|
|
2845
|
+
createOpaqueDirectory(area?: Exclude<DaemonImagePathArea, 'mountManifest'>): VerifiedDaemonImagePath;
|
|
2846
|
+
mountManifest(): VerifiedDaemonImagePath;
|
|
2847
|
+
/** Revalidate and return one internal root for store-local bounded I/O. */
|
|
2848
|
+
verifiedRoot(area: DaemonImagePathArea): string;
|
|
2849
|
+
/** Revalidate immediately before unlinking a resolver-issued file capability. */
|
|
2850
|
+
removeFile(target: VerifiedDaemonImagePath): void;
|
|
2851
|
+
/** Only empty opaque directories may be removed until the owned-marker layer is composed. */
|
|
2852
|
+
removeEmptyDirectory(target: VerifiedDaemonImagePath): void;
|
|
2853
|
+
private issue;
|
|
2854
|
+
private verifyDestructiveTarget;
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2857
|
+
interface FileCodexImageCapabilityEvidenceManifestOwnerOptions {
|
|
2858
|
+
readonly paths: DaemonImagePathResolver;
|
|
2859
|
+
readonly maxEntries?: number;
|
|
2860
|
+
readonly now?: () => number;
|
|
2861
|
+
readonly random?: (bytes: number) => Buffer;
|
|
2862
|
+
readonly hmacSalt?: Uint8Array;
|
|
2863
|
+
readonly replaceManifest?: (targetPath: string, contents: Uint8Array) => void;
|
|
2864
|
+
}
|
|
2865
|
+
type FileCodexImageCapabilityEvidenceSourceOptions = Readonly<(FileCodexImageCapabilityEvidenceManifestOwnerOptions & {
|
|
2866
|
+
readonly ttlMs: number;
|
|
2867
|
+
}) | {
|
|
2868
|
+
readonly owner: FileCodexImageCapabilityEvidenceManifestOwner;
|
|
2869
|
+
readonly ttlMs: number;
|
|
2870
|
+
}>;
|
|
2871
|
+
interface FileCodexImageCapabilityEvidenceStatus {
|
|
2872
|
+
readonly entries: number;
|
|
2873
|
+
readonly freshEntries: number;
|
|
2874
|
+
readonly staleEntries: number;
|
|
2875
|
+
readonly bytes: number;
|
|
2876
|
+
}
|
|
2877
|
+
/** Revision-aware manifest owner shared by runtime generations, doctor, and cleanup. */
|
|
2878
|
+
declare class FileCodexImageCapabilityEvidenceManifestOwner {
|
|
2879
|
+
#private;
|
|
2880
|
+
constructor(options: FileCodexImageCapabilityEvidenceManifestOwnerOptions);
|
|
2881
|
+
createSource(ttlMs: number): FileCodexImageCapabilityEvidenceSource;
|
|
2882
|
+
resolveWithTtl(request: CodexImageCapabilityEvidenceRequest, ttlMs: number): Promise<CodexImageCapabilityEvidence>;
|
|
2883
|
+
recordSuccessfulVerificationWithTtl(observation: CodexImageCapabilityObservation, ttlMs: number): Promise<void>;
|
|
2884
|
+
cleanup(now: number, limit: number): Promise<{
|
|
2885
|
+
readonly entriesRemoved: number;
|
|
2886
|
+
readonly bytesRemoved: number;
|
|
2887
|
+
}>;
|
|
2888
|
+
statusWithTtl(ttlMs: number): FileCodexImageCapabilityEvidenceStatus;
|
|
2889
|
+
}
|
|
2890
|
+
/** Immutable TTL view over a revision-aware file-backed evidence manifest owner. */
|
|
2891
|
+
declare class FileCodexImageCapabilityEvidenceSource implements CodexImageCapabilityEvidenceSource {
|
|
2892
|
+
#private;
|
|
2893
|
+
constructor(options: FileCodexImageCapabilityEvidenceSourceOptions);
|
|
2894
|
+
createView(ttlMs: number): FileCodexImageCapabilityEvidenceSource;
|
|
2895
|
+
resolve(request: CodexImageCapabilityEvidenceRequest): Promise<CodexImageCapabilityEvidence>;
|
|
2896
|
+
recordSuccessfulVerification(observation: CodexImageCapabilityObservation): Promise<void>;
|
|
2897
|
+
cleanup(now: number, limit: number): Promise<{
|
|
2898
|
+
readonly entriesRemoved: number;
|
|
2899
|
+
readonly bytesRemoved: number;
|
|
2900
|
+
}>;
|
|
2901
|
+
status(): FileCodexImageCapabilityEvidenceStatus;
|
|
2902
|
+
ttlMs(): number;
|
|
2903
|
+
/** Lifecycle-symmetric no-op; physical safety no longer depends on local leases. */
|
|
2904
|
+
dispose(): void;
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
interface FileImageReferenceStoreLimits {
|
|
2908
|
+
readonly ttlMs: number;
|
|
2909
|
+
readonly maxArtifactBytes: number;
|
|
2910
|
+
readonly maxTotalBytes: number;
|
|
2911
|
+
readonly maxTenantBytes: number;
|
|
2912
|
+
readonly maxEntries: number;
|
|
2913
|
+
readonly maxTombstones: number;
|
|
2914
|
+
readonly tombstoneTtlMs: number;
|
|
2915
|
+
}
|
|
2916
|
+
interface FileImageReferenceStoreOptions {
|
|
2917
|
+
readonly paths: DaemonImagePathResolver;
|
|
2918
|
+
readonly limits: FileImageReferenceStoreLimits;
|
|
2919
|
+
readonly secretBox?: SecretBox;
|
|
2920
|
+
readonly now?: () => number;
|
|
2921
|
+
readonly random?: (bytes: number) => Buffer;
|
|
2922
|
+
readonly replaceManifest?: (targetPath: string, contents: Uint8Array) => void;
|
|
2923
|
+
}
|
|
2924
|
+
interface FileImageReferenceReconciliationResult {
|
|
2925
|
+
readonly metadataRemoved: number;
|
|
2926
|
+
readonly metadataDegradedToProviderReference: number;
|
|
2927
|
+
readonly orphanFilesRemoved: number;
|
|
2928
|
+
readonly incompleteFilesRemoved: number;
|
|
2929
|
+
readonly invalidDescendants: number;
|
|
2930
|
+
}
|
|
2931
|
+
declare class FileImageReferenceStore implements ImageReferenceStore {
|
|
2932
|
+
#private;
|
|
2933
|
+
constructor(options: FileImageReferenceStoreOptions);
|
|
2934
|
+
save(input: ImageReferenceSaveInput): Promise<ImageReferenceMetadata>;
|
|
2935
|
+
/** Generation-bound write entry point; reads and maintenance remain shared. */
|
|
2936
|
+
saveWithLimits(input: ImageReferenceSaveInput, limits: FileImageReferenceStoreLimits): Promise<ImageReferenceMetadata>;
|
|
2937
|
+
/** Updates only app-session maintenance policy; pinned writes pass their own limits. */
|
|
2938
|
+
updateMaintenanceLimits(limits: FileImageReferenceStoreLimits): void;
|
|
2939
|
+
resolve(tenantId: string, referenceId: ImageReferenceId): Promise<ImageReferenceResolution>;
|
|
2940
|
+
delete(tenantId: string, referenceId: ImageReferenceId): Promise<boolean>;
|
|
2941
|
+
/** Daemon-internal cleanup path; accepts only the local reference-domain tenant HMAC. */
|
|
2942
|
+
deleteByHashedTenantKey(tenantKey: string, referenceId: ImageReferenceId): Promise<boolean>;
|
|
2943
|
+
cleanup(now?: number): Promise<number>;
|
|
2944
|
+
status(): {
|
|
2945
|
+
readonly entries: number;
|
|
2946
|
+
readonly bytes: number;
|
|
2947
|
+
readonly tombstones: number;
|
|
2948
|
+
};
|
|
2949
|
+
hasLiveReferenceByHashedTenantKey(tenantKey: string, referenceId: ImageReferenceId, now?: number): Promise<boolean>;
|
|
2950
|
+
reconcileOwnedFiles(maxEntries: number): Promise<FileImageReferenceReconciliationResult>;
|
|
2951
|
+
openArtifact(fileName: string, byteLength: number, signal?: AbortSignal): Promise<ReadableStream<Uint8Array>>;
|
|
2952
|
+
private exclusive;
|
|
2953
|
+
private tenantKey;
|
|
2954
|
+
private newReferenceId;
|
|
2955
|
+
private validateSaveInput;
|
|
2956
|
+
private selectVictims;
|
|
2957
|
+
private nextTombstones;
|
|
2958
|
+
private writeArtifact;
|
|
2959
|
+
private artifactPath;
|
|
2960
|
+
private validArtifact;
|
|
2961
|
+
private removeArtifact;
|
|
2962
|
+
private safeUnlinkArtifactPath;
|
|
2963
|
+
private releaseLease;
|
|
2964
|
+
private manifestPath;
|
|
2965
|
+
private persist;
|
|
2966
|
+
private atomicReplace;
|
|
2967
|
+
private loadManifest;
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
interface FileResponsesImageStateStoreLimits {
|
|
2971
|
+
readonly maxCalls: number;
|
|
2972
|
+
readonly maxResponses: number;
|
|
2973
|
+
readonly maxTombstones: number;
|
|
2974
|
+
readonly tombstoneTtlMs: number;
|
|
2975
|
+
}
|
|
2976
|
+
interface FileResponsesImageStateStoreOptions {
|
|
2977
|
+
readonly paths: DaemonImagePathResolver;
|
|
2978
|
+
readonly limits: FileResponsesImageStateStoreLimits;
|
|
2979
|
+
readonly now?: () => number;
|
|
2980
|
+
readonly random?: (bytes: number) => Buffer;
|
|
2981
|
+
readonly replaceManifest?: (targetPath: string, contents: Uint8Array) => void;
|
|
2982
|
+
}
|
|
2983
|
+
interface PendingResponsesImageReferenceDelete {
|
|
2984
|
+
readonly referenceTenantKey: string;
|
|
2985
|
+
readonly binding: ResponsesImageCallBinding;
|
|
2986
|
+
}
|
|
2987
|
+
/** Durable production implementation of the existing Responses image-state contract. */
|
|
2988
|
+
declare class FileResponsesImageStateStore implements ResponsesImageStateStore {
|
|
2989
|
+
#private;
|
|
2990
|
+
constructor(options: FileResponsesImageStateStoreOptions);
|
|
2991
|
+
commit(input: ResponsesImageStateCommitInput): Promise<readonly ResponsesImageCallBinding[]>;
|
|
2992
|
+
/** Generation-bound write entry point; reads and maintenance remain shared. */
|
|
2993
|
+
commitWithLimits(input: ResponsesImageStateCommitInput, limits: FileResponsesImageStateStoreLimits): Promise<readonly ResponsesImageCallBinding[]>;
|
|
2994
|
+
/** Updates only app-session maintenance policy; pinned commits pass their own limits. */
|
|
2995
|
+
updateMaintenanceLimits(limits: FileResponsesImageStateStoreLimits): void;
|
|
2996
|
+
resolveCall(tenantId: string, callId: ResponsesImageCallId): Promise<ResponsesImageCallResolution>;
|
|
2997
|
+
resolveResponse(tenantId: string, responseId: string): Promise<ResponsesImageResponseResolution>;
|
|
2998
|
+
deleteCall(tenantId: string, callId: ResponsesImageCallId): Promise<ResponsesImageCallBinding | undefined>;
|
|
2999
|
+
deleteResponse(tenantId: string, responseId: string): Promise<boolean>;
|
|
3000
|
+
cleanup(now?: number): Promise<readonly ResponsesImageCallBinding[]>;
|
|
3001
|
+
pendingReferenceDeletes(limit?: number): readonly PendingResponsesImageReferenceDelete[];
|
|
3002
|
+
acknowledgeReferenceDeletes(completed: readonly PendingResponsesImageReferenceDelete[]): Promise<number>;
|
|
3003
|
+
reconcileBrokenReferenceLinks(hasLiveReference: (referenceTenantKey: string, referenceId: ResponsesImageCallBinding['referenceId']) => Promise<boolean>, maxEntries: number): Promise<readonly ResponsesImageCallBinding[]>;
|
|
3004
|
+
status(): {
|
|
3005
|
+
readonly calls: number;
|
|
3006
|
+
readonly responses: number;
|
|
3007
|
+
readonly tombstones: number;
|
|
3008
|
+
readonly pendingReferenceDeletes: number;
|
|
3009
|
+
};
|
|
3010
|
+
private exclusive;
|
|
3011
|
+
private failure;
|
|
3012
|
+
private assertCommit;
|
|
3013
|
+
private tenantKey;
|
|
3014
|
+
private rememberTombstone;
|
|
3015
|
+
private enqueuePendingReferenceDelete;
|
|
3016
|
+
private hasTombstone;
|
|
3017
|
+
private prunedTombstones;
|
|
3018
|
+
private pruneTombstonesInPlace;
|
|
3019
|
+
private sameTombstones;
|
|
3020
|
+
private touch;
|
|
3021
|
+
private releaseCall;
|
|
3022
|
+
private releaseResponse;
|
|
3023
|
+
private manifestPath;
|
|
3024
|
+
private persist;
|
|
3025
|
+
private atomicReplace;
|
|
3026
|
+
private loadManifest;
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
interface ImageStorageMountBackend {
|
|
3030
|
+
readonly id: string;
|
|
3031
|
+
readonly createdAt: number;
|
|
3032
|
+
readonly resolver: DaemonImagePathResolver;
|
|
3033
|
+
readonly references: FileImageReferenceStore;
|
|
3034
|
+
readonly responsesState: FileResponsesImageStateStore;
|
|
3035
|
+
}
|
|
3036
|
+
interface ImageStorageMountCatalogOptions {
|
|
3037
|
+
readonly pathOptions: Omit<CreateDaemonImagePathResolverOptions, 'storageRoot'>;
|
|
3038
|
+
readonly activeStorageRoot?: string;
|
|
3039
|
+
readonly referenceLimits: FileImageReferenceStoreLimits;
|
|
3040
|
+
readonly responsesStateLimits: FileResponsesImageStateStoreLimits;
|
|
3041
|
+
readonly secretBox?: SecretBox;
|
|
3042
|
+
readonly now?: () => number;
|
|
3043
|
+
readonly random?: (bytes: number) => Buffer;
|
|
3044
|
+
readonly replaceCatalog?: (targetPath: string, contents: Uint8Array) => void;
|
|
3045
|
+
readonly reconcileCorruptManifests?: boolean;
|
|
3046
|
+
}
|
|
3047
|
+
interface ImageStorageMountPolicy {
|
|
3048
|
+
readonly referenceLimits: FileImageReferenceStoreLimits;
|
|
3049
|
+
readonly responsesStateLimits: FileResponsesImageStateStoreLimits;
|
|
3050
|
+
}
|
|
3051
|
+
interface PreparedImageStorageMountActivation {
|
|
3052
|
+
readonly backend: ImageStorageMountBackend;
|
|
3053
|
+
publish(): ImageStorageMountBackend;
|
|
3054
|
+
rollback(): void;
|
|
3055
|
+
dispose(): void;
|
|
3056
|
+
}
|
|
3057
|
+
/** Owns the durable-root set independently from any one runtime generation. */
|
|
3058
|
+
declare class ImageStorageMountCatalog {
|
|
3059
|
+
#private;
|
|
3060
|
+
constructor(options: ImageStorageMountCatalogOptions);
|
|
3061
|
+
active(): ImageStorageMountBackend;
|
|
3062
|
+
mountsForRead(): readonly ImageStorageMountBackend[];
|
|
3063
|
+
status(): {
|
|
3064
|
+
readonly mounts: number;
|
|
3065
|
+
readonly retiredMounts: number;
|
|
3066
|
+
};
|
|
3067
|
+
startupReconciliationStatus(): {
|
|
3068
|
+
readonly corruptManifestsQuarantined: number;
|
|
3069
|
+
};
|
|
3070
|
+
utilization(): {
|
|
3071
|
+
readonly referenceEntries: number;
|
|
3072
|
+
readonly referenceBytes: number;
|
|
3073
|
+
readonly referenceTombstones: number;
|
|
3074
|
+
readonly stateCalls: number;
|
|
3075
|
+
readonly stateResponses: number;
|
|
3076
|
+
readonly stateTombstones: number;
|
|
3077
|
+
readonly pendingReferenceDeletes: number;
|
|
3078
|
+
};
|
|
3079
|
+
/** Pins a backend object until its owning runtime generation drains. */
|
|
3080
|
+
retainBackend(backend: ImageStorageMountBackend): () => void;
|
|
3081
|
+
activate(storageRoot?: string): ImageStorageMountBackend;
|
|
3082
|
+
/** Prepare a validated backend without changing the catalog's active mount. */
|
|
3083
|
+
prepareActivation(storageRoot?: string, policy?: ImageStorageMountPolicy): PreparedImageStorageMountActivation;
|
|
3084
|
+
retireEmptyMount(mountId: string): boolean;
|
|
3085
|
+
private createResolver;
|
|
3086
|
+
private createBackend;
|
|
3087
|
+
private applyMaintenancePolicy;
|
|
3088
|
+
private newMountId;
|
|
3089
|
+
private isManifestError;
|
|
3090
|
+
private quarantineManifest;
|
|
3091
|
+
private isVerifiedEmpty;
|
|
3092
|
+
private catalogPath;
|
|
3093
|
+
private persist;
|
|
3094
|
+
private atomicReplace;
|
|
3095
|
+
private loadCatalog;
|
|
3096
|
+
}
|
|
3097
|
+
declare class MountedImageReferenceStore implements ImageReferenceStore {
|
|
3098
|
+
private readonly catalog;
|
|
3099
|
+
private readonly writeBackend?;
|
|
3100
|
+
private readonly writeLimits?;
|
|
3101
|
+
constructor(catalog: ImageStorageMountCatalog, writeBackend?: ImageStorageMountBackend | undefined, writeLimits?: FileImageReferenceStoreLimits | undefined);
|
|
3102
|
+
bindWriteBackend(backend: ImageStorageMountBackend, limits: FileImageReferenceStoreLimits): MountedImageReferenceStore;
|
|
3103
|
+
status(): Readonly<{
|
|
3104
|
+
referenceEntries: number;
|
|
3105
|
+
referenceBytes: number;
|
|
3106
|
+
referenceTombstones: number;
|
|
3107
|
+
stateCalls: number;
|
|
3108
|
+
stateResponses: number;
|
|
3109
|
+
stateTombstones: number;
|
|
3110
|
+
pendingReferenceDeletes: number;
|
|
3111
|
+
mounts: number;
|
|
3112
|
+
retiredMounts: number;
|
|
3113
|
+
}>;
|
|
3114
|
+
save(input: ImageReferenceSaveInput): Promise<_omnicross_contracts_image_generation_types.ImageReferenceMetadata>;
|
|
3115
|
+
resolve(tenantId: string, referenceId: ImageReferenceId): Promise<ImageReferenceResolution>;
|
|
3116
|
+
delete(tenantId: string, referenceId: ImageReferenceId): Promise<boolean>;
|
|
3117
|
+
deleteByHashedTenantKey(tenantKey: string, referenceId: ImageReferenceId): Promise<boolean>;
|
|
3118
|
+
cleanup(now?: number): Promise<number>;
|
|
3119
|
+
}
|
|
3120
|
+
declare class MountedResponsesImageStateStore implements ResponsesImageStateStore {
|
|
3121
|
+
private readonly catalog;
|
|
3122
|
+
private readonly writeBackend?;
|
|
3123
|
+
private readonly writeLimits?;
|
|
3124
|
+
constructor(catalog: ImageStorageMountCatalog, writeBackend?: ImageStorageMountBackend | undefined, writeLimits?: FileResponsesImageStateStoreLimits | undefined);
|
|
3125
|
+
bindWriteBackend(backend: ImageStorageMountBackend, limits: FileResponsesImageStateStoreLimits): MountedResponsesImageStateStore;
|
|
3126
|
+
commit(input: ResponsesImageStateCommitInput): Promise<readonly ResponsesImageCallBinding[]>;
|
|
3127
|
+
resolveCall(tenantId: string, callId: ResponsesImageCallId): Promise<ResponsesImageCallResolution>;
|
|
3128
|
+
resolveResponse(tenantId: string, responseId: string): Promise<ResponsesImageResponseResolution>;
|
|
3129
|
+
deleteCall(tenantId: string, callId: ResponsesImageCallId): Promise<ResponsesImageCallBinding | undefined>;
|
|
3130
|
+
deleteResponse(tenantId: string, responseId: string): Promise<boolean>;
|
|
3131
|
+
cleanup(now?: number): Promise<readonly ResponsesImageCallBinding[]>;
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
interface ImageDoctorLocalSnapshot {
|
|
3135
|
+
readonly config: Readonly<{
|
|
3136
|
+
enabled: boolean;
|
|
3137
|
+
provider: 'codex-subscription';
|
|
3138
|
+
model: string;
|
|
3139
|
+
valid: boolean;
|
|
3140
|
+
errorCount: number;
|
|
3141
|
+
}>;
|
|
3142
|
+
readonly roots: Readonly<{
|
|
3143
|
+
valid: boolean;
|
|
3144
|
+
verifiedAreas: number;
|
|
3145
|
+
expectedAreas: number;
|
|
3146
|
+
}>;
|
|
3147
|
+
readonly stores: Readonly<{
|
|
3148
|
+
valid: boolean;
|
|
3149
|
+
mounts: number;
|
|
3150
|
+
retiredMounts: number;
|
|
3151
|
+
referenceEntries: number;
|
|
3152
|
+
referenceBytes: number;
|
|
3153
|
+
stateCalls: number;
|
|
3154
|
+
stateResponses: number;
|
|
3155
|
+
corruptManifestsQuarantined: number;
|
|
3156
|
+
}>;
|
|
3157
|
+
readonly permissions: Readonly<{
|
|
3158
|
+
valid: boolean;
|
|
3159
|
+
rows: number;
|
|
3160
|
+
legacyRows: number;
|
|
3161
|
+
invalidRows: number;
|
|
3162
|
+
imagesAuthorizedRows: number;
|
|
3163
|
+
}>;
|
|
3164
|
+
readonly account: Readonly<{
|
|
3165
|
+
present: boolean;
|
|
3166
|
+
usable: boolean;
|
|
3167
|
+
reason: 'ready' | 'missing' | 'unavailable';
|
|
3168
|
+
}>;
|
|
3169
|
+
readonly evidence: Readonly<FileCodexImageCapabilityEvidenceStatus & {
|
|
3170
|
+
valid: boolean;
|
|
3171
|
+
}>;
|
|
3172
|
+
}
|
|
3173
|
+
type ImageDoctorLiveFailureCode = 'images_disabled' | 'codex_account_unavailable' | 'evidence_store_unavailable' | 'evidence_persist_failed' | ImageGenerationErrorCode;
|
|
3174
|
+
type ImageDoctorLiveResult = Readonly<{
|
|
3175
|
+
ok: true;
|
|
3176
|
+
code: 'verified';
|
|
3177
|
+
model: 'gpt-image-2';
|
|
3178
|
+
quality: 'low';
|
|
3179
|
+
outputFormat: 'png';
|
|
3180
|
+
freshEvidenceEntries: number;
|
|
3181
|
+
}> | Readonly<{
|
|
3182
|
+
ok: false;
|
|
3183
|
+
code: ImageDoctorLiveFailureCode;
|
|
3184
|
+
}>;
|
|
3185
|
+
interface ImageDoctorService {
|
|
3186
|
+
inspectLocal(config: ImagesServerConfig): Promise<ImageDoctorLocalSnapshot>;
|
|
3187
|
+
verifyLive(config: ImagesServerConfig, signal: AbortSignal): Promise<ImageDoctorLiveResult>;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
interface ImageTemporaryBudgetStatus {
|
|
3191
|
+
readonly activeScopes: number;
|
|
3192
|
+
readonly totalBytes: number;
|
|
3193
|
+
readonly tenantCount: number;
|
|
3194
|
+
}
|
|
3195
|
+
/** Process-local atomic budget shared by every scope in one pinned runtime generation. */
|
|
3196
|
+
declare class DaemonImageTemporaryBudget implements ImageTemporaryResourceBudget {
|
|
3197
|
+
#private;
|
|
3198
|
+
constructor(config: ImagesServerConfig['temporary']);
|
|
3199
|
+
acquireScope(tenantId: string): ImageTemporaryResourceBudgetLease;
|
|
3200
|
+
status(): ImageTemporaryBudgetStatus;
|
|
3201
|
+
}
|
|
3202
|
+
interface DaemonImageTemporaryResourceFactoryOptions {
|
|
3203
|
+
readonly paths: DaemonImagePathResolver;
|
|
3204
|
+
readonly config: ImagesServerConfig['temporary'];
|
|
3205
|
+
readonly activeScopes?: DaemonImageActiveScopeRegistry;
|
|
3206
|
+
}
|
|
3207
|
+
/** App-session registry shared by all runtime generations and recurring cleanup. */
|
|
3208
|
+
declare class DaemonImageActiveScopeRegistry {
|
|
3209
|
+
#private;
|
|
3210
|
+
constructor(paths: DaemonImagePathResolver);
|
|
3211
|
+
register(privateDirectory: string): () => void;
|
|
3212
|
+
isActive(privateDirectory: string): boolean;
|
|
3213
|
+
status(): {
|
|
3214
|
+
readonly activeDirectories: number;
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
/** Binds the private root, fixed owner marker, tenant, and shared budget in one seam. */
|
|
3218
|
+
declare class DaemonImageTemporaryResourceFactory {
|
|
3219
|
+
#private;
|
|
3220
|
+
readonly budget: DaemonImageTemporaryBudget;
|
|
3221
|
+
constructor(options: DaemonImageTemporaryResourceFactoryOptions);
|
|
3222
|
+
readonly createResourceScope: (limits: ImageApiLimits, signal: AbortSignal, tenantId: string) => Promise<ImageRequestResourceScope>;
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
interface ImageStartupReconcilerOptions {
|
|
3226
|
+
readonly catalog: ImageStorageMountCatalog;
|
|
3227
|
+
readonly temporaryPaths: DaemonImagePathResolver;
|
|
3228
|
+
readonly staleTemporaryAfterMs: number;
|
|
3229
|
+
readonly activeTemporaryScopes?: Pick<DaemonImageActiveScopeRegistry, 'isActive'>;
|
|
3230
|
+
readonly maxMountsPerPass?: number;
|
|
3231
|
+
readonly maxEntriesPerMount?: number;
|
|
3232
|
+
readonly maxTemporaryDirectoriesPerPass?: number;
|
|
3233
|
+
readonly now?: () => number;
|
|
3234
|
+
}
|
|
3235
|
+
interface ImageStartupReconciliationResult {
|
|
3236
|
+
readonly corruptManifestsQuarantined: number;
|
|
3237
|
+
readonly mountsVisited: number;
|
|
3238
|
+
readonly stateBindingsRemoved: number;
|
|
3239
|
+
readonly brokenBindingsRemoved: number;
|
|
3240
|
+
readonly referenceEntriesRemoved: number;
|
|
3241
|
+
readonly metadataRemoved: number;
|
|
3242
|
+
readonly metadataDegradedToProviderReference: number;
|
|
3243
|
+
readonly orphanFilesRemoved: number;
|
|
3244
|
+
readonly incompleteFilesRemoved: number;
|
|
3245
|
+
readonly transactionFilesRemoved: number;
|
|
3246
|
+
readonly temporaryDirectoriesRemoved: number;
|
|
3247
|
+
readonly foreignTemporaryDirectoriesSkipped: number;
|
|
3248
|
+
readonly activeTemporaryDirectoriesSkipped: number;
|
|
3249
|
+
readonly invalidDescendantsSkipped: number;
|
|
3250
|
+
readonly pendingReferenceDeletes: number;
|
|
3251
|
+
}
|
|
3252
|
+
/** One bounded, synchronous-filesystem startup pass; it never follows symlinks. */
|
|
3253
|
+
declare class ImageStartupReconciler {
|
|
3254
|
+
#private;
|
|
3255
|
+
constructor(options: ImageStartupReconcilerOptions);
|
|
3256
|
+
run(): Promise<ImageStartupReconciliationResult>;
|
|
3257
|
+
private hasLiveReference;
|
|
3258
|
+
private removeTransactionFiles;
|
|
3259
|
+
private removeStaleTemporaryDirectories;
|
|
3260
|
+
private removeTreeWithoutFollowingSymlinks;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
interface BoundedImageEvidenceCleanup {
|
|
3264
|
+
cleanup(now: number, limit: number): Promise<{
|
|
3265
|
+
readonly entriesRemoved: number;
|
|
3266
|
+
readonly bytesRemoved: number;
|
|
3267
|
+
}>;
|
|
3268
|
+
}
|
|
3269
|
+
interface ImageCleanupTimer {
|
|
3270
|
+
unref(): unknown;
|
|
3271
|
+
}
|
|
3272
|
+
interface ImageCleanupServiceOptions {
|
|
3273
|
+
readonly reconciler: ImageStartupReconciler;
|
|
3274
|
+
readonly catalog: ImageStorageMountCatalog;
|
|
3275
|
+
readonly intervalMs: number;
|
|
3276
|
+
readonly maxEvidenceEntriesPerPass?: number;
|
|
3277
|
+
readonly maxRetiredMountsPerPass?: number;
|
|
3278
|
+
readonly evidence?: BoundedImageEvidenceCleanup;
|
|
3279
|
+
readonly now?: () => number;
|
|
3280
|
+
readonly scheduleInterval?: (callback: () => void, intervalMs: number) => ImageCleanupTimer;
|
|
3281
|
+
readonly clearScheduledInterval?: (timer: ImageCleanupTimer) => void;
|
|
3282
|
+
}
|
|
3283
|
+
interface ImageCleanupPolicy {
|
|
3284
|
+
readonly reconciler: ImageStartupReconciler;
|
|
3285
|
+
readonly intervalMs: number;
|
|
3286
|
+
readonly evidence?: BoundedImageEvidenceCleanup;
|
|
3287
|
+
}
|
|
3288
|
+
interface PreparedImageCleanupPolicyChange {
|
|
3289
|
+
publish(): void;
|
|
3290
|
+
rollback(): void;
|
|
3291
|
+
dispose(): void;
|
|
3292
|
+
}
|
|
3293
|
+
interface ImageCleanupServicePassResult {
|
|
3294
|
+
readonly stateBindingsRemoved: number;
|
|
3295
|
+
readonly brokenBindingsRemoved: number;
|
|
3296
|
+
readonly referenceEntriesRemoved: number;
|
|
3297
|
+
readonly orphanFilesRemoved: number;
|
|
3298
|
+
readonly incompleteFilesRemoved: number;
|
|
3299
|
+
readonly transactionFilesRemoved: number;
|
|
3300
|
+
readonly temporaryDirectoriesRemoved: number;
|
|
3301
|
+
readonly evidenceEntriesRemoved: number;
|
|
3302
|
+
readonly evidenceBytesRemoved: number;
|
|
3303
|
+
readonly evidenceCleanupFailures: number;
|
|
3304
|
+
readonly retiredMountsRemoved: number;
|
|
3305
|
+
readonly referenceEntries: number;
|
|
3306
|
+
readonly referenceBytes: number;
|
|
3307
|
+
readonly referenceTombstones: number;
|
|
3308
|
+
readonly stateCalls: number;
|
|
3309
|
+
readonly stateResponses: number;
|
|
3310
|
+
readonly stateTombstones: number;
|
|
3311
|
+
readonly pendingReferenceDeletes: number;
|
|
3312
|
+
readonly finishedAt: number;
|
|
3313
|
+
}
|
|
3314
|
+
interface ImageCleanupServiceStatus extends ImageCleanupServicePassResult {
|
|
3315
|
+
readonly running: boolean;
|
|
3316
|
+
readonly passesCompleted: number;
|
|
3317
|
+
readonly passFailures: number;
|
|
3318
|
+
}
|
|
3319
|
+
/** Unref'ed recurring lifecycle owner with one non-overlapping bounded pass. */
|
|
3320
|
+
declare class ImageCleanupService {
|
|
3321
|
+
#private;
|
|
3322
|
+
constructor(options: ImageCleanupServiceOptions);
|
|
3323
|
+
start(): void;
|
|
3324
|
+
private schedule;
|
|
3325
|
+
/** Prepares a hot-reloadable cadence/reconciler/evidence snapshot. */
|
|
3326
|
+
preparePolicy(policy: ImageCleanupPolicy): PreparedImageCleanupPolicyChange;
|
|
3327
|
+
stop(): Promise<void>;
|
|
3328
|
+
reset(): Promise<void>;
|
|
3329
|
+
runOnce(): Promise<ImageCleanupServicePassResult>;
|
|
3330
|
+
status(): ImageCleanupServiceStatus;
|
|
3331
|
+
private performPass;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3334
|
+
interface TrustedImageApiRuntimeResolverOptions {
|
|
3335
|
+
readonly config: ImagesServerConfig;
|
|
3336
|
+
readonly referenceStore: ImageReferenceStore;
|
|
3337
|
+
/** Persistent private daemon key material. It is copied on construction. */
|
|
3338
|
+
readonly hmacKey: Uint8Array;
|
|
3339
|
+
/** Present only when the host has proved the complete remote-fetch policy. */
|
|
3340
|
+
readonly provenRemoteResolver?: RemoteImageAssetResolver;
|
|
3341
|
+
}
|
|
3342
|
+
interface TrustedImageApiRuntimeResolver {
|
|
3343
|
+
readonly resolve: ImageApiRuntimeResolver;
|
|
3344
|
+
dispose(): void;
|
|
3345
|
+
}
|
|
3346
|
+
/**
|
|
3347
|
+
* Resolves only daemon-authenticated route state. Named outbound keys retain
|
|
3348
|
+
* their stable key-id tenant; ephemeral Route Lease traffic falls back to the
|
|
3349
|
+
* authenticated lease id and remains isolated from other leases. Request
|
|
3350
|
+
* headers, including an inbound bearer, are deliberately outside the resolver's
|
|
3351
|
+
* identity inputs.
|
|
3352
|
+
*/
|
|
3353
|
+
declare function createTrustedImageApiRuntimeResolver(options: TrustedImageApiRuntimeResolverOptions): TrustedImageApiRuntimeResolver;
|
|
3354
|
+
|
|
3355
|
+
interface DaemonImageExecutionSchedulerOptions {
|
|
3356
|
+
readonly config: ImagesServerConfig['queue'];
|
|
3357
|
+
/** Persistent private daemon key material; copied on construction. */
|
|
3358
|
+
readonly hmacKey: Uint8Array;
|
|
3359
|
+
}
|
|
3360
|
+
interface DaemonImageExecutionSchedulerStatus {
|
|
3361
|
+
readonly activeJobs: number;
|
|
3362
|
+
readonly waitingJobs: number;
|
|
3363
|
+
readonly activeAccounts: number;
|
|
3364
|
+
readonly waitingAccounts: number;
|
|
3365
|
+
readonly waitingTenants: number;
|
|
3366
|
+
readonly maxConcurrentJobsPerAccount: number;
|
|
3367
|
+
readonly maxQueuedJobs: number;
|
|
3368
|
+
readonly accepting: boolean;
|
|
3369
|
+
readonly shuttingDown: boolean;
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
* Snapshot-bound image admission with per-account active caps and fair tenant
|
|
3373
|
+
* rotation under one bounded global waiting population.
|
|
3374
|
+
*/
|
|
3375
|
+
declare class DaemonImageExecutionScheduler implements ImageExecutionScheduler {
|
|
3376
|
+
#private;
|
|
3377
|
+
constructor(options: DaemonImageExecutionSchedulerOptions);
|
|
3378
|
+
deriveAccountKey(selectedAccountId: string): ImageExecutionAccountKey;
|
|
3379
|
+
acquire(request: ImageExecutionSchedulerRequest): Promise<ImageExecutionSchedulerGrant>;
|
|
3380
|
+
status(): DaemonImageExecutionSchedulerStatus;
|
|
3381
|
+
/** Stop new admissions while allowing already queued and active work to drain. */
|
|
3382
|
+
retire(): void;
|
|
3383
|
+
/** Reject waiters and cancel active grants. Safe to call repeatedly. */
|
|
3384
|
+
shutdown(): void;
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
interface ImageRuntimeGenerationSharedStorage {
|
|
3388
|
+
/** Resolver associated with the catalog's already-active mount. */
|
|
3389
|
+
readonly paths: DaemonImagePathResolver;
|
|
3390
|
+
readonly referenceStore: MountedImageReferenceStore;
|
|
3391
|
+
readonly stateStore: MountedResponsesImageStateStore;
|
|
3392
|
+
}
|
|
3393
|
+
interface ImageRuntimeMetadataObservability {
|
|
3394
|
+
readonly telemetrySink?: ImageTelemetrySink;
|
|
3395
|
+
readonly audit?: (record: ImageApiAuditRecord) => void | Promise<void>;
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* Explicit deterministic Tier-A seam. It replaces only the provider inside an
|
|
3399
|
+
* otherwise-production runtime generation and is never inferred from config.
|
|
3400
|
+
*/
|
|
3401
|
+
interface SyntheticVerifiedImageProviderTestSeam {
|
|
3402
|
+
readonly label: 'synthetic-verified-image-provider-test-only';
|
|
3403
|
+
createProvider(context: Readonly<{
|
|
3404
|
+
generationId: string;
|
|
3405
|
+
scheduler: ImageExecutionScheduler;
|
|
3406
|
+
now: () => number;
|
|
3407
|
+
referenceStore: MountedImageReferenceStore;
|
|
3408
|
+
stateStore: MountedResponsesImageStateStore;
|
|
3409
|
+
}>): ImageProvider;
|
|
3410
|
+
}
|
|
3411
|
+
interface ImageRuntimeGenerationFactoryOptions {
|
|
3412
|
+
readonly generationId: string;
|
|
3413
|
+
readonly config: ImagesServerConfig;
|
|
3414
|
+
readonly subscriptionAccounts: Pick<SubscriptionAccountService, 'getStrategy'>;
|
|
3415
|
+
readonly storage: ImageRuntimeGenerationSharedStorage;
|
|
3416
|
+
readonly provenRemoteResolver?: RemoteImageAssetResolver;
|
|
3417
|
+
readonly observability?: ImageRuntimeMetadataObservability;
|
|
3418
|
+
readonly createRequestId?: () => string;
|
|
3419
|
+
readonly createCallId?: () => `ig_${string}`;
|
|
3420
|
+
readonly now?: () => number;
|
|
3421
|
+
/** Test seam; production loads the persistent daemon-local HMAC salt. */
|
|
3422
|
+
readonly privateHmacKey?: Uint8Array;
|
|
3423
|
+
/** App-session owner used to protect live directories across generations. */
|
|
3424
|
+
readonly activeTemporaryScopes?: DaemonImageActiveScopeRegistry;
|
|
3425
|
+
/** Immutable TTL view scoped to this runtime generation. */
|
|
3426
|
+
readonly evidenceSource?: FileCodexImageCapabilityEvidenceSource;
|
|
3427
|
+
/** App-session catalog lease retained until this generation is disposed. */
|
|
3428
|
+
readonly releaseStorageBackend?: () => void;
|
|
3429
|
+
/** Test-only Tier-A provider; production leaves this absent. */
|
|
3430
|
+
readonly testOnlySyntheticVerifiedProvider?: SyntheticVerifiedImageProviderTestSeam;
|
|
3431
|
+
}
|
|
3432
|
+
interface ProductionImageRuntimeComponents {
|
|
3433
|
+
readonly providerRegistry: ImageProviderRegistry;
|
|
3434
|
+
readonly orchestrator: ImageOrchestrator;
|
|
3435
|
+
readonly scheduler: DaemonImageExecutionScheduler;
|
|
3436
|
+
readonly evidenceSource: FileCodexImageCapabilityEvidenceSource;
|
|
3437
|
+
readonly temporaryResources: DaemonImageTemporaryResourceFactory;
|
|
3438
|
+
readonly runtimeResolver: TrustedImageApiRuntimeResolver;
|
|
3439
|
+
readonly referenceStore: MountedImageReferenceStore;
|
|
3440
|
+
readonly stateStore: MountedResponsesImageStateStore;
|
|
3441
|
+
}
|
|
3442
|
+
type ProductionImageRuntimeGeneration = PreparedImageRuntimeGeneration & {
|
|
3443
|
+
readonly components?: ProductionImageRuntimeComponents;
|
|
3444
|
+
};
|
|
3445
|
+
/**
|
|
3446
|
+
* Builds a complete generation without changing the storage catalog's active
|
|
3447
|
+
* mount. Catalog activation must be composed by a failure-atomic transaction.
|
|
3448
|
+
*/
|
|
3449
|
+
declare function createImageRuntimeGeneration(options: ImageRuntimeGenerationFactoryOptions): ProductionImageRuntimeGeneration;
|
|
3450
|
+
|
|
3451
|
+
/**
|
|
3452
|
+
* JsonOutboundKeyDb — the daemon's file-backed `OutboundKeyDb` port impl
|
|
3453
|
+
* (design D3).
|
|
3454
|
+
*
|
|
3455
|
+
* Durable storage for named outbound API keys, backed by a json file (a sibling
|
|
3456
|
+
* of `config.json`, e.g. `keys.json`) holding an `OutboundKeyDbRow[]`. This port
|
|
3457
|
+
* provides ONLY storage — it never generates secrets nor hashes. Core's
|
|
3458
|
+
* `createNamedKey(db, name)` calls `outboundApiKeysCreate` with the sha256
|
|
3459
|
+
* `keyHash` + display `keyPrefix` and returns the one-time plaintext; the hot
|
|
3460
|
+
* auth path uses core's `hashKey(presented)` + `outboundApiKeysGetByHash`.
|
|
3461
|
+
*
|
|
3462
|
+
* OPTIONAL reversible storage: when constructed with a `SecretBox`, each created
|
|
3463
|
+
* key ALSO persists its plaintext as a `keySecret` `enc:` envelope, powering the
|
|
3464
|
+
* operator "view key" affordance (`outboundApiKeysReveal`). The hash remains the
|
|
3465
|
+
* auth index; without a box the store is hash-only (byte-identical to legacy).
|
|
3466
|
+
*
|
|
3467
|
+
* @module @omnicross/daemon/ports/JsonOutboundKeyDb
|
|
3468
|
+
*/
|
|
3469
|
+
|
|
3470
|
+
type AtomicFileReplace = (targetPath: string, contents: string) => void;
|
|
2236
3471
|
declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
2237
3472
|
private readonly keysPath;
|
|
2238
3473
|
private readonly secretBox?;
|
|
3474
|
+
private readonly atomicReplace;
|
|
2239
3475
|
/**
|
|
2240
3476
|
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
2241
3477
|
* key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
|
|
@@ -2244,7 +3480,7 @@ declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
|
2244
3480
|
* always returns `null`. Existing 1-arg call sites (tests, lightweight
|
|
2245
3481
|
* embedders) keep working.
|
|
2246
3482
|
*/
|
|
2247
|
-
constructor(keysPath: string, secretBox?: SecretBox | undefined);
|
|
3483
|
+
constructor(keysPath: string, secretBox?: SecretBox | undefined, atomicReplace?: AtomicFileReplace);
|
|
2248
3484
|
outboundApiKeysList(): Promise<OutboundKeyDbRow[]>;
|
|
2249
3485
|
outboundApiKeysGetByHash(hash: string): Promise<OutboundKeyDbRow | null>;
|
|
2250
3486
|
outboundApiKeysCreate(input: {
|
|
@@ -2254,7 +3490,7 @@ declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
|
2254
3490
|
keyPrefix: string;
|
|
2255
3491
|
createdAt?: number;
|
|
2256
3492
|
kind?: 'client' | 'integration';
|
|
2257
|
-
allowedEndpoints?:
|
|
3493
|
+
allowedEndpoints?: OutboundPermission[];
|
|
2258
3494
|
loopbackOnly?: boolean;
|
|
2259
3495
|
plaintext?: string;
|
|
2260
3496
|
}): Promise<OutboundKeyDbRow>;
|
|
@@ -2263,6 +3499,7 @@ declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
|
2263
3499
|
outboundApiKeysRevoke(id: string): Promise<boolean>;
|
|
2264
3500
|
outboundApiKeysTouchLastUsed(id: string): Promise<boolean>;
|
|
2265
3501
|
outboundApiKeysSetEnabled(id: string, enabled: boolean): Promise<boolean>;
|
|
3502
|
+
outboundApiKeysSetPermissions(id: string, permissions: OutboundPermission[]): Promise<boolean>;
|
|
2266
3503
|
outboundApiKeysSetMaxConcurrency(id: string, maxConcurrency: number | null): Promise<boolean>;
|
|
2267
3504
|
outboundApiKeysSetPolicy(id: string, policy: OutboundKeyPolicy): Promise<boolean>;
|
|
2268
3505
|
outboundApiKeysMarkActivated(id: string, activatedAt: number): Promise<boolean>;
|
|
@@ -2424,6 +3661,52 @@ declare class AuditPruneSweeper {
|
|
|
2424
3661
|
private archiveDay;
|
|
2425
3662
|
}
|
|
2426
3663
|
|
|
3664
|
+
/**
|
|
3665
|
+
* usageMigrate — the ONE-SHOT fold of the legacy flat `usage-events.jsonl` into
|
|
3666
|
+
* per-LOCAL-day shards plus their immutable rollups.
|
|
3667
|
+
*
|
|
3668
|
+
* Runs at bootstrap, BEFORE any listener is bound, so no request can be served
|
|
3669
|
+
* against a half-migrated store. It streams: the legacy file is never held in
|
|
3670
|
+
* memory as one string (that is the exact shape that put the old store on course
|
|
3671
|
+
* for V8's ~512 MB string ceiling), and each day's rollup is accumulated during
|
|
3672
|
+
* the same pass that writes its shard, so the whole migration is a single read.
|
|
3673
|
+
*
|
|
3674
|
+
* Writes are BATCHED per day (see {@link FLUSH_BYTES}). Awaiting a write per row
|
|
3675
|
+
* turned 199k rows into ~17 s of boot on a real 157 MB store, which the desktop
|
|
3676
|
+
* shell — waiting on the admin port — is right to find suspicious; batching cuts
|
|
3677
|
+
* it to a few seconds without changing what lands on disk.
|
|
3678
|
+
*
|
|
3679
|
+
* CRASH SAFETY. Everything is built inside `usage/.migrating/` and only moved
|
|
3680
|
+
* into place once the row count reconciles. A crash before the commit leaves the
|
|
3681
|
+
* legacy file untouched and the scratch directory to be wiped and rebuilt on the
|
|
3682
|
+
* next attempt. A crash DURING the commit leaves some shards in place and the
|
|
3683
|
+
* legacy file still present; the next attempt refuses to run (a target shard
|
|
3684
|
+
* already exists) and says so, rather than overwriting or double-counting rows.
|
|
3685
|
+
*
|
|
3686
|
+
* RECONCILIATION is the point of the exercise: `linesRead` must equal
|
|
3687
|
+
* `rowsWritten + skipped`, where `skipped` is lines the shared row guard rejects.
|
|
3688
|
+
* If it does not, nothing is committed and the legacy file stays exactly where it
|
|
3689
|
+
* was. Silently losing usage rows would corrupt lifetime key spend, which is the
|
|
3690
|
+
* one number in this store that can never be reconstructed.
|
|
3691
|
+
*
|
|
3692
|
+
* @module @omnicross/daemon/usage/usageMigrate
|
|
3693
|
+
*/
|
|
3694
|
+
|
|
3695
|
+
interface UsageMigrationResult {
|
|
3696
|
+
/** True only when the legacy file was folded in and removed. */
|
|
3697
|
+
migrated: boolean;
|
|
3698
|
+
/** Non-empty lines read from the legacy file. */
|
|
3699
|
+
linesRead: number;
|
|
3700
|
+
/** Rows that passed the guard and were written to a shard. */
|
|
3701
|
+
rowsWritten: number;
|
|
3702
|
+
/** Lines the guard rejected (torn tail, hand-edited, foreign writer). */
|
|
3703
|
+
skipped: number;
|
|
3704
|
+
/** Distinct LOCAL days produced. */
|
|
3705
|
+
days: number;
|
|
3706
|
+
/** Present when the migration declined or aborted; nothing was committed. */
|
|
3707
|
+
reason?: string;
|
|
3708
|
+
}
|
|
3709
|
+
|
|
2427
3710
|
/**
|
|
2428
3711
|
* AuditWriter — the daemon's file-backed audit sink (request-audit-log design
|
|
2429
3712
|
* D4/D5, re-laid-out by audit-store-sharding design D2). Registered as
|
|
@@ -2824,6 +4107,16 @@ interface DaemonPaths {
|
|
|
2824
4107
|
* never invoke a real package manager. Absent → the real `exec`-based runner.
|
|
2825
4108
|
*/
|
|
2826
4109
|
cliCommandRunner?: CommandRunner;
|
|
4110
|
+
/** TEST/COMPOSITION SEAM: prepared Images runtime generation for config transactions. */
|
|
4111
|
+
imageRuntimeConfig?: AdminApiDeps['imageRuntimeConfig'];
|
|
4112
|
+
/** TEST/COMPOSITION SEAM: metadata-only Images status reader. */
|
|
4113
|
+
imageRuntimeStatus?: AdminApiDeps['imageRuntimeStatus'];
|
|
4114
|
+
/** TEST/COMPOSITION SEAM: metadata-only successful Images config audit sink. */
|
|
4115
|
+
imageConfigAudit?: AdminApiDeps['imageConfigAudit'];
|
|
4116
|
+
/** TEST ONLY: deterministic Tier-A provider inside the production Images composition. */
|
|
4117
|
+
testOnlySyntheticVerifiedImageProvider?: SyntheticVerifiedImageProviderTestSeam;
|
|
4118
|
+
/** TEST SEAM: inject an atomic settings replacement fault. */
|
|
4119
|
+
settingsAtomicReplace?: (targetPath: string, contents: Uint8Array) => void;
|
|
2827
4120
|
}
|
|
2828
4121
|
/** The constructed daemon handles the CLI commands operate on. */
|
|
2829
4122
|
interface Daemon {
|
|
@@ -2832,6 +4125,25 @@ interface Daemon {
|
|
|
2832
4125
|
readonly llmConfig: ConfigFileProviderConfigSource;
|
|
2833
4126
|
readonly keyDb: JsonOutboundKeyDb;
|
|
2834
4127
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
4128
|
+
/** App-session extension-operation registry shared with the resident proxy. */
|
|
4129
|
+
readonly openAIOperationRegistry: OpenAIOperationRegistry;
|
|
4130
|
+
/**
|
|
4131
|
+
* The ONE search runtime for this daemon (plan 阶段5 §6.3). The same object
|
|
4132
|
+
* the Codex route, both managed frontends and the search doctor hold.
|
|
4133
|
+
*/
|
|
4134
|
+
readonly searchRuntime: SearchRuntime;
|
|
4135
|
+
/** Per-frontend search modes as loaded at bootstrap. */
|
|
4136
|
+
readonly searchFrontendModes: SearchFrontendModes;
|
|
4137
|
+
/** Stable Images forwarders and generation lifecycle owner for this app session. */
|
|
4138
|
+
readonly imageRuntimeManager: ImageRuntimeManager;
|
|
4139
|
+
/** Bounded process-local metadata aggregation shared by every runtime generation. */
|
|
4140
|
+
readonly imageObservability: ImageObservability;
|
|
4141
|
+
/** Startup reconciliation plus recurring bounded cleanup for Images state. */
|
|
4142
|
+
readonly imageCleanupService: ImageCleanupService;
|
|
4143
|
+
/** Local-only diagnostics plus the explicit consuming Images verifier. */
|
|
4144
|
+
readonly imageDoctor: ImageDoctorService;
|
|
4145
|
+
/** Generation-pinned hosted-image lease factory used by Native Responses. */
|
|
4146
|
+
readonly hostedImageContributionFactory: HostedImageContributionFactory;
|
|
2835
4147
|
readonly providerProxy: ProviderProxy;
|
|
2836
4148
|
readonly routeLeaseManager: RouteLeaseManager;
|
|
2837
4149
|
readonly outboundApiServer: OutboundApiServer;
|
|
@@ -2909,6 +4221,17 @@ interface Daemon {
|
|
|
2909
4221
|
* in cleanup.
|
|
2910
4222
|
*/
|
|
2911
4223
|
readonly auditPruneSweeper: AuditPruneSweeper;
|
|
4224
|
+
/**
|
|
4225
|
+
* Retention for RAW usage rows (rollups are kept forever). Armed by `start`;
|
|
4226
|
+
* `launch` leaves it off — a short-lived boot has no business pruning.
|
|
4227
|
+
*/
|
|
4228
|
+
readonly usagePruneSweeper: UsagePruneSweeper;
|
|
4229
|
+
/**
|
|
4230
|
+
* Fold a legacy flat `usage-events.jsonl` into day shards. MUST be awaited
|
|
4231
|
+
* before any listener binds: it moves files the query path reads, and a
|
|
4232
|
+
* request served mid-migration would see a partial store.
|
|
4233
|
+
*/
|
|
4234
|
+
readonly migrateUsageStore: () => Promise<UsageMigrationResult>;
|
|
2912
4235
|
/**
|
|
2913
4236
|
* Durable-first billing publisher (billing-event-stream) — appends each event
|
|
2914
4237
|
* to `billing/billing-YYYY-MM-DD.jsonl` FIRST, then best-effort POSTs it.
|
|
@@ -2925,11 +4248,6 @@ interface Daemon {
|
|
|
2925
4248
|
*/
|
|
2926
4249
|
readonly billingRetrySweeper: BillingRetrySweeper;
|
|
2927
4250
|
}
|
|
2928
|
-
/**
|
|
2929
|
-
* Construct the standalone daemon from a loaded config + on-disk paths. Does NOT
|
|
2930
|
-
* start the listeners — the `start` command awaits `providerProxy.start()` then
|
|
2931
|
-
* `outboundApiServer.applyConfig(...)`.
|
|
2932
|
-
*/
|
|
2933
4251
|
declare function buildDaemon(config: DaemonConfig, paths: DaemonPaths): Daemon;
|
|
2934
4252
|
/** Reset the core singletons (tests / teardown only). Re-exported for the suite.
|
|
2935
4253
|
*
|
|
@@ -3015,11 +4333,24 @@ declare function buildHealthReport(deps: HealthReportDeps): HealthReport;
|
|
|
3015
4333
|
* - SINK: always the console; PLUS an optional append-only file stream when
|
|
3016
4334
|
* `file` is set (lazy-open; a write/open error is swallowed → the daemon never
|
|
3017
4335
|
* crashes on a logging failure, it just falls back to the console).
|
|
4336
|
+
* - ROTATION: the file sink is size-capped (`maxFileBytes`, default 8 MB) and
|
|
4337
|
+
* keeps `maxFiles` generations (default 5) as `<file>.1` … `<file>.N`. An
|
|
4338
|
+
* UNBOUNDED append-only log is how a long-lived daemon quietly fills a disk,
|
|
4339
|
+
* so the cap is on by default rather than opt-in. Lines emitted mid-rotation
|
|
4340
|
+
* are queued (bounded) and flushed into the fresh generation, never dropped
|
|
4341
|
+
* silently unless the queue itself overflows.
|
|
3018
4342
|
*
|
|
3019
4343
|
* ZERO-REGRESSION DEFAULT: `new ConfigurableLogger()` (no config) = console +
|
|
3020
4344
|
* all levels + text = behaviorally byte-identical to the legacy `ConsoleLogger`
|
|
3021
4345
|
* (same `console` method per level, same `(message[, meta])` / error arg shape).
|
|
3022
4346
|
*
|
|
4347
|
+
* NOTE — the daemon no longer CONSTRUCTS it that way. `bootstrap.ts` defaults the
|
|
4348
|
+
* file sink on (`<configDir>/logs/daemon.log`, level `info`, format `json`)
|
|
4349
|
+
* whenever the config omits it: the desktop app discards the daemon's stdout, so
|
|
4350
|
+
* a console-only logger meant a crash left no evidence at all. The unconfigured
|
|
4351
|
+
* CONSTRUCTOR default above is still console-only — only the daemon's wiring
|
|
4352
|
+
* changed.
|
|
4353
|
+
*
|
|
3023
4354
|
* CAUTION (per the #3 host:port-only-logging precedent): the JSON serializer
|
|
3024
4355
|
* reduces an `Error` to `{ message, stack }` and spreads a plain `meta` object,
|
|
3025
4356
|
* but it is NOT a secret redactor — call sites remain responsible for not passing
|
|
@@ -3032,8 +4363,16 @@ declare class ConfigurableLogger implements Logger {
|
|
|
3032
4363
|
private readonly threshold;
|
|
3033
4364
|
private readonly format;
|
|
3034
4365
|
private readonly filePath;
|
|
4366
|
+
private readonly maxFileBytes;
|
|
4367
|
+
private readonly maxFiles;
|
|
3035
4368
|
private fileStream;
|
|
3036
4369
|
private fileDisabled;
|
|
4370
|
+
/** Bytes in the CURRENT generation — seeded from the file on open. */
|
|
4371
|
+
private fileBytes;
|
|
4372
|
+
/** True from the moment a rotation starts until the fresh stream is live. */
|
|
4373
|
+
private rotating;
|
|
4374
|
+
/** Lines emitted while `rotating`; flushed into the new generation. */
|
|
4375
|
+
private rotateQueue;
|
|
3037
4376
|
constructor(cfg?: LoggingConfig);
|
|
3038
4377
|
info(message: string, meta?: Record<string, unknown> | Error | object): void;
|
|
3039
4378
|
warn(message: string, meta?: Record<string, unknown> | Error | object): void;
|
|
@@ -3053,7 +4392,22 @@ declare class ConfigurableLogger implements Logger {
|
|
|
3053
4392
|
private writeConsole;
|
|
3054
4393
|
/** Append one line to the file sink; a failure disables the sink (swallowed). */
|
|
3055
4394
|
private writeFile;
|
|
3056
|
-
/**
|
|
4395
|
+
/** Write ONE prepared line to the live generation, rotating once it is full. */
|
|
4396
|
+
private emitLine;
|
|
4397
|
+
/**
|
|
4398
|
+
* Close the full generation, shift `<file>.N-1` → `<file>.N` (oldest dropped),
|
|
4399
|
+
* then reopen. Renames run in the `end()` callback so nothing still buffered in
|
|
4400
|
+
* the stream lands in the wrong generation. Any failure disables the sink
|
|
4401
|
+
* rather than throwing — the console sink is unaffected either way.
|
|
4402
|
+
*/
|
|
4403
|
+
private rotate;
|
|
4404
|
+
/** `<file>.N` unlinked, `<file>.k` → `<file>.k+1`, `<file>` → `<file>.1`. */
|
|
4405
|
+
private shiftGenerations;
|
|
4406
|
+
/**
|
|
4407
|
+
* Lazily open the append-only file stream; disable the sink on any error. The
|
|
4408
|
+
* byte counter is seeded from the file already on disk so a restart cannot
|
|
4409
|
+
* reset an almost-full generation back to zero and blow past the cap.
|
|
4410
|
+
*/
|
|
3057
4411
|
private getFileStream;
|
|
3058
4412
|
private consoleFn;
|
|
3059
4413
|
/** `{ ts, level, msg, ...meta }` (+ `error` when present) as a single line. */
|
|
@@ -3143,4 +4497,4 @@ declare function mapCcrToOmnicross(ccr: CcrConfig): {
|
|
|
3143
4497
|
notes: string[];
|
|
3144
4498
|
};
|
|
3145
4499
|
|
|
3146
|
-
export { type AdminApiDeps, AdminServer, type AdminServerDeps, type AdminServerStatus, type CcrConfig, type CcrProvider, type CcrRouter, ConfigFileProviderConfigSource, ConfigurableLogger, ConsoleLogger, DEFAULT_ADMIN_PORT, type Daemon, type DaemonAdminConfig, type DaemonApiFormat, type DaemonConfig, type DaemonPaths, type DaemonProviderConfig, type HealthReportDeps, JsonApiServerSettingsStore, JsonOutboundKeyDb, JsonSubscriptionCredentialStore, type ResolvedAdminConfig, buildDaemon, buildHealthReport, handleAdminApi, inferApiFormat, loadConfig, mapCcrToOmnicross, parseCcrConfig, resetDaemonSingletonsForTests, resolveAdminConfig, saveConfig, validateConfig };
|
|
4500
|
+
export { type AdminApiDeps, AdminServer, type AdminServerDeps, type AdminServerStatus, type CcrConfig, type CcrProvider, type CcrRouter, ConfigFileProviderConfigSource, ConfigurableLogger, ConsoleLogger, DEFAULT_ADMIN_PORT, type Daemon, type DaemonAdminConfig, type DaemonApiFormat, type DaemonConfig, type DaemonPaths, type DaemonProviderConfig, type HealthReportDeps, type HostedImageContributionFactory, type HostedImageRuntimeGenerationLease, type ImageApiMetricDimensions, type ImageApiMetricSnapshot, type ImageExecutionMetricDimensions, type ImageExecutionMetricSnapshot, type ImageHistogramSnapshot, ImageObservability, type ImageObservabilityOptions, type ImageObservabilitySnapshot, type ImageRuntimeCapabilityInspection, type ImageRuntimeGenerationFactoryOptions, type ImageRuntimeGenerationSharedStorage, ImageRuntimeManager, type ImageRuntimeManagerStatus, type ImageRuntimeMetadataObservability, type ImageRuntimeResourceStatus, type ImageRuntimeSafeUnavailableReason, JsonApiServerSettingsStore, JsonOutboundKeyDb, JsonSubscriptionCredentialStore, type PreparedImageRuntimeChange, type PreparedImageRuntimeGeneration, type ProductionImageRuntimeComponents, type ProductionImageRuntimeGeneration, type ResolvedAdminConfig, type TrustedImageApiRuntimeResolver, type TrustedImageApiRuntimeResolverOptions, buildDaemon, buildHealthReport, createHostedImageContributionFactory, createImageRuntimeGeneration, createTrustedImageApiRuntimeResolver, handleAdminApi, inferApiFormat, loadConfig, mapCcrToOmnicross, parseCcrConfig, resetDaemonSingletonsForTests, resolveAdminConfig, saveConfig, validateConfig };
|