@omnicross/contracts 0.1.2 → 0.1.4

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.
Files changed (47) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +15 -15
  3. package/dist/account-tokens-types.d.cts +157 -1
  4. package/dist/account-tokens-types.d.ts +157 -1
  5. package/dist/audit-types.cjs +36 -0
  6. package/dist/audit-types.d.cts +98 -0
  7. package/dist/audit-types.d.ts +98 -0
  8. package/dist/audit-types.js +11 -0
  9. package/dist/billing-types.cjs +33 -0
  10. package/dist/billing-types.d.cts +98 -0
  11. package/dist/billing-types.d.ts +98 -0
  12. package/dist/billing-types.js +8 -0
  13. package/dist/canonical-models.d.cts +1 -1
  14. package/dist/canonical-models.d.ts +1 -1
  15. package/dist/endpoint-resolver.d.cts +1 -1
  16. package/dist/endpoint-resolver.d.ts +1 -1
  17. package/dist/health-logging-types.cjs +32 -0
  18. package/dist/health-logging-types.d.cts +68 -0
  19. package/dist/health-logging-types.d.ts +68 -0
  20. package/dist/health-logging-types.js +7 -0
  21. package/dist/index.cjs +63 -0
  22. package/dist/index.d.cts +9 -3
  23. package/dist/index.d.ts +9 -3
  24. package/dist/index.js +55 -0
  25. package/dist/{llm-config-D1jKQLVp.d.ts → llm-config-CKOaFFdy.d.ts} +8 -1
  26. package/dist/{llm-config-CQjOimv2.d.cts → llm-config-DeWNx1ig.d.cts} +8 -1
  27. package/dist/llm-config.d.cts +1 -1
  28. package/dist/llm-config.d.ts +1 -1
  29. package/dist/provider-presets/index.d.cts +2 -2
  30. package/dist/provider-presets/index.d.ts +2 -2
  31. package/dist/subscription-model-catalog.cjs +40 -0
  32. package/dist/subscription-model-catalog.d.cts +34 -0
  33. package/dist/subscription-model-catalog.d.ts +34 -0
  34. package/dist/subscription-model-catalog.js +14 -0
  35. package/dist/thinking-config.d.cts +1 -1
  36. package/dist/thinking-config.d.ts +1 -1
  37. package/dist/usage-stats-types.d.cts +22 -1
  38. package/dist/usage-stats-types.d.ts +22 -1
  39. package/dist/voucher-types.cjs +32 -0
  40. package/dist/voucher-types.d.cts +153 -0
  41. package/dist/voucher-types.d.ts +153 -0
  42. package/dist/voucher-types.js +7 -0
  43. package/dist/webhook-types.cjs +40 -0
  44. package/dist/webhook-types.d.cts +122 -0
  45. package/dist/webhook-types.d.ts +122 -0
  46. package/dist/webhook-types.js +14 -0
  47. package/package.json +156 -126
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Sayo
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sayo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # @omnicross/contracts
2
-
3
- Dependency-light, host-agnostic contract types + runtime-value helpers shared across the omnicross packages: LLM config, completion types + message blocks, provider presets, thinking config, usage, and subscription/account-token types.
4
-
5
- Consumed via subpaths to keep the dependency graph tight, e.g. `@omnicross/contracts/llm-config`, `@omnicross/contracts/provider-presets`, `@omnicross/contracts/completion-types`.
6
-
7
- Part of the [omnicross](https://github.com/Dumoedss/omnicross) monorepo — see the root README for the full overview.
8
-
9
- ```bash
10
- npm install @omnicross/contracts
11
- ```
12
-
13
- ## License
14
-
15
- [MIT](LICENSE)
1
+ # @omnicross/contracts
2
+
3
+ Dependency-light, host-agnostic contract types + runtime-value helpers shared across the omnicross packages: LLM config, completion types + message blocks, provider presets, thinking config, usage, and subscription/account-token types.
4
+
5
+ Consumed via subpaths to keep the dependency graph tight, e.g. `@omnicross/contracts/llm-config`, `@omnicross/contracts/provider-presets`, `@omnicross/contracts/completion-types`.
6
+
7
+ Part of the [omnicross](https://github.com/Dumoedss/omnicross) monorepo — see the root README for the full overview.
8
+
9
+ ```bash
10
+ npm install @omnicross/contracts
11
+ ```
12
+
13
+ ## License
14
+
15
+ [MIT](LICENSE)
@@ -9,6 +9,45 @@ import { OpenCodeGoTokenConfig } from './subscription-types.cjs';
9
9
  * sanitized shapes, and the OAuth exchange request types.
10
10
  */
11
11
 
12
+ /**
13
+ * Upstream proxy descriptor (upstream-proxy). Routes an outbound upstream call
14
+ * through an http/https or socks5 proxy. Two interchangeable shapes:
15
+ * - `{ url }` — a full proxy URL, e.g. `http://user:pass@host:1080` or
16
+ * `socks5://host:1080` (userinfo carries basic-auth).
17
+ * - structured — an explicit `{ type, host, port, username?, password? }`.
18
+ *
19
+ * `username`/`password` are SECRETS: encrypted at rest via the same envelope as
20
+ * other credentials, masked in every sanitized/admin view, and never logged
21
+ * (logs carry at most `host:port`). Additive everywhere it appears — absent ⇒ a
22
+ * direct (non-proxied) call, byte-identical to before proxy support.
23
+ */
24
+ type ProxyConfig = {
25
+ url: string;
26
+ } | {
27
+ type: 'http' | 'https' | 'socks5';
28
+ host: string;
29
+ port: number;
30
+ username?: string;
31
+ password?: string;
32
+ };
33
+ /**
34
+ * Persisted per-account client identity (subscription-client-fingerprint #7, P2).
35
+ * The frozen fingerprint headers a real Claude Code client sent for this account,
36
+ * captured + replayed so relayed traffic presents a stable identity across
37
+ * restarts. NON-secret metadata: it holds ONLY whitelisted fingerprint headers
38
+ * (`x-stainless-*` / user-agent / anthropic-beta / x-app / CC headers) — NEVER
39
+ * `authorization` / `x-api-key` / `cookie` (excluded at capture AND at
40
+ * store-normalize). Additive + OPTIONAL — an existing `tokens.json` without it
41
+ * parses unchanged (the account re-captures from a real client). Because it is
42
+ * non-secret it lives on the entry OUTSIDE the encrypted `tokens` block and is
43
+ * not walked by the secrets encryptor.
44
+ */
45
+ type AccountClientIdentity = {
46
+ /** The frozen fingerprint headers (lowercased keys; token/secret excluded). */
47
+ headers: Record<string, string>;
48
+ /** Epoch ms of the freeze / last TTL refresh. */
49
+ capturedAt: number;
50
+ };
12
51
  /**
13
52
  * Authorization method (general)
14
53
  */
@@ -102,6 +141,57 @@ type SubscriptionAccountEntry<TConfig> = {
102
141
  label?: string;
103
142
  /** ISO creation timestamp. */
104
143
  createdAt?: string;
144
+ /**
145
+ * Scheduling precedence in the account pool (subscription-account-scheduling).
146
+ * Lower = higher precedence; default `50` when absent (CRS `parseInt(x,10) || 50`
147
+ * parity). OPTIONAL — an existing `tokens.json` without it parses unchanged and
148
+ * every account defaults to 50.
149
+ */
150
+ priority?: number;
151
+ /**
152
+ * ISO timestamp of the last time this account was selected to serve a request
153
+ * (subscription-account-scheduling LRU tie-break input). OPTIONAL, best-effort
154
+ * throttled persist — the selector's in-memory overlay is the authoritative live
155
+ * value; an account without it sorts as least-recently-used (timestamp `0`).
156
+ */
157
+ lastUsedAt?: string;
158
+ /**
159
+ * Per-account upstream proxy override (upstream-proxy). When set, this
160
+ * account's relay + OAuth-refresh traffic is routed through this proxy,
161
+ * WINNING over the per-provider and global proxy layers. OPTIONAL — an
162
+ * existing `tokens.json` without it parses unchanged (no proxy → direct). Its
163
+ * `password` is a secret: encrypted at rest by the tokens `SecretBox` walker
164
+ * and masked in the sanitized view.
165
+ */
166
+ proxy?: ProxyConfig;
167
+ /**
168
+ * Per-account model support + logical→actual remap (subscription-account-model-map).
169
+ * CRS dual-format, OPTIONAL — an existing `tokens.json` without it parses
170
+ * unchanged (the account supports every model and never remaps, byte-identical
171
+ * to before this change):
172
+ * - **array** `["a","b"]` — an ALLOW-LIST: the account supports ONLY these
173
+ * logical models (skip-only, no remap). In a ≥2-account pool the account is
174
+ * routed AROUND for any other model.
175
+ * - **object** `{ "a": "X", "b": "Y" }` — the keys are the same allow-list AND
176
+ * each value is the account's ACTUAL upstream model, so a selected account
177
+ * remaps the logical model to its actual model on the outbound request.
178
+ *
179
+ * Model-support filtering only applies when the provider has ≥2 accounts (the
180
+ * same gate as account health) — a sole account is never model-gated
181
+ * (never-strand; the upstream stays authoritative). A sole account that must
182
+ * serve a logical model AS a different actual model uses the OBJECT map (remap),
183
+ * not skip.
184
+ */
185
+ supportedModels?: string[] | Record<string, string>;
186
+ /**
187
+ * Persisted per-account client fingerprint identity (subscription-client-
188
+ * fingerprint #7, P2). OPTIONAL, additive, NON-secret metadata (kept OUTSIDE the
189
+ * encrypted `tokens` block) — an existing `tokens.json` without it parses
190
+ * unchanged. Written through by the daemon on a first-seen freeze / TTL refresh;
191
+ * seeded back into the in-memory identity store at boot so a claude account's
192
+ * replayed identity survives restart.
193
+ */
194
+ identity?: AccountClientIdentity;
105
195
  /** The provider's existing token config, verbatim. */
106
196
  tokens: TConfig;
107
197
  };
@@ -128,6 +218,22 @@ type AccountTokensConfig = {
128
218
  activeOpencodegoAccountId?: string;
129
219
  updatedAt: string;
130
220
  };
221
+ /**
222
+ * Secret-free view of a per-account/global/provider proxy (upstream-proxy). The
223
+ * password is NEVER carried — only a `hasPassword` presence flag plus a
224
+ * display-safe `host:port` endpoint (userinfo stripped). Rendered in the admin
225
+ * accounts view.
226
+ */
227
+ type SanitizedProxyConfig = {
228
+ /** `'url'` when configured via a full URL, else the structured proxy type. */
229
+ kind: 'url' | 'http' | 'https' | 'socks5';
230
+ /** Display-safe `host:port` (parsed from a url form; userinfo stripped). */
231
+ endpoint?: string;
232
+ /** Optional non-secret username (for display); the password is never returned. */
233
+ username?: string;
234
+ /** Whether a proxy password is set. The password value itself never leaves. */
235
+ hasPassword: boolean;
236
+ };
131
237
  /**
132
238
  * Sanitized view of a single subscription account (frontend display).
133
239
  * NEVER carries raw token material (no accessToken/refreshToken/idToken/apiKey).
@@ -143,12 +249,62 @@ type SubscriptionAccountSanitized = {
143
249
  isSetupToken?: boolean;
144
250
  hasAccessToken: boolean;
145
251
  isActive: boolean;
252
+ /**
253
+ * Scheduling precedence (subscription-account-scheduling) — editable in the
254
+ * admin accounts view so an operator can order a pool. Absent ⇒ default 50.
255
+ */
256
+ priority?: number;
257
+ /**
258
+ * ISO timestamp of the last scheduler selection (display-only in the admin
259
+ * accounts view). Absent ⇒ never selected (or the best-effort persist has not
260
+ * yet flushed).
261
+ */
262
+ lastUsedAt?: string;
146
263
  /**
147
264
  * Credential-sync warning for this account (external-cli-sync). Carries the
148
265
  * persisted code when one was recorded by a failed refresh, plus the
149
266
  * list-time computed codes (`external-divergent` / `duplicate-token`).
150
267
  */
151
268
  syncWarning?: SyncWarningCode;
269
+ /**
270
+ * Live scheduling-health state (subscription-account-health) — in-memory, never
271
+ * persisted. Absent / `'healthy'` ⇒ eligible; the rest mean the account is
272
+ * currently excluded from the pool (multi-account) or would surface the
273
+ * upstream's error (single-account). Secret-free.
274
+ */
275
+ health?: 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'blocked';
276
+ /**
277
+ * ISO instant the current health cooldown elapses (absent for healthy /
278
+ * permanently-blocked). Lets the admin view render "rate-limited until …".
279
+ */
280
+ cooldownUntil?: string;
281
+ /**
282
+ * Secret-free view of this account's proxy override (upstream-proxy). Absent ⇒
283
+ * no per-account proxy configured. The password is masked to a `hasPassword`
284
+ * flag — never returned.
285
+ */
286
+ proxy?: SanitizedProxyConfig;
287
+ /**
288
+ * Per-account model support / logical→actual remap (subscription-account-model-map)
289
+ * — editable in the admin accounts view. Carried verbatim (secret-free — model
290
+ * ids are not token material): an array allow-list or an object logical→actual
291
+ * map. Absent ⇒ the account supports every model with no remap.
292
+ */
293
+ supportedModels?: string[] | Record<string, string>;
294
+ /**
295
+ * COARSE client-fingerprint status (subscription-client-fingerprint #7, D7) —
296
+ * whether THIS account has a captured/frozen client identity in the in-memory
297
+ * store. Present only when fingerprint replay is ENABLED (else absent ⇒ the UI
298
+ * shows nothing). Secret-free by construction: it is a BOOLEAN only — the raw
299
+ * captured headers are NEVER surfaced here (nor in any admin view).
300
+ */
301
+ identityCaptured?: boolean;
302
+ /**
303
+ * ISO instant this account's fingerprint identity was frozen / last TTL-refreshed
304
+ * (subscription-client-fingerprint #7, D7). Present only alongside
305
+ * `identityCaptured === true`. Coarse timestamp only — never the headers.
306
+ */
307
+ identityCapturedAt?: string;
152
308
  };
153
309
  /**
154
310
  * OAuth authorization parameters
@@ -167,4 +323,4 @@ type TokenExchangeRequest = {
167
323
  state: string;
168
324
  };
169
325
 
170
- export type { AccountTokensConfig, AuthMethod, ClaudeAuthMethod, ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, OAuthParams, SubscriptionAccountEntry, SubscriptionAccountSanitized, SubscriptionLevel, SyncWarningCode, TokenExchangeRequest, TokenStatus };
326
+ export type { AccountClientIdentity, AccountTokensConfig, AuthMethod, ClaudeAuthMethod, ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, OAuthParams, ProxyConfig, SanitizedProxyConfig, SubscriptionAccountEntry, SubscriptionAccountSanitized, SubscriptionLevel, SyncWarningCode, TokenExchangeRequest, TokenStatus };
@@ -9,6 +9,45 @@ import { OpenCodeGoTokenConfig } from './subscription-types.js';
9
9
  * sanitized shapes, and the OAuth exchange request types.
10
10
  */
11
11
 
12
+ /**
13
+ * Upstream proxy descriptor (upstream-proxy). Routes an outbound upstream call
14
+ * through an http/https or socks5 proxy. Two interchangeable shapes:
15
+ * - `{ url }` — a full proxy URL, e.g. `http://user:pass@host:1080` or
16
+ * `socks5://host:1080` (userinfo carries basic-auth).
17
+ * - structured — an explicit `{ type, host, port, username?, password? }`.
18
+ *
19
+ * `username`/`password` are SECRETS: encrypted at rest via the same envelope as
20
+ * other credentials, masked in every sanitized/admin view, and never logged
21
+ * (logs carry at most `host:port`). Additive everywhere it appears — absent ⇒ a
22
+ * direct (non-proxied) call, byte-identical to before proxy support.
23
+ */
24
+ type ProxyConfig = {
25
+ url: string;
26
+ } | {
27
+ type: 'http' | 'https' | 'socks5';
28
+ host: string;
29
+ port: number;
30
+ username?: string;
31
+ password?: string;
32
+ };
33
+ /**
34
+ * Persisted per-account client identity (subscription-client-fingerprint #7, P2).
35
+ * The frozen fingerprint headers a real Claude Code client sent for this account,
36
+ * captured + replayed so relayed traffic presents a stable identity across
37
+ * restarts. NON-secret metadata: it holds ONLY whitelisted fingerprint headers
38
+ * (`x-stainless-*` / user-agent / anthropic-beta / x-app / CC headers) — NEVER
39
+ * `authorization` / `x-api-key` / `cookie` (excluded at capture AND at
40
+ * store-normalize). Additive + OPTIONAL — an existing `tokens.json` without it
41
+ * parses unchanged (the account re-captures from a real client). Because it is
42
+ * non-secret it lives on the entry OUTSIDE the encrypted `tokens` block and is
43
+ * not walked by the secrets encryptor.
44
+ */
45
+ type AccountClientIdentity = {
46
+ /** The frozen fingerprint headers (lowercased keys; token/secret excluded). */
47
+ headers: Record<string, string>;
48
+ /** Epoch ms of the freeze / last TTL refresh. */
49
+ capturedAt: number;
50
+ };
12
51
  /**
13
52
  * Authorization method (general)
14
53
  */
@@ -102,6 +141,57 @@ type SubscriptionAccountEntry<TConfig> = {
102
141
  label?: string;
103
142
  /** ISO creation timestamp. */
104
143
  createdAt?: string;
144
+ /**
145
+ * Scheduling precedence in the account pool (subscription-account-scheduling).
146
+ * Lower = higher precedence; default `50` when absent (CRS `parseInt(x,10) || 50`
147
+ * parity). OPTIONAL — an existing `tokens.json` without it parses unchanged and
148
+ * every account defaults to 50.
149
+ */
150
+ priority?: number;
151
+ /**
152
+ * ISO timestamp of the last time this account was selected to serve a request
153
+ * (subscription-account-scheduling LRU tie-break input). OPTIONAL, best-effort
154
+ * throttled persist — the selector's in-memory overlay is the authoritative live
155
+ * value; an account without it sorts as least-recently-used (timestamp `0`).
156
+ */
157
+ lastUsedAt?: string;
158
+ /**
159
+ * Per-account upstream proxy override (upstream-proxy). When set, this
160
+ * account's relay + OAuth-refresh traffic is routed through this proxy,
161
+ * WINNING over the per-provider and global proxy layers. OPTIONAL — an
162
+ * existing `tokens.json` without it parses unchanged (no proxy → direct). Its
163
+ * `password` is a secret: encrypted at rest by the tokens `SecretBox` walker
164
+ * and masked in the sanitized view.
165
+ */
166
+ proxy?: ProxyConfig;
167
+ /**
168
+ * Per-account model support + logical→actual remap (subscription-account-model-map).
169
+ * CRS dual-format, OPTIONAL — an existing `tokens.json` without it parses
170
+ * unchanged (the account supports every model and never remaps, byte-identical
171
+ * to before this change):
172
+ * - **array** `["a","b"]` — an ALLOW-LIST: the account supports ONLY these
173
+ * logical models (skip-only, no remap). In a ≥2-account pool the account is
174
+ * routed AROUND for any other model.
175
+ * - **object** `{ "a": "X", "b": "Y" }` — the keys are the same allow-list AND
176
+ * each value is the account's ACTUAL upstream model, so a selected account
177
+ * remaps the logical model to its actual model on the outbound request.
178
+ *
179
+ * Model-support filtering only applies when the provider has ≥2 accounts (the
180
+ * same gate as account health) — a sole account is never model-gated
181
+ * (never-strand; the upstream stays authoritative). A sole account that must
182
+ * serve a logical model AS a different actual model uses the OBJECT map (remap),
183
+ * not skip.
184
+ */
185
+ supportedModels?: string[] | Record<string, string>;
186
+ /**
187
+ * Persisted per-account client fingerprint identity (subscription-client-
188
+ * fingerprint #7, P2). OPTIONAL, additive, NON-secret metadata (kept OUTSIDE the
189
+ * encrypted `tokens` block) — an existing `tokens.json` without it parses
190
+ * unchanged. Written through by the daemon on a first-seen freeze / TTL refresh;
191
+ * seeded back into the in-memory identity store at boot so a claude account's
192
+ * replayed identity survives restart.
193
+ */
194
+ identity?: AccountClientIdentity;
105
195
  /** The provider's existing token config, verbatim. */
106
196
  tokens: TConfig;
107
197
  };
@@ -128,6 +218,22 @@ type AccountTokensConfig = {
128
218
  activeOpencodegoAccountId?: string;
129
219
  updatedAt: string;
130
220
  };
221
+ /**
222
+ * Secret-free view of a per-account/global/provider proxy (upstream-proxy). The
223
+ * password is NEVER carried — only a `hasPassword` presence flag plus a
224
+ * display-safe `host:port` endpoint (userinfo stripped). Rendered in the admin
225
+ * accounts view.
226
+ */
227
+ type SanitizedProxyConfig = {
228
+ /** `'url'` when configured via a full URL, else the structured proxy type. */
229
+ kind: 'url' | 'http' | 'https' | 'socks5';
230
+ /** Display-safe `host:port` (parsed from a url form; userinfo stripped). */
231
+ endpoint?: string;
232
+ /** Optional non-secret username (for display); the password is never returned. */
233
+ username?: string;
234
+ /** Whether a proxy password is set. The password value itself never leaves. */
235
+ hasPassword: boolean;
236
+ };
131
237
  /**
132
238
  * Sanitized view of a single subscription account (frontend display).
133
239
  * NEVER carries raw token material (no accessToken/refreshToken/idToken/apiKey).
@@ -143,12 +249,62 @@ type SubscriptionAccountSanitized = {
143
249
  isSetupToken?: boolean;
144
250
  hasAccessToken: boolean;
145
251
  isActive: boolean;
252
+ /**
253
+ * Scheduling precedence (subscription-account-scheduling) — editable in the
254
+ * admin accounts view so an operator can order a pool. Absent ⇒ default 50.
255
+ */
256
+ priority?: number;
257
+ /**
258
+ * ISO timestamp of the last scheduler selection (display-only in the admin
259
+ * accounts view). Absent ⇒ never selected (or the best-effort persist has not
260
+ * yet flushed).
261
+ */
262
+ lastUsedAt?: string;
146
263
  /**
147
264
  * Credential-sync warning for this account (external-cli-sync). Carries the
148
265
  * persisted code when one was recorded by a failed refresh, plus the
149
266
  * list-time computed codes (`external-divergent` / `duplicate-token`).
150
267
  */
151
268
  syncWarning?: SyncWarningCode;
269
+ /**
270
+ * Live scheduling-health state (subscription-account-health) — in-memory, never
271
+ * persisted. Absent / `'healthy'` ⇒ eligible; the rest mean the account is
272
+ * currently excluded from the pool (multi-account) or would surface the
273
+ * upstream's error (single-account). Secret-free.
274
+ */
275
+ health?: 'healthy' | 'rate_limited' | 'overloaded' | 'transient' | 'blocked';
276
+ /**
277
+ * ISO instant the current health cooldown elapses (absent for healthy /
278
+ * permanently-blocked). Lets the admin view render "rate-limited until …".
279
+ */
280
+ cooldownUntil?: string;
281
+ /**
282
+ * Secret-free view of this account's proxy override (upstream-proxy). Absent ⇒
283
+ * no per-account proxy configured. The password is masked to a `hasPassword`
284
+ * flag — never returned.
285
+ */
286
+ proxy?: SanitizedProxyConfig;
287
+ /**
288
+ * Per-account model support / logical→actual remap (subscription-account-model-map)
289
+ * — editable in the admin accounts view. Carried verbatim (secret-free — model
290
+ * ids are not token material): an array allow-list or an object logical→actual
291
+ * map. Absent ⇒ the account supports every model with no remap.
292
+ */
293
+ supportedModels?: string[] | Record<string, string>;
294
+ /**
295
+ * COARSE client-fingerprint status (subscription-client-fingerprint #7, D7) —
296
+ * whether THIS account has a captured/frozen client identity in the in-memory
297
+ * store. Present only when fingerprint replay is ENABLED (else absent ⇒ the UI
298
+ * shows nothing). Secret-free by construction: it is a BOOLEAN only — the raw
299
+ * captured headers are NEVER surfaced here (nor in any admin view).
300
+ */
301
+ identityCaptured?: boolean;
302
+ /**
303
+ * ISO instant this account's fingerprint identity was frozen / last TTL-refreshed
304
+ * (subscription-client-fingerprint #7, D7). Present only alongside
305
+ * `identityCaptured === true`. Coarse timestamp only — never the headers.
306
+ */
307
+ identityCapturedAt?: string;
152
308
  };
153
309
  /**
154
310
  * OAuth authorization parameters
@@ -167,4 +323,4 @@ type TokenExchangeRequest = {
167
323
  state: string;
168
324
  };
169
325
 
170
- export type { AccountTokensConfig, AuthMethod, ClaudeAuthMethod, ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, OAuthParams, SubscriptionAccountEntry, SubscriptionAccountSanitized, SubscriptionLevel, SyncWarningCode, TokenExchangeRequest, TokenStatus };
326
+ export type { AccountClientIdentity, AccountTokensConfig, AuthMethod, ClaudeAuthMethod, ClaudeTokenConfig, CodexTokenConfig, GeminiTokenConfig, OAuthParams, ProxyConfig, SanitizedProxyConfig, SubscriptionAccountEntry, SubscriptionAccountSanitized, SubscriptionLevel, SyncWarningCode, TokenExchangeRequest, TokenStatus };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/audit-types.ts
21
+ var audit_types_exports = {};
22
+ __export(audit_types_exports, {
23
+ DEFAULT_AUDIT_CONFIG: () => DEFAULT_AUDIT_CONFIG
24
+ });
25
+ module.exports = __toCommonJS(audit_types_exports);
26
+ var DEFAULT_AUDIT_CONFIG = {
27
+ enabled: false,
28
+ captureBodies: false,
29
+ maxBodyBytes: 8192,
30
+ retentionDays: 7,
31
+ trustForwardedFor: false
32
+ };
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ DEFAULT_AUDIT_CONFIG
36
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Request-audit contracts (request-audit-log, design D1/D2).
3
+ *
4
+ * Two dependency-light shapes shared across the `@omnicross/*` packages:
5
+ * - `AuditRecord` — the FROZEN per-request audit entry. It carries request
6
+ * METADATA (who/where/when/status/latency/model) plus, ONLY when body capture
7
+ * is explicitly enabled, a redacted+truncated request/response body snapshot.
8
+ * It is SECRET-FREE BY CONSTRUCTION: it holds the outbound key ID (NEVER the
9
+ * key material/hash), the client IP + user-agent (PII, hence the whole store
10
+ * is authed-only + TTL-pruned), and NEVER a token, Authorization header, or
11
+ * api-key header value (request headers are NEVER captured). A secret-scan
12
+ * test asserts no key/token pattern survives in a written record.
13
+ * - `AuditConfig` — the `audit` config segment. Two independent switches:
14
+ * `enabled` (record metadata) and `captureBodies` (the sensitive second
15
+ * opt-in — record bodies too), both default OFF (zero regression).
16
+ *
17
+ * @module audit-types
18
+ */
19
+ /**
20
+ * One per-request audit entry (design D1). The metadata fields are recorded
21
+ * whenever audit is `enabled`; the two body snapshots are present ONLY when
22
+ * `captureBodies` is ALSO on, and always after truncation + redaction. NO field
23
+ * ever holds key material, an upstream token, or an Authorization/api-key header.
24
+ */
25
+ interface AuditRecord {
26
+ /** Unique record id (a generated request id — NOT any secret). */
27
+ id: string;
28
+ /** Epoch ms the request was captured. */
29
+ ts: number;
30
+ /** Outbound key id (attribution) — NEVER the key secret/hash. Null when unauthenticated. */
31
+ keyId?: string | null;
32
+ /** Client IP (PII). Socket address by default; a trusted forwarded header only when configured. */
33
+ ip?: string;
34
+ /** Client user-agent (PII). */
35
+ ua?: string;
36
+ /** HTTP method. */
37
+ method: string;
38
+ /** Request path (query string dropped so no secret query param is stored). */
39
+ path: string;
40
+ /** Resolved upstream model. */
41
+ model?: string;
42
+ /** Upstream provider id (or `'byo'`). */
43
+ provider?: string;
44
+ /** HTTP status the client received. */
45
+ status: number;
46
+ /** End-to-end latency (ms). */
47
+ latencyMs: number;
48
+ /** Prompt-side token count (present only when the host correlates usage). */
49
+ inputTokens?: number;
50
+ /** Completion-side token count (present only when the host correlates usage). */
51
+ outputTokens?: number;
52
+ /** Cost in USD (present only when the host correlates usage). */
53
+ costUsd?: number;
54
+ /** Sanitized error message (present only on a failed relay). */
55
+ error?: string;
56
+ /**
57
+ * Request body snapshot — present ONLY when `captureBodies`, truncated to the
58
+ * configured cap, and ALWAYS run through the secret-redaction pass first.
59
+ */
60
+ requestBody?: string;
61
+ /**
62
+ * Response body snapshot — present ONLY when `captureBodies` AND the response
63
+ * was NON-streaming (a streaming response records metadata only), truncated +
64
+ * redacted like `requestBody`.
65
+ */
66
+ responseBody?: string;
67
+ }
68
+ /**
69
+ * The `audit` config segment (design D2), normalized like `accountHealth`.
70
+ * Absent/`enabled:false` ⇒ no sink wired + no capture ⇒ byte-identical zero
71
+ * regression. `captureBodies` is a SEPARATE, sensitive opt-in that does nothing
72
+ * unless `enabled` is also on.
73
+ */
74
+ interface AuditConfig {
75
+ /** Master switch; default FALSE (zero regression). */
76
+ enabled: boolean;
77
+ /** Capture request/response bodies too (redacted+truncated); default FALSE. */
78
+ captureBodies: boolean;
79
+ /** Per-body truncation cap in bytes; default 8192, clamped. */
80
+ maxBodyBytes: number;
81
+ /** TTL retention in days; default 7, clamped `[1, 365]`. */
82
+ retentionDays: number;
83
+ /**
84
+ * Trust the `X-Forwarded-For` header for the client IP (LEAD OQ1 anti-spoof).
85
+ * Default FALSE — the socket remote address is authoritative. Only set true
86
+ * behind a trusted reverse proxy; a client-supplied XFF is NEVER trusted by
87
+ * default.
88
+ */
89
+ trustForwardedFor: boolean;
90
+ }
91
+ /** Frozen defaults for the `audit` segment (SSOT). */
92
+ declare const DEFAULT_AUDIT_CONFIG: AuditConfig;
93
+ /** One page of audit records the authed admin query returns (newest first). */
94
+ interface AuditQueryResult {
95
+ records: AuditRecord[];
96
+ }
97
+
98
+ export { type AuditConfig, type AuditQueryResult, type AuditRecord, DEFAULT_AUDIT_CONFIG };