@modelprofile.com/authswitch 6.4.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/authority-contract.d.ts +302 -6
- package/dist_ts/authority-contract.js +1 -1
- package/dist_ts/authority-runtime-contract.d.ts +15 -0
- package/dist_ts/authorityrehearsal.child.d.ts +1 -0
- package/dist_ts/authorityrehearsal.child.js +395 -0
- package/dist_ts/classes.accountlist.js +4 -3
- package/dist_ts/classes.authoritybackup.d.ts +134 -0
- package/dist_ts/classes.authoritybackup.js +769 -0
- package/dist_ts/classes.authoritybroker.d.ts +29 -6
- package/dist_ts/classes.authoritybroker.js +413 -122
- package/dist_ts/classes.authoritycli.d.ts +24 -0
- package/dist_ts/classes.authoritycli.js +675 -0
- package/dist_ts/classes.authorityclient.d.ts +34 -9
- package/dist_ts/classes.authorityclient.js +136 -38
- package/dist_ts/classes.authoritydaemon.d.ts +47 -0
- package/dist_ts/classes.authoritydaemon.js +705 -16
- package/dist_ts/classes.authoritydatabase.d.ts +182 -8
- package/dist_ts/classes.authoritydatabase.js +1188 -41
- package/dist_ts/classes.authoritymodels.d.ts +247 -1
- package/dist_ts/classes.authoritymodels.js +870 -6
- package/dist_ts/classes.authoritypreuse.d.ts +47 -0
- package/dist_ts/classes.authoritypreuse.js +278 -0
- package/dist_ts/classes.authorityregistry.d.ts +24 -0
- package/dist_ts/classes.authorityregistry.js +88 -0
- package/dist_ts/classes.authorityrehearsal.d.ts +127 -0
- package/dist_ts/classes.authorityrehearsal.js +632 -0
- package/dist_ts/classes.authorityusage.d.ts +160 -0
- package/dist_ts/classes.authorityusage.js +429 -0
- package/dist_ts/classes.claudeauthority.d.ts +66 -0
- package/dist_ts/classes.claudeauthority.js +532 -0
- package/dist_ts/classes.claudecodeharness.js +3 -2
- package/dist_ts/classes.claudecodelocks.d.ts +13 -0
- package/dist_ts/classes.claudecodelocks.js +75 -3
- package/dist_ts/classes.claudenative.d.ts +137 -0
- package/dist_ts/classes.claudenative.js +731 -0
- package/dist_ts/classes.claudestatus.d.ts +9 -0
- package/dist_ts/classes.claudestatus.js +26 -9
- package/dist_ts/classes.claudetokenrefresh.d.ts +15 -1
- package/dist_ts/classes.claudetokenrefresh.js +74 -21
- package/dist_ts/classes.codexharness.js +4 -2
- package/dist_ts/classes.codexmanaged.d.ts +91 -0
- package/dist_ts/classes.codexmanaged.js +404 -0
- package/dist_ts/classes.codexpreuse.d.ts +8 -0
- package/dist_ts/classes.codexpreuse.js +24 -6
- package/dist_ts/classes.fileharness.d.ts +2 -0
- package/dist_ts/classes.fileharness.js +6 -4
- package/dist_ts/classes.limits.js +12 -7
- package/dist_ts/classes.opencodeharness.js +2 -2
- package/dist_ts/claudehttp.d.ts +10 -0
- package/dist_ts/claudehttp.js +29 -3
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +8 -1
- package/dist_ts/interfaces.harness.d.ts +6 -0
- package/dist_ts/interfaces.list.d.ts +9 -3
- package/dist_ts/plugins.d.ts +7 -3
- package/dist_ts/plugins.js +9 -4
- package/dist_ts/ts_migration/0001_authority_meta.d.ts +3 -0
- package/dist_ts/ts_migration/0001_authority_meta.js +32 -0
- package/dist_ts/ts_migration/index.d.ts +3 -0
- package/dist_ts/ts_migration/index.js +6 -0
- package/package.json +12 -2
- package/readme.md +205 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/authority-contract.ts +264 -9
- package/ts/authority-runtime-contract.ts +21 -1
- package/ts/authorityrehearsal.child.ts +330 -0
- package/ts/classes.accountlist.ts +3 -2
- package/ts/classes.authoritybackup.ts +780 -0
- package/ts/classes.authoritybroker.ts +410 -120
- package/ts/classes.authoritycli.ts +719 -0
- package/ts/classes.authorityclient.ts +164 -38
- package/ts/classes.authoritydaemon.ts +614 -17
- package/ts/classes.authoritydatabase.ts +1229 -44
- package/ts/classes.authoritymodels.ts +579 -4
- package/ts/classes.authoritypreuse.ts +297 -0
- package/ts/classes.authorityregistry.ts +118 -0
- package/ts/classes.authorityrehearsal.ts +625 -0
- package/ts/classes.authorityusage.ts +527 -0
- package/ts/classes.claudeauthority.ts +541 -0
- package/ts/classes.claudecodeharness.ts +2 -1
- package/ts/classes.claudecodelocks.ts +70 -1
- package/ts/classes.claudenative.ts +816 -0
- package/ts/classes.claudestatus.ts +38 -9
- package/ts/classes.claudetokenrefresh.ts +82 -19
- package/ts/classes.codexharness.ts +3 -1
- package/ts/classes.codexmanaged.ts +402 -0
- package/ts/classes.codexpreuse.ts +33 -5
- package/ts/classes.fileharness.ts +7 -3
- package/ts/classes.limits.ts +11 -6
- package/ts/classes.opencodeharness.ts +1 -1
- package/ts/claudehttp.ts +31 -2
- package/ts/index.ts +7 -0
- package/ts/interfaces.harness.ts +6 -0
- package/ts/interfaces.list.ts +9 -3
- package/ts/plugins.ts +9 -3
- package/ts/ts_migration/0001_authority_meta.ts +33 -0
- package/ts/ts_migration/index.ts +7 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
+
import type { TAuthSwitchLoginPrompt } from './authority-contract.js';
|
|
3
|
+
import type { IAuthSwitchStoredUsage } from './classes.authorityusage.js';
|
|
2
4
|
|
|
3
5
|
export interface IStoredAuthorityMeta {
|
|
4
6
|
id: 'authswitch-authority';
|
|
7
|
+
schemaVersion: 2;
|
|
8
|
+
admission: 'open' | 'closed_restored';
|
|
5
9
|
epoch: string;
|
|
6
10
|
revision: number;
|
|
7
11
|
updateId: string;
|
|
@@ -34,7 +38,7 @@ export interface IStoredAuthorityGrant {
|
|
|
34
38
|
providerId: string;
|
|
35
39
|
purpose: TStoredGrantPurpose;
|
|
36
40
|
audience: string;
|
|
37
|
-
state: 'ready' | 'exchange_may_have_been_sent' | 'retry_wait' | 'needs_reauth' | 'native' | 'legacy_native_pending' | 'removed';
|
|
41
|
+
state: 'ready' | 'exchange_may_have_been_sent' | 'retry_wait' | 'needs_reauth' | 'native' | 'legacy_native_pending' | 'handoff_pending' | 'handoff_quarantined' | 'removed';
|
|
38
42
|
owner: 'daemon' | 'claude_native' | 'legacy_native' | 'none';
|
|
39
43
|
grantGeneration: number;
|
|
40
44
|
authorizationGeneration: number;
|
|
@@ -49,6 +53,16 @@ export interface IStoredAuthorityGrant {
|
|
|
49
53
|
updateId: string;
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
/** Credential-free provider usage cached for one exact account/login pair. */
|
|
57
|
+
export interface IStoredAuthorityUsage extends IAuthSwitchStoredUsage {
|
|
58
|
+
id: string;
|
|
59
|
+
accountId: string;
|
|
60
|
+
loginId: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const authorityUsageId = (accountId: string, loginId: string): string =>
|
|
64
|
+
plugins.crypto.createHash('sha256').update(JSON.stringify(['authswitch-usage-v1', accountId, loginId])).digest('hex');
|
|
65
|
+
|
|
52
66
|
export interface IStoredAuthorityBinding {
|
|
53
67
|
id: string;
|
|
54
68
|
accountId: string;
|
|
@@ -71,6 +85,63 @@ export interface IStoredAuthorityEnrollment {
|
|
|
71
85
|
updateId: string;
|
|
72
86
|
}
|
|
73
87
|
|
|
88
|
+
/** An immutable assignment of one private native Codex state home to one account and runtime scope. */
|
|
89
|
+
export interface IStoredAuthorityCodexHome {
|
|
90
|
+
id: string;
|
|
91
|
+
accountId: string;
|
|
92
|
+
grantId: string;
|
|
93
|
+
scopeId: string;
|
|
94
|
+
activeRun: { id: string; socketPath: string; pid: number | null; startedAt: string | null } | null;
|
|
95
|
+
createdAt: string;
|
|
96
|
+
updateId: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** One vendor home owns at most one active Claude grant; activeGrantId has a unique index. */
|
|
100
|
+
export interface IStoredAuthorityClaudeHome {
|
|
101
|
+
id: string;
|
|
102
|
+
activeAccountId: string;
|
|
103
|
+
activeGrantId: string;
|
|
104
|
+
pendingOperationId: string | null;
|
|
105
|
+
status: 'ready' | 'quarantined';
|
|
106
|
+
revision: number;
|
|
107
|
+
createdAt: string;
|
|
108
|
+
updateId: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface IStoredAuthorityNativePair {
|
|
112
|
+
credentialDigest: string | null;
|
|
113
|
+
configDigest: string | null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface IStoredAuthorityNativeIdentity {
|
|
117
|
+
accountUuid: string;
|
|
118
|
+
organizationUuid: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Backend-only proof for one exact two-grant native transfer. */
|
|
122
|
+
export interface IStoredAuthorityClaudeHandoff {
|
|
123
|
+
id: string;
|
|
124
|
+
homeId: string;
|
|
125
|
+
outgoingAccountId: string;
|
|
126
|
+
outgoingGrantId: string;
|
|
127
|
+
incomingAccountId: string;
|
|
128
|
+
incomingGrantId: string;
|
|
129
|
+
phase: 'reserved' | 'prepared' | 'committed' | 'aborted' | 'quarantined';
|
|
130
|
+
before: IStoredAuthorityNativePair | null;
|
|
131
|
+
after: IStoredAuthorityNativePair | null;
|
|
132
|
+
sourceIdentity: IStoredAuthorityNativeIdentity;
|
|
133
|
+
targetIdentity: IStoredAuthorityNativeIdentity;
|
|
134
|
+
sourceAccessDigest: string | null;
|
|
135
|
+
targetAccessDigest: string | null;
|
|
136
|
+
sealedOutgoing: string | null;
|
|
137
|
+
runningEffectiveAuth: 'no_scoped_sessions' | 'unsupported_effective_auth' | null;
|
|
138
|
+
problem: 'none' | 'native_uncertain' | 'foreign_or_torn' | 'unsupported_effective_auth' | 'database_uncertain';
|
|
139
|
+
startedAt: string;
|
|
140
|
+
updatedAt: string;
|
|
141
|
+
revision: number;
|
|
142
|
+
updateId: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
74
145
|
/** Journal for a native-home handoff. A prepared grant is never usable. */
|
|
75
146
|
export interface IStoredAuthorityHandoff {
|
|
76
147
|
id: string;
|
|
@@ -112,6 +183,82 @@ export interface IStoredAuthorityEvent {
|
|
|
112
183
|
accountId: string;
|
|
113
184
|
}
|
|
114
185
|
|
|
186
|
+
/** A device flow and its immutable result receipt. Provider work is never resumed from this record. */
|
|
187
|
+
export interface IStoredAuthorityDeviceOperation {
|
|
188
|
+
id: string;
|
|
189
|
+
kind: 'add_openai' | 'reauth_openai';
|
|
190
|
+
purpose: 'openai_managed';
|
|
191
|
+
accountId: string | null;
|
|
192
|
+
grantId: string | null;
|
|
193
|
+
expectedGrantGeneration: number | null;
|
|
194
|
+
state: 'starting' | 'pending' | 'committing' | 'complete' | 'failed' | 'cancelled' | 'interrupted' | 'outcome_unknown';
|
|
195
|
+
prompt: TAuthSwitchLoginPrompt | null;
|
|
196
|
+
result: { accountId: string; grantId: string; accountRevision: number; grantGeneration: number } | null;
|
|
197
|
+
error: string | null;
|
|
198
|
+
commitId: string | null;
|
|
199
|
+
createdAt: string;
|
|
200
|
+
updatedAt: string;
|
|
201
|
+
finishedAt: string | null;
|
|
202
|
+
revision: number;
|
|
203
|
+
updateId: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type TStoredAuthorityPreuseProblem =
|
|
207
|
+
| 'none' | 'target_unavailable' | 'access_unavailable' | 'catalog_unavailable'
|
|
208
|
+
| 'account_busy' | 'cancelled' | 'authority_closing' | 'interrupted'
|
|
209
|
+
| 'request_uncertain' | 'restored_history_uncertain';
|
|
210
|
+
|
|
211
|
+
/** One quota-consuming request. The prompt and generated prose never enter persistence. */
|
|
212
|
+
export interface IStoredAuthorityPreuseOperation {
|
|
213
|
+
id: string;
|
|
214
|
+
kind: 'preuse_openai';
|
|
215
|
+
purpose: 'openai_managed';
|
|
216
|
+
accountId: string;
|
|
217
|
+
grantId: string;
|
|
218
|
+
/** Hash of the exact target, prompt and requested model; used only for idempotent admission. */
|
|
219
|
+
requestHash: string;
|
|
220
|
+
requestedModel: string | null;
|
|
221
|
+
model: string | null;
|
|
222
|
+
authorizationGeneration: number;
|
|
223
|
+
grantGeneration: number | null;
|
|
224
|
+
state: 'preparing' | 'request_may_have_started' | 'complete' | 'not_sent' | 'outcome_unknown';
|
|
225
|
+
result: { inputTokens: number | null; outputTokens: number | null; totalTokens: number | null } | null;
|
|
226
|
+
problem: TStoredAuthorityPreuseProblem;
|
|
227
|
+
createdAt: string;
|
|
228
|
+
updatedAt: string;
|
|
229
|
+
finishedAt: string | null;
|
|
230
|
+
revision: number;
|
|
231
|
+
updateId: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export type IStoredAuthorityOperation = IStoredAuthorityDeviceOperation | IStoredAuthorityPreuseOperation;
|
|
235
|
+
|
|
236
|
+
/** Decorated storage fields shared by the two exact discriminated operation variants. */
|
|
237
|
+
export interface IStoredAuthorityOperationDocument {
|
|
238
|
+
id: string;
|
|
239
|
+
kind: IStoredAuthorityOperation['kind'];
|
|
240
|
+
purpose: 'openai_managed';
|
|
241
|
+
accountId: string | null;
|
|
242
|
+
grantId: string | null;
|
|
243
|
+
expectedGrantGeneration?: number | null;
|
|
244
|
+
state: IStoredAuthorityOperation['state'];
|
|
245
|
+
prompt?: TAuthSwitchLoginPrompt | null;
|
|
246
|
+
result: IStoredAuthorityOperation['result'];
|
|
247
|
+
error?: string | null;
|
|
248
|
+
commitId?: string | null;
|
|
249
|
+
requestHash?: string;
|
|
250
|
+
requestedModel?: string | null;
|
|
251
|
+
model?: string | null;
|
|
252
|
+
authorizationGeneration?: number;
|
|
253
|
+
grantGeneration?: number | null;
|
|
254
|
+
problem?: TStoredAuthorityPreuseProblem;
|
|
255
|
+
createdAt: string;
|
|
256
|
+
updatedAt: string;
|
|
257
|
+
finishedAt: string | null;
|
|
258
|
+
revision: number;
|
|
259
|
+
updateId: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
115
262
|
const object = (value: unknown): value is Record<string, unknown> =>
|
|
116
263
|
value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
117
264
|
&& [Object.prototype, null].includes(Object.getPrototypeOf(value));
|
|
@@ -127,9 +274,110 @@ const revision = (value: unknown): value is number => Number.isSafeInteger(value
|
|
|
127
274
|
const ciphertext = (value: unknown): boolean => value === null
|
|
128
275
|
|| (typeof value === 'string' && value.length > 0 && value.length <= 131072 && /^[A-Za-z0-9_-]+$/.test(value));
|
|
129
276
|
|
|
277
|
+
const usageWindow = (value: unknown): boolean => object(value)
|
|
278
|
+
&& exactKeys(value, ['usedPercent', 'limitWindowSeconds', 'resetAfterSeconds', 'resetsAt'])
|
|
279
|
+
&& ['usedPercent', 'limitWindowSeconds', 'resetAfterSeconds', 'resetsAt']
|
|
280
|
+
.every(key => typeof value[key] === 'number' && Number.isFinite(value[key]));
|
|
281
|
+
const usageDetails = (value: unknown): boolean => object(value)
|
|
282
|
+
&& Object.keys(value).every(key => ['allowed', 'limitReached', 'primaryWindow', 'secondaryWindow'].includes(key))
|
|
283
|
+
&& typeof value.allowed === 'boolean' && typeof value.limitReached === 'boolean'
|
|
284
|
+
&& (value.primaryWindow === undefined || usageWindow(value.primaryWindow))
|
|
285
|
+
&& (value.secondaryWindow === undefined || usageWindow(value.secondaryWindow));
|
|
286
|
+
const usageRateLimits = (value: unknown): boolean => object(value)
|
|
287
|
+
&& Object.keys(value).every(key => ['providerId', 'plan', 'observedAt', 'rateLimit',
|
|
288
|
+
'additionalRateLimits', 'rateLimitReachedType', 'rateLimitResetCreditsAvailableCount'].includes(key))
|
|
289
|
+
&& value.providerId === 'openai' && bounded(value.plan, 256) && iso(value.observedAt)
|
|
290
|
+
&& (value.rateLimit === undefined || usageDetails(value.rateLimit))
|
|
291
|
+
&& Array.isArray(value.additionalRateLimits) && value.additionalRateLimits.length <= 128
|
|
292
|
+
&& value.additionalRateLimits.every((item: unknown) => object(item)
|
|
293
|
+
&& Object.keys(item).every(key => ['limitName', 'meteredFeature', 'rateLimit'].includes(key))
|
|
294
|
+
&& bounded(item.limitName, 256) && bounded(item.meteredFeature, 256)
|
|
295
|
+
&& (item.rateLimit === undefined || usageDetails(item.rateLimit)))
|
|
296
|
+
&& (value.rateLimitReachedType === undefined || bounded(value.rateLimitReachedType, 256))
|
|
297
|
+
&& (value.rateLimitResetCreditsAvailableCount === undefined
|
|
298
|
+
|| (typeof value.rateLimitResetCreditsAvailableCount === 'number'
|
|
299
|
+
&& Number.isFinite(value.rateLimitResetCreditsAvailableCount)));
|
|
300
|
+
|
|
301
|
+
const usageStatusText = (value: unknown): boolean => typeof value === 'string' && value.length <= 500
|
|
302
|
+
&& !/[\u0000-\u001f\u007f-\u009f]/.test(value);
|
|
303
|
+
const usageClaudeStatus = (value: unknown): boolean => object(value)
|
|
304
|
+
&& exactKeys(value, ['plan', 'windows', 'facts', 'problems', 'rateLimit'])
|
|
305
|
+
&& (value.plan === null || (object(value.plan) && exactKeys(value.plan, ['name', 'source'])
|
|
306
|
+
&& usageStatusText(value.plan.name) && ['live', 'stored'].includes(String(value.plan.source))))
|
|
307
|
+
&& (value.windows === null || (Array.isArray(value.windows) && value.windows.length <= 128
|
|
308
|
+
&& value.windows.every((window: unknown) => object(window)
|
|
309
|
+
&& Object.keys(window).every(key => ['label', 'scope', 'durationSeconds', 'usedPercent',
|
|
310
|
+
'resetAt', 'severity', 'headline'].includes(key))
|
|
311
|
+
&& ['label', 'scope', 'durationSeconds', 'usedPercent', 'resetAt'].every(key => Object.hasOwn(window, key))
|
|
312
|
+
&& usageStatusText(window.label) && ['account', 'feature'].includes(String(window.scope))
|
|
313
|
+
&& Number.isSafeInteger(window.durationSeconds) && Number(window.durationSeconds) > 0
|
|
314
|
+
&& typeof window.usedPercent === 'number' && Number.isFinite(window.usedPercent)
|
|
315
|
+
&& window.usedPercent >= 0 && (window.resetAt === null || iso(window.resetAt))
|
|
316
|
+
&& (window.severity === undefined || ['normal', 'warning', 'critical'].includes(String(window.severity)))
|
|
317
|
+
&& (window.headline === undefined || window.headline === true))))
|
|
318
|
+
&& Array.isArray(value.facts) && value.facts.length <= 128
|
|
319
|
+
&& value.facts.every((fact: unknown) => object(fact)
|
|
320
|
+
&& Object.keys(fact).every(key => ['section', 'label', 'value', 'summaryKey'].includes(key))
|
|
321
|
+
&& ['section', 'label', 'value'].every(key => Object.hasOwn(fact, key))
|
|
322
|
+
&& (fact.section === null || usageStatusText(fact.section))
|
|
323
|
+
&& usageStatusText(fact.label) && usageStatusText(fact.value)
|
|
324
|
+
&& (fact.summaryKey === undefined || ['subscription', 'billing', 'usageWindows', 'resets',
|
|
325
|
+
'resetDetails'].includes(String(fact.summaryKey))))
|
|
326
|
+
&& Array.isArray(value.problems) && value.problems.length <= 32
|
|
327
|
+
&& value.problems.every(usageStatusText)
|
|
328
|
+
&& (value.rateLimit === null || (object(value.rateLimit)
|
|
329
|
+
&& exactKeys(value.rateLimit, ['retryAt'])
|
|
330
|
+
&& (value.rateLimit.retryAt === null || iso(value.rateLimit.retryAt))));
|
|
331
|
+
const usageReading = (value: unknown): boolean => object(value)
|
|
332
|
+
&& (value.kind === 'openai' ? exactKeys(value, ['kind', 'rateLimits']) && usageRateLimits(value.rateLimits)
|
|
333
|
+
: value.kind === 'anthropic' && exactKeys(value, ['kind', 'status'])
|
|
334
|
+
&& usageClaudeStatus(value.status));
|
|
335
|
+
|
|
336
|
+
export const assertStoredAuthorityUsage: (value: unknown) => asserts value is IStoredAuthorityUsage = value => {
|
|
337
|
+
if (!object(value) || !exactKeys(value, ['id', 'accountId', 'loginId', 'context', 'updateId',
|
|
338
|
+
'reading', 'observedAt', 'currentUntil', 'staleUntil', 'lastAttemptAt', 'nextAttemptAt',
|
|
339
|
+
'failures', 'problem']) || !hash(value.accountId) || !hash(value.loginId)
|
|
340
|
+
|| value.id !== authorityUsageId(value.accountId, value.loginId)
|
|
341
|
+
|| !object(value.context) || !exactKeys(value.context, ['epoch', 'accountId', 'loginId',
|
|
342
|
+
'subjectId', 'workspaceId', 'providerId', 'purpose', 'owner', 'grantState', 'removed',
|
|
343
|
+
'authorizationGeneration', 'grantGeneration', 'nativeSource'])
|
|
344
|
+
|| !uuid(value.context.epoch) || value.context.accountId !== value.accountId
|
|
345
|
+
|| value.context.loginId !== value.loginId || !bounded(value.context.subjectId)
|
|
346
|
+
|| !bounded(value.context.workspaceId)
|
|
347
|
+
|| !((value.context.providerId === 'openai' && value.context.purpose === 'openai_managed'
|
|
348
|
+
&& value.context.owner === 'daemon' && value.context.nativeSource === null
|
|
349
|
+
&& ['ready', 'retry_wait'].includes(String(value.context.grantState)))
|
|
350
|
+
|| (value.context.providerId === 'anthropic' && value.context.purpose === 'claude_host_native'
|
|
351
|
+
&& ((value.context.owner === 'daemon' && value.context.nativeSource === null
|
|
352
|
+
&& ['ready', 'retry_wait'].includes(String(value.context.grantState)))
|
|
353
|
+
|| (value.context.owner === 'claude_native' && value.context.grantState === 'native'
|
|
354
|
+
&& object(value.context.nativeSource)
|
|
355
|
+
&& exactKeys(value.context.nativeSource, ['homeId', 'credentialDigest',
|
|
356
|
+
'configDigest', 'accessTokenDigest'])
|
|
357
|
+
&& hash(value.context.nativeSource.homeId)
|
|
358
|
+
&& hash(value.context.nativeSource.credentialDigest)
|
|
359
|
+
&& hash(value.context.nativeSource.configDigest)
|
|
360
|
+
&& hash(value.context.nativeSource.accessTokenDigest)))))
|
|
361
|
+
|| value.context.removed !== false || !revision(value.context.authorizationGeneration)
|
|
362
|
+
|| !revision(value.context.grantGeneration) || !uuid(value.updateId)
|
|
363
|
+
|| (value.reading !== null && (!object(value.reading) || !usageReading(value.reading)
|
|
364
|
+
|| (value.context.providerId === 'openai' ? value.reading.kind !== 'openai'
|
|
365
|
+
: value.reading.kind !== 'anthropic')))
|
|
366
|
+
|| (value.observedAt !== null && !iso(value.observedAt))
|
|
367
|
+
|| (value.currentUntil !== null && !iso(value.currentUntil))
|
|
368
|
+
|| (value.staleUntil !== null && !iso(value.staleUntil))
|
|
369
|
+
|| !iso(value.lastAttemptAt) || !iso(value.nextAttemptAt)
|
|
370
|
+
|| !revision(value.failures) || value.failures > 16
|
|
371
|
+
|| !['none', 'unsupported', 'access_unavailable', 'provider_unavailable', 'provider_rejected',
|
|
372
|
+
'profile_unavailable', 'usage_unavailable'].includes(String(value.problem))) {
|
|
373
|
+
throw new Error('Invalid credential-free authority usage record.');
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
130
377
|
export const assertStoredAuthorityMeta: (value: unknown) => asserts value is IStoredAuthorityMeta = value => {
|
|
131
|
-
if (!object(value) || !exactKeys(value, ['id', 'epoch', 'revision', 'updateId'])
|
|
132
|
-
|| value.id !== 'authswitch-authority' ||
|
|
378
|
+
if (!object(value) || !exactKeys(value, ['id', 'schemaVersion', 'admission', 'epoch', 'revision', 'updateId'])
|
|
379
|
+
|| value.id !== 'authswitch-authority' || value.schemaVersion !== 2
|
|
380
|
+
|| !['open', 'closed_restored'].includes(value.admission as string) || !uuid(value.epoch)
|
|
133
381
|
|| !revision(value.revision) || !uuid(value.updateId)) throw new Error('Invalid authswitch authority metadata.');
|
|
134
382
|
};
|
|
135
383
|
|
|
@@ -154,7 +402,7 @@ export const assertStoredAuthorityGrant: (value: unknown) => asserts value is IS
|
|
|
154
402
|
|| typeof value.providerId !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(value.providerId)
|
|
155
403
|
|| !['openai_managed', 'claude_host_native', 'claude_container_setup', 'opencode_native'].includes(String(value.purpose))
|
|
156
404
|
|| !bounded(value.audience)
|
|
157
|
-
|| !['ready', 'exchange_may_have_been_sent', 'retry_wait', 'needs_reauth', 'native', 'legacy_native_pending', 'removed'].includes(String(value.state))
|
|
405
|
+
|| !['ready', 'exchange_may_have_been_sent', 'retry_wait', 'needs_reauth', 'native', 'legacy_native_pending', 'handoff_pending', 'handoff_quarantined', 'removed'].includes(String(value.state))
|
|
158
406
|
|| !['daemon', 'claude_native', 'legacy_native', 'none'].includes(String(value.owner))
|
|
159
407
|
|| !revision(value.grantGeneration) || !revision(value.authorizationGeneration)
|
|
160
408
|
|| !revision(value.revision) || !ciphertext(value.ciphertext)
|
|
@@ -170,6 +418,13 @@ export const assertStoredAuthorityGrant: (value: unknown) => asserts value is IS
|
|
|
170
418
|
if ((value.state === 'retry_wait') !== (value.retryAt !== null)) throw new Error('Invalid refresh retry marker.');
|
|
171
419
|
if (value.state === 'removed' && (value.ciphertext !== null || value.owner !== 'none')) throw new Error('A removed grant was retained.');
|
|
172
420
|
if (value.state === 'legacy_native_pending' && value.owner !== 'legacy_native') throw new Error('A legacy native grant cannot be daemon-owned.');
|
|
421
|
+
if (['handoff_pending', 'handoff_quarantined'].includes(String(value.state))
|
|
422
|
+
&& value.purpose !== 'claude_host_native') throw new Error('Only a Claude host grant may enter native handoff.');
|
|
423
|
+
if (['handoff_pending', 'handoff_quarantined'].includes(String(value.state))
|
|
424
|
+
&& (value.owner === 'daemon' ? value.ciphertext === null
|
|
425
|
+
: value.owner !== 'claude_native' || value.ciphertext !== null)) {
|
|
426
|
+
throw new Error('Claude handoff grant has incompatible custody.');
|
|
427
|
+
}
|
|
173
428
|
if (value.purpose === 'openai_managed' && value.providerId !== 'openai') throw new Error('OpenAI grant provider mismatch.');
|
|
174
429
|
if (value.purpose === 'claude_container_setup' && value.owner === 'claude_native') throw new Error('Container setup grant has a native host owner.');
|
|
175
430
|
};
|
|
@@ -191,6 +446,75 @@ export const assertStoredAuthorityEnrollment: (value: unknown) => asserts value
|
|
|
191
446
|
|| !revision(value.revision) || !uuid(value.updateId)) throw new Error('Invalid authswitch enrollment record.');
|
|
192
447
|
};
|
|
193
448
|
|
|
449
|
+
export const assertStoredAuthorityCodexHome: (value: unknown) => asserts value is IStoredAuthorityCodexHome = value => {
|
|
450
|
+
if (!object(value) || !exactKeys(value, ['id', 'accountId', 'grantId', 'scopeId', 'activeRun', 'createdAt', 'updateId'])
|
|
451
|
+
|| !hash(value.id) || !hash(value.accountId) || !hash(value.grantId) || !bounded(value.scopeId)
|
|
452
|
+
|| !iso(value.createdAt) || !uuid(value.updateId)) {
|
|
453
|
+
throw new Error('Invalid managed Codex home assignment.');
|
|
454
|
+
}
|
|
455
|
+
if (value.activeRun !== null && (!object(value.activeRun)
|
|
456
|
+
|| !exactKeys(value.activeRun, ['id', 'socketPath', 'pid', 'startedAt'])
|
|
457
|
+
|| !uuid(value.activeRun.id) || !bounded(value.activeRun.socketPath, 1024)
|
|
458
|
+
|| (value.activeRun.pid !== null && (typeof value.activeRun.pid !== 'number'
|
|
459
|
+
|| !Number.isSafeInteger(value.activeRun.pid) || value.activeRun.pid <= 0))
|
|
460
|
+
|| (value.activeRun.startedAt !== null && !iso(value.activeRun.startedAt))
|
|
461
|
+
|| (value.activeRun.pid === null) !== (value.activeRun.startedAt === null))) {
|
|
462
|
+
throw new Error('Invalid managed Codex run assignment.');
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
export const assertStoredAuthorityClaudeHome: (value: unknown) => asserts value is IStoredAuthorityClaudeHome = value => {
|
|
467
|
+
if (!object(value) || !exactKeys(value, ['id', 'activeAccountId', 'activeGrantId', 'pendingOperationId',
|
|
468
|
+
'status', 'revision', 'createdAt', 'updateId']) || !hash(value.id) || !hash(value.activeAccountId)
|
|
469
|
+
|| !hash(value.activeGrantId) || (value.pendingOperationId !== null && !uuid(value.pendingOperationId))
|
|
470
|
+
|| !['ready', 'quarantined'].includes(String(value.status)) || !revision(value.revision)
|
|
471
|
+
|| value.revision === 0 || !iso(value.createdAt) || !uuid(value.updateId)
|
|
472
|
+
|| (value.status === 'quarantined' && value.pendingOperationId === null)) {
|
|
473
|
+
throw new Error('Invalid Claude native home assignment.');
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
const nativePair = (value: unknown): value is IStoredAuthorityNativePair => object(value)
|
|
478
|
+
&& exactKeys(value, ['credentialDigest', 'configDigest'])
|
|
479
|
+
&& (value.credentialDigest === null || hash(value.credentialDigest))
|
|
480
|
+
&& (value.configDigest === null || hash(value.configDigest));
|
|
481
|
+
const nativeIdentity = (value: unknown): value is IStoredAuthorityNativeIdentity => object(value)
|
|
482
|
+
&& exactKeys(value, ['accountUuid', 'organizationUuid'])
|
|
483
|
+
&& bounded(value.accountUuid) && bounded(value.organizationUuid);
|
|
484
|
+
|
|
485
|
+
export const assertStoredAuthorityClaudeHandoff: (value: unknown) => asserts value is IStoredAuthorityClaudeHandoff = value => {
|
|
486
|
+
if (!object(value) || !exactKeys(value, ['id', 'homeId', 'outgoingAccountId', 'outgoingGrantId',
|
|
487
|
+
'incomingAccountId', 'incomingGrantId', 'phase', 'before', 'after', 'sourceIdentity',
|
|
488
|
+
'targetIdentity', 'sourceAccessDigest', 'targetAccessDigest', 'sealedOutgoing',
|
|
489
|
+
'runningEffectiveAuth', 'problem', 'startedAt', 'updatedAt', 'revision', 'updateId'])
|
|
490
|
+
|| !uuid(value.id) || !hash(value.homeId) || !hash(value.outgoingAccountId)
|
|
491
|
+
|| !hash(value.outgoingGrantId) || !hash(value.incomingAccountId) || !hash(value.incomingGrantId)
|
|
492
|
+
|| value.outgoingAccountId === value.incomingAccountId || value.outgoingGrantId === value.incomingGrantId
|
|
493
|
+
|| !['reserved', 'prepared', 'committed', 'aborted', 'quarantined'].includes(String(value.phase))
|
|
494
|
+
|| (value.before !== null && !nativePair(value.before)) || (value.after !== null && !nativePair(value.after))
|
|
495
|
+
|| !nativeIdentity(value.sourceIdentity) || !nativeIdentity(value.targetIdentity)
|
|
496
|
+
|| (value.sourceAccessDigest !== null && !hash(value.sourceAccessDigest))
|
|
497
|
+
|| (value.targetAccessDigest !== null && !hash(value.targetAccessDigest))
|
|
498
|
+
|| !ciphertext(value.sealedOutgoing)
|
|
499
|
+
|| ![null, 'no_scoped_sessions', 'unsupported_effective_auth'].includes(value.runningEffectiveAuth as null)
|
|
500
|
+
|| !['none', 'native_uncertain', 'foreign_or_torn', 'unsupported_effective_auth', 'database_uncertain'].includes(String(value.problem))
|
|
501
|
+
|| !iso(value.startedAt) || !iso(value.updatedAt) || !revision(value.revision)
|
|
502
|
+
|| value.revision === 0 || !uuid(value.updateId)) throw new Error('Invalid Claude native handoff.');
|
|
503
|
+
const hasProof = value.before !== null && value.after !== null
|
|
504
|
+
&& value.sourceAccessDigest !== null && value.targetAccessDigest !== null;
|
|
505
|
+
const hasNoProof = value.before === null && value.after === null
|
|
506
|
+
&& value.sourceAccessDigest === null && value.targetAccessDigest === null;
|
|
507
|
+
if ((value.phase === 'reserved' && (!hasNoProof || value.sealedOutgoing !== null))
|
|
508
|
+
|| (['prepared', 'committed'].includes(String(value.phase)) && !hasProof)
|
|
509
|
+
|| (['aborted', 'quarantined'].includes(String(value.phase)) && !hasProof && !hasNoProof)) {
|
|
510
|
+
throw new Error('Claude handoff phase lacks exact native proof.');
|
|
511
|
+
}
|
|
512
|
+
if (value.phase === 'prepared' && value.sealedOutgoing === null) throw new Error('Prepared Claude handoff lacks sealed outgoing grant.');
|
|
513
|
+
if (['committed', 'aborted'].includes(String(value.phase)) && value.sealedOutgoing !== null) {
|
|
514
|
+
throw new Error('Terminal Claude handoff retained a grant copy.');
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
194
518
|
export const assertStoredAuthorityHandoff: (value: unknown) => asserts value is IStoredAuthorityHandoff = value => {
|
|
195
519
|
if (!object(value) || !exactKeys(value, ['id', 'accountId', 'grantId', 'nativeHomeId', 'direction', 'phase',
|
|
196
520
|
'operationId', 'sourceDigest', 'verifiedSourceDigest', 'backupDigest', 'revision', 'statusObservedAt', 'updateId'])
|
|
@@ -230,11 +554,154 @@ export const assertStoredAuthorityEvent: (value: unknown) => asserts value is IS
|
|
|
230
554
|
|| !['account', 'binding'].includes(String(value.kind)) || !hash(value.accountId)) throw new Error('Invalid authswitch event record.');
|
|
231
555
|
};
|
|
232
556
|
|
|
557
|
+
const assertStoredAuthorityDeviceOperation: (value: unknown) => asserts value is IStoredAuthorityDeviceOperation = value => {
|
|
558
|
+
if (!object(value) || !exactKeys(value, ['id', 'kind', 'purpose', 'accountId', 'grantId',
|
|
559
|
+
'expectedGrantGeneration', 'state', 'prompt', 'result', 'error', 'commitId', 'createdAt',
|
|
560
|
+
'updatedAt', 'finishedAt', 'revision', 'updateId'])
|
|
561
|
+
|| !uuid(value.id) || !['add_openai', 'reauth_openai'].includes(String(value.kind))
|
|
562
|
+
|| value.purpose !== 'openai_managed'
|
|
563
|
+
|| (value.accountId !== null && !hash(value.accountId))
|
|
564
|
+
|| (value.grantId !== null && !hash(value.grantId))
|
|
565
|
+
|| (value.expectedGrantGeneration !== null && !revision(value.expectedGrantGeneration))
|
|
566
|
+
|| !['starting', 'pending', 'committing', 'complete', 'failed', 'cancelled', 'interrupted', 'outcome_unknown'].includes(String(value.state))
|
|
567
|
+
|| (value.commitId !== null && !uuid(value.commitId))
|
|
568
|
+
|| !iso(value.createdAt) || !iso(value.updatedAt)
|
|
569
|
+
|| (value.finishedAt !== null && !iso(value.finishedAt))
|
|
570
|
+
|| !revision(value.revision) || value.revision === 0 || !uuid(value.updateId)) {
|
|
571
|
+
throw new Error('Invalid authswitch operation record.');
|
|
572
|
+
}
|
|
573
|
+
if (value.kind === 'add_openai'
|
|
574
|
+
? value.accountId !== null || value.grantId !== null || value.expectedGrantGeneration !== null
|
|
575
|
+
: value.accountId === null || value.grantId === null || value.expectedGrantGeneration === null) {
|
|
576
|
+
throw new Error('Invalid authswitch operation target.');
|
|
577
|
+
}
|
|
578
|
+
if (value.prompt !== null && (!object(value.prompt)
|
|
579
|
+
|| (value.prompt.flow === 'device'
|
|
580
|
+
? !exactKeys(value.prompt, ['flow', 'verificationUrl', 'userCode'])
|
|
581
|
+
|| !bounded(value.prompt.verificationUrl, 2048) || !bounded(value.prompt.userCode, 128)
|
|
582
|
+
: value.prompt.flow === 'browser'
|
|
583
|
+
? !exactKeys(value.prompt, ['flow', 'authUrl']) || !bounded(value.prompt.authUrl, 2048)
|
|
584
|
+
: true))) throw new Error('Invalid authswitch operation prompt.');
|
|
585
|
+
if (value.result !== null && (!object(value.result)
|
|
586
|
+
|| !exactKeys(value.result, ['accountId', 'grantId', 'accountRevision', 'grantGeneration'])
|
|
587
|
+
|| !hash(value.result.accountId) || !hash(value.result.grantId)
|
|
588
|
+
|| !revision(value.result.accountRevision) || !revision(value.result.grantGeneration))) {
|
|
589
|
+
throw new Error('Invalid authswitch operation result.');
|
|
590
|
+
}
|
|
591
|
+
if (value.error !== null && !bounded(value.error, 512)) throw new Error('Invalid authswitch operation error.');
|
|
592
|
+
if (['starting', 'pending', 'committing'].includes(String(value.state))) {
|
|
593
|
+
if (value.finishedAt !== null || value.result !== null || value.error !== null
|
|
594
|
+
|| (value.state === 'pending') !== (value.prompt !== null)
|
|
595
|
+
|| (value.state === 'committing') !== (value.commitId !== null)) {
|
|
596
|
+
throw new Error('Invalid pending authswitch operation.');
|
|
597
|
+
}
|
|
598
|
+
} else if (value.finishedAt === null || value.prompt !== null
|
|
599
|
+
|| (value.state === 'complete' ? value.result === null || value.error !== null || value.commitId === null
|
|
600
|
+
: value.result !== null || value.error === null)) {
|
|
601
|
+
throw new Error('Invalid terminal authswitch operation.');
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
const modelId = (value: unknown): value is string => typeof value === 'string'
|
|
606
|
+
&& /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,127}$/.test(value);
|
|
607
|
+
const tokenCount = (value: unknown): value is number | null => value === null
|
|
608
|
+
|| (Number.isSafeInteger(value) && Number(value) >= 0);
|
|
609
|
+
|
|
610
|
+
const assertStoredAuthorityPreuseOperation: (value: unknown) => asserts value is IStoredAuthorityPreuseOperation = value => {
|
|
611
|
+
if (!object(value) || !exactKeys(value, ['id', 'kind', 'purpose', 'accountId', 'grantId', 'requestHash',
|
|
612
|
+
'requestedModel', 'model', 'authorizationGeneration', 'grantGeneration', 'state', 'result', 'problem',
|
|
613
|
+
'createdAt', 'updatedAt', 'finishedAt', 'revision', 'updateId'])
|
|
614
|
+
|| !uuid(value.id) || value.kind !== 'preuse_openai' || value.purpose !== 'openai_managed'
|
|
615
|
+
|| !hash(value.accountId) || !hash(value.grantId) || !hash(value.requestHash)
|
|
616
|
+
|| (value.requestedModel !== null && !modelId(value.requestedModel))
|
|
617
|
+
|| (value.model !== null && !modelId(value.model))
|
|
618
|
+
|| !revision(value.authorizationGeneration) || value.authorizationGeneration === 0
|
|
619
|
+
|| (value.grantGeneration !== null && (!revision(value.grantGeneration) || value.grantGeneration === 0))
|
|
620
|
+
|| !['preparing', 'request_may_have_started', 'complete', 'not_sent', 'outcome_unknown'].includes(String(value.state))
|
|
621
|
+
|| !['none', 'target_unavailable', 'access_unavailable', 'catalog_unavailable', 'account_busy', 'cancelled',
|
|
622
|
+
'authority_closing', 'interrupted', 'request_uncertain', 'restored_history_uncertain'].includes(String(value.problem))
|
|
623
|
+
|| !iso(value.createdAt) || !iso(value.updatedAt)
|
|
624
|
+
|| (value.finishedAt !== null && !iso(value.finishedAt))
|
|
625
|
+
|| !revision(value.revision) || value.revision === 0 || !uuid(value.updateId)) {
|
|
626
|
+
throw new Error('Invalid authswitch preuse operation record.');
|
|
627
|
+
}
|
|
628
|
+
if (value.result !== null && (!object(value.result)
|
|
629
|
+
|| !exactKeys(value.result, ['inputTokens', 'outputTokens', 'totalTokens'])
|
|
630
|
+
|| !tokenCount(value.result.inputTokens) || !tokenCount(value.result.outputTokens)
|
|
631
|
+
|| !tokenCount(value.result.totalTokens))) {
|
|
632
|
+
throw new Error('Invalid authswitch preuse operation result.');
|
|
633
|
+
}
|
|
634
|
+
if (value.state === 'preparing') {
|
|
635
|
+
if (value.model !== null || value.grantGeneration !== null || value.result !== null
|
|
636
|
+
|| value.problem !== 'none' || value.finishedAt !== null) {
|
|
637
|
+
throw new Error('Invalid preparing authswitch preuse operation.');
|
|
638
|
+
}
|
|
639
|
+
} else if (value.state === 'request_may_have_started') {
|
|
640
|
+
if (value.model === null || value.grantGeneration === null || value.result !== null
|
|
641
|
+
|| value.problem !== 'none' || value.finishedAt !== null) {
|
|
642
|
+
throw new Error('Invalid active authswitch preuse operation.');
|
|
643
|
+
}
|
|
644
|
+
} else if (value.state === 'complete') {
|
|
645
|
+
if (value.model === null || value.grantGeneration === null || value.result === null
|
|
646
|
+
|| value.problem !== 'none' || value.finishedAt === null) {
|
|
647
|
+
throw new Error('Invalid completed authswitch preuse operation.');
|
|
648
|
+
}
|
|
649
|
+
} else if (value.state === 'not_sent') {
|
|
650
|
+
if (value.model !== null || value.grantGeneration !== null || value.result !== null
|
|
651
|
+
|| value.problem === 'none' || value.problem === 'request_uncertain' || value.finishedAt === null) {
|
|
652
|
+
throw new Error('Invalid unsent authswitch preuse operation.');
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
const restoredHistory = value.problem === 'restored_history_uncertain';
|
|
656
|
+
const coherentMarker = (value.model === null) === (value.grantGeneration === null);
|
|
657
|
+
if (value.result !== null || value.finishedAt === null
|
|
658
|
+
|| (restoredHistory ? !coherentMarker : value.model === null || value.grantGeneration === null
|
|
659
|
+
|| !['cancelled', 'authority_closing', 'request_uncertain'].includes(String(value.problem)))) {
|
|
660
|
+
throw new Error('Invalid uncertain authswitch preuse operation.');
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
export const assertStoredAuthorityOperation: (value: unknown) => asserts value is IStoredAuthorityOperation = value => {
|
|
666
|
+
if (object(value) && value.kind === 'preuse_openai') assertStoredAuthorityPreuseOperation(value);
|
|
667
|
+
else assertStoredAuthorityDeviceOperation(value);
|
|
668
|
+
};
|
|
669
|
+
export const assertStoredAuthorityOperationDocument: (value: unknown) => asserts value is IStoredAuthorityOperationDocument = value => {
|
|
670
|
+
assertStoredAuthorityOperation(value);
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Converts unresolved snapshot history into an immutable restored receipt. A live restart has stronger
|
|
675
|
+
* evidence and is handled separately: a snapshot captured in `preparing` may have sent after capture.
|
|
676
|
+
*/
|
|
677
|
+
export const restoreStoredAuthorityOperation = (operation: IStoredAuthorityOperation, options: {
|
|
678
|
+
restoredAt: string;
|
|
679
|
+
updateId: string;
|
|
680
|
+
}): IStoredAuthorityOperation => {
|
|
681
|
+
assertStoredAuthorityOperation(operation);
|
|
682
|
+
const unresolvedDevice = operation.kind !== 'preuse_openai'
|
|
683
|
+
&& ['starting', 'pending', 'committing'].includes(operation.state);
|
|
684
|
+
const unresolvedPreuse = operation.kind === 'preuse_openai'
|
|
685
|
+
&& ['preparing', 'request_may_have_started'].includes(operation.state);
|
|
686
|
+
if (!unresolvedDevice && !unresolvedPreuse) return operation;
|
|
687
|
+
const restored: IStoredAuthorityOperation = operation.kind === 'preuse_openai'
|
|
688
|
+
? { ...operation, state: 'outcome_unknown', result: null, problem: 'restored_history_uncertain',
|
|
689
|
+
updatedAt: options.restoredAt, finishedAt: options.restoredAt,
|
|
690
|
+
revision: operation.revision + 1, updateId: options.updateId }
|
|
691
|
+
: { ...operation, state: 'interrupted', prompt: null, result: null, commitId: null,
|
|
692
|
+
error: 'Interrupted by authority restore.', updatedAt: options.restoredAt, finishedAt: options.restoredAt,
|
|
693
|
+
revision: operation.revision + 1, updateId: options.updateId };
|
|
694
|
+
assertStoredAuthorityOperation(restored);
|
|
695
|
+
return restored;
|
|
696
|
+
};
|
|
697
|
+
|
|
233
698
|
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_meta' })
|
|
234
699
|
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityMeta })
|
|
235
700
|
export class AuthSwitchAuthorityMetaModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityMetaModel, IStoredAuthorityMeta> {
|
|
236
701
|
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityMetaModel>;
|
|
237
702
|
@plugins.smartdata.unI() public id!: 'authswitch-authority';
|
|
703
|
+
@plugins.smartdata.svDb() public schemaVersion!: 2;
|
|
704
|
+
@plugins.smartdata.svDb() public admission!: IStoredAuthorityMeta['admission'];
|
|
238
705
|
@plugins.smartdata.svDb() public epoch!: string;
|
|
239
706
|
@plugins.smartdata.svDb() public revision!: number;
|
|
240
707
|
@plugins.smartdata.svDb() public updateId!: string;
|
|
@@ -286,6 +753,26 @@ export class AuthSwitchAuthorityGrantModel extends plugins.smartdata.SmartDataDb
|
|
|
286
753
|
@plugins.smartdata.svDb() public updateId!: string;
|
|
287
754
|
}
|
|
288
755
|
|
|
756
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_usage_account_login', key: { accountId: 1, loginId: 1 }, options: { unique: true } })
|
|
757
|
+
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_usage' })
|
|
758
|
+
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityUsage })
|
|
759
|
+
export class AuthSwitchAuthorityUsageModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityUsageModel, IStoredAuthorityUsage> {
|
|
760
|
+
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityUsageModel>;
|
|
761
|
+
@plugins.smartdata.unI() public id!: string;
|
|
762
|
+
@plugins.smartdata.svDb() public accountId!: string;
|
|
763
|
+
@plugins.smartdata.svDb() public loginId!: string;
|
|
764
|
+
@plugins.smartdata.svDb() public context!: IAuthSwitchStoredUsage['context'];
|
|
765
|
+
@plugins.smartdata.svDb() public updateId!: string;
|
|
766
|
+
@plugins.smartdata.svDb() public reading!: IAuthSwitchStoredUsage['reading'];
|
|
767
|
+
@plugins.smartdata.svDb() public observedAt!: string | null;
|
|
768
|
+
@plugins.smartdata.svDb() public currentUntil!: string | null;
|
|
769
|
+
@plugins.smartdata.svDb() public staleUntil!: string | null;
|
|
770
|
+
@plugins.smartdata.svDb() public lastAttemptAt!: string;
|
|
771
|
+
@plugins.smartdata.svDb() public nextAttemptAt!: string;
|
|
772
|
+
@plugins.smartdata.svDb() public failures!: number;
|
|
773
|
+
@plugins.smartdata.svDb() public problem!: IAuthSwitchStoredUsage['problem'];
|
|
774
|
+
}
|
|
775
|
+
|
|
289
776
|
@plugins.smartdata.compoundIndex({ name: 'authority_binding_account_id', key: { accountId: 1, id: 1 } })
|
|
290
777
|
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_bindings' })
|
|
291
778
|
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityBinding })
|
|
@@ -315,6 +802,62 @@ export class AuthSwitchAuthorityEnrollmentModel extends plugins.smartdata.SmartD
|
|
|
315
802
|
@plugins.smartdata.svDb() public updateId!: string;
|
|
316
803
|
}
|
|
317
804
|
|
|
805
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_codex_home_account_id', key: { accountId: 1, id: 1 } })
|
|
806
|
+
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_codex_homes' })
|
|
807
|
+
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityCodexHome })
|
|
808
|
+
export class AuthSwitchAuthorityCodexHomeModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityCodexHomeModel, IStoredAuthorityCodexHome> {
|
|
809
|
+
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityCodexHomeModel>;
|
|
810
|
+
@plugins.smartdata.unI() public id!: string;
|
|
811
|
+
@plugins.smartdata.svDb() public accountId!: string;
|
|
812
|
+
@plugins.smartdata.svDb() public grantId!: string;
|
|
813
|
+
@plugins.smartdata.svDb() public scopeId!: string;
|
|
814
|
+
@plugins.smartdata.svDb() public activeRun!: IStoredAuthorityCodexHome['activeRun'];
|
|
815
|
+
@plugins.smartdata.svDb() public createdAt!: string;
|
|
816
|
+
@plugins.smartdata.svDb() public updateId!: string;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_claude_homes' })
|
|
820
|
+
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityClaudeHome })
|
|
821
|
+
export class AuthSwitchAuthorityClaudeHomeModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityClaudeHomeModel, IStoredAuthorityClaudeHome> {
|
|
822
|
+
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityClaudeHomeModel>;
|
|
823
|
+
@plugins.smartdata.unI() public id!: string;
|
|
824
|
+
@plugins.smartdata.svDb() public activeAccountId!: string;
|
|
825
|
+
@plugins.smartdata.index({ unique: true }) public activeGrantId!: string;
|
|
826
|
+
@plugins.smartdata.svDb() public pendingOperationId!: string | null;
|
|
827
|
+
@plugins.smartdata.svDb() public status!: IStoredAuthorityClaudeHome['status'];
|
|
828
|
+
@plugins.smartdata.svDb() public revision!: number;
|
|
829
|
+
@plugins.smartdata.svDb() public createdAt!: string;
|
|
830
|
+
@plugins.smartdata.svDb() public updateId!: string;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_claude_handoff_home_phase', key: { homeId: 1, phase: 1, id: 1 } })
|
|
834
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_claude_handoff_phase_id', key: { phase: 1, id: 1 } })
|
|
835
|
+
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_claude_handoffs' })
|
|
836
|
+
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityClaudeHandoff })
|
|
837
|
+
export class AuthSwitchAuthorityClaudeHandoffModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityClaudeHandoffModel, IStoredAuthorityClaudeHandoff> {
|
|
838
|
+
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityClaudeHandoffModel>;
|
|
839
|
+
@plugins.smartdata.unI() public id!: string;
|
|
840
|
+
@plugins.smartdata.svDb() public homeId!: string;
|
|
841
|
+
@plugins.smartdata.svDb() public outgoingAccountId!: string;
|
|
842
|
+
@plugins.smartdata.svDb() public outgoingGrantId!: string;
|
|
843
|
+
@plugins.smartdata.svDb() public incomingAccountId!: string;
|
|
844
|
+
@plugins.smartdata.svDb() public incomingGrantId!: string;
|
|
845
|
+
@plugins.smartdata.svDb() public phase!: IStoredAuthorityClaudeHandoff['phase'];
|
|
846
|
+
@plugins.smartdata.svDb() public before!: IStoredAuthorityNativePair | null;
|
|
847
|
+
@plugins.smartdata.svDb() public after!: IStoredAuthorityNativePair | null;
|
|
848
|
+
@plugins.smartdata.svDb() public sourceIdentity!: IStoredAuthorityNativeIdentity;
|
|
849
|
+
@plugins.smartdata.svDb() public targetIdentity!: IStoredAuthorityNativeIdentity;
|
|
850
|
+
@plugins.smartdata.svDb() public sourceAccessDigest!: string | null;
|
|
851
|
+
@plugins.smartdata.svDb() public targetAccessDigest!: string | null;
|
|
852
|
+
@plugins.smartdata.svDb() public sealedOutgoing!: string | null;
|
|
853
|
+
@plugins.smartdata.svDb() public runningEffectiveAuth!: IStoredAuthorityClaudeHandoff['runningEffectiveAuth'];
|
|
854
|
+
@plugins.smartdata.svDb() public problem!: IStoredAuthorityClaudeHandoff['problem'];
|
|
855
|
+
@plugins.smartdata.svDb() public startedAt!: string;
|
|
856
|
+
@plugins.smartdata.svDb() public updatedAt!: string;
|
|
857
|
+
@plugins.smartdata.svDb() public revision!: number;
|
|
858
|
+
@plugins.smartdata.svDb() public updateId!: string;
|
|
859
|
+
}
|
|
860
|
+
|
|
318
861
|
@plugins.smartdata.compoundIndex({ name: 'authority_handoff_grant_id', key: { grantId: 1, id: 1 } })
|
|
319
862
|
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_handoffs' })
|
|
320
863
|
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityHandoff })
|
|
@@ -336,6 +879,7 @@ export class AuthSwitchAuthorityHandoffModel extends plugins.smartdata.SmartData
|
|
|
336
879
|
}
|
|
337
880
|
|
|
338
881
|
@plugins.smartdata.compoundIndex({ name: 'authority_migration_status_id', key: { status: 1, id: 1 } })
|
|
882
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_migration_grant_status_id', key: { grantId: 1, status: 1, id: 1 } })
|
|
339
883
|
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_migration_ledger' })
|
|
340
884
|
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityMigrationLedger })
|
|
341
885
|
export class AuthSwitchAuthorityMigrationLedgerModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityMigrationLedgerModel, IStoredAuthorityMigrationLedger> {
|
|
@@ -365,3 +909,34 @@ export class AuthSwitchAuthorityEventModel extends plugins.smartdata.SmartDataDb
|
|
|
365
909
|
@plugins.smartdata.svDb() public kind!: IStoredAuthorityEvent['kind'];
|
|
366
910
|
@plugins.smartdata.svDb() public accountId!: string;
|
|
367
911
|
}
|
|
912
|
+
|
|
913
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_operation_state_id', key: { state: 1, id: 1 } })
|
|
914
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_operation_account_id', key: { accountId: 1, id: 1 } })
|
|
915
|
+
@plugins.smartdata.compoundIndex({ name: 'authority_operation_kind_id', key: { kind: 1, id: 1 } })
|
|
916
|
+
@plugins.smartdata.managed({ collectionName: 'authswitch_authority_operations' })
|
|
917
|
+
@plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityOperationDocument })
|
|
918
|
+
export class AuthSwitchAuthorityOperationModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityOperationModel, IStoredAuthorityOperationDocument> {
|
|
919
|
+
declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityOperationModel>;
|
|
920
|
+
@plugins.smartdata.unI() public id!: string;
|
|
921
|
+
@plugins.smartdata.svDb() public kind!: IStoredAuthorityOperationDocument['kind'];
|
|
922
|
+
@plugins.smartdata.svDb() public purpose!: IStoredAuthorityOperation['purpose'];
|
|
923
|
+
@plugins.smartdata.svDb() public accountId!: string | null;
|
|
924
|
+
@plugins.smartdata.svDb() public grantId!: string | null;
|
|
925
|
+
@plugins.smartdata.svDb() public expectedGrantGeneration?: number | null;
|
|
926
|
+
@plugins.smartdata.svDb() public state!: IStoredAuthorityOperationDocument['state'];
|
|
927
|
+
@plugins.smartdata.svDb() public prompt?: TAuthSwitchLoginPrompt | null;
|
|
928
|
+
@plugins.smartdata.svDb() public result!: IStoredAuthorityOperationDocument['result'];
|
|
929
|
+
@plugins.smartdata.svDb() public error?: string | null;
|
|
930
|
+
@plugins.smartdata.svDb() public commitId?: string | null;
|
|
931
|
+
@plugins.smartdata.svDb() public requestHash?: string;
|
|
932
|
+
@plugins.smartdata.svDb() public requestedModel?: string | null;
|
|
933
|
+
@plugins.smartdata.svDb() public model?: string | null;
|
|
934
|
+
@plugins.smartdata.svDb() public authorizationGeneration?: number;
|
|
935
|
+
@plugins.smartdata.svDb() public grantGeneration?: number | null;
|
|
936
|
+
@plugins.smartdata.svDb() public problem?: TStoredAuthorityPreuseProblem;
|
|
937
|
+
@plugins.smartdata.svDb() public createdAt!: string;
|
|
938
|
+
@plugins.smartdata.svDb() public updatedAt!: string;
|
|
939
|
+
@plugins.smartdata.svDb() public finishedAt!: string | null;
|
|
940
|
+
@plugins.smartdata.svDb() public revision!: number;
|
|
941
|
+
@plugins.smartdata.svDb() public updateId!: string;
|
|
942
|
+
}
|