@modelprofile.com/authswitch 6.5.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.
Files changed (98) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/authority-contract.d.ts +302 -6
  3. package/dist_ts/authority-contract.js +1 -1
  4. package/dist_ts/authority-runtime-contract.d.ts +13 -0
  5. package/dist_ts/authorityrehearsal.child.d.ts +1 -0
  6. package/dist_ts/authorityrehearsal.child.js +395 -0
  7. package/dist_ts/classes.accountlist.js +4 -3
  8. package/dist_ts/classes.authoritybackup.d.ts +134 -0
  9. package/dist_ts/classes.authoritybackup.js +769 -0
  10. package/dist_ts/classes.authoritybroker.d.ts +25 -5
  11. package/dist_ts/classes.authoritybroker.js +392 -123
  12. package/dist_ts/classes.authoritycli.d.ts +24 -0
  13. package/dist_ts/classes.authoritycli.js +675 -0
  14. package/dist_ts/classes.authorityclient.d.ts +19 -7
  15. package/dist_ts/classes.authorityclient.js +51 -14
  16. package/dist_ts/classes.authoritydaemon.d.ts +28 -1
  17. package/dist_ts/classes.authoritydaemon.js +482 -36
  18. package/dist_ts/classes.authoritydatabase.d.ts +175 -10
  19. package/dist_ts/classes.authoritydatabase.js +1100 -52
  20. package/dist_ts/classes.authoritymodels.d.ts +223 -1
  21. package/dist_ts/classes.authoritymodels.js +798 -9
  22. package/dist_ts/classes.authoritypreuse.d.ts +47 -0
  23. package/dist_ts/classes.authoritypreuse.js +278 -0
  24. package/dist_ts/classes.authorityregistry.d.ts +24 -0
  25. package/dist_ts/classes.authorityregistry.js +88 -0
  26. package/dist_ts/classes.authorityrehearsal.d.ts +127 -0
  27. package/dist_ts/classes.authorityrehearsal.js +632 -0
  28. package/dist_ts/classes.authorityusage.d.ts +160 -0
  29. package/dist_ts/classes.authorityusage.js +429 -0
  30. package/dist_ts/classes.claudeauthority.d.ts +66 -0
  31. package/dist_ts/classes.claudeauthority.js +532 -0
  32. package/dist_ts/classes.claudecodeharness.js +3 -2
  33. package/dist_ts/classes.claudecodelocks.d.ts +13 -0
  34. package/dist_ts/classes.claudecodelocks.js +75 -3
  35. package/dist_ts/classes.claudenative.d.ts +137 -0
  36. package/dist_ts/classes.claudenative.js +731 -0
  37. package/dist_ts/classes.claudestatus.d.ts +9 -0
  38. package/dist_ts/classes.claudestatus.js +26 -9
  39. package/dist_ts/classes.claudetokenrefresh.d.ts +15 -1
  40. package/dist_ts/classes.claudetokenrefresh.js +74 -21
  41. package/dist_ts/classes.codexharness.js +4 -2
  42. package/dist_ts/classes.codexmanaged.d.ts +11 -0
  43. package/dist_ts/classes.codexmanaged.js +75 -14
  44. package/dist_ts/classes.codexpreuse.d.ts +8 -0
  45. package/dist_ts/classes.codexpreuse.js +24 -6
  46. package/dist_ts/classes.fileharness.d.ts +2 -0
  47. package/dist_ts/classes.fileharness.js +6 -4
  48. package/dist_ts/classes.limits.js +12 -7
  49. package/dist_ts/classes.opencodeharness.js +2 -2
  50. package/dist_ts/claudehttp.d.ts +10 -0
  51. package/dist_ts/claudehttp.js +29 -3
  52. package/dist_ts/index.d.ts +1 -0
  53. package/dist_ts/index.js +7 -1
  54. package/dist_ts/interfaces.harness.d.ts +6 -0
  55. package/dist_ts/interfaces.list.d.ts +9 -3
  56. package/dist_ts/plugins.d.ts +5 -2
  57. package/dist_ts/plugins.js +7 -3
  58. package/dist_ts/ts_migration/0001_authority_meta.d.ts +3 -0
  59. package/dist_ts/ts_migration/0001_authority_meta.js +32 -0
  60. package/dist_ts/ts_migration/index.d.ts +3 -0
  61. package/dist_ts/ts_migration/index.js +6 -0
  62. package/package.json +4 -1
  63. package/readme.md +181 -14
  64. package/ts/00_commitinfo_data.ts +1 -1
  65. package/ts/authority-contract.ts +264 -9
  66. package/ts/authority-runtime-contract.ts +14 -0
  67. package/ts/authorityrehearsal.child.ts +330 -0
  68. package/ts/classes.accountlist.ts +3 -2
  69. package/ts/classes.authoritybackup.ts +780 -0
  70. package/ts/classes.authoritybroker.ts +389 -121
  71. package/ts/classes.authoritycli.ts +719 -0
  72. package/ts/classes.authorityclient.ts +75 -18
  73. package/ts/classes.authoritydaemon.ts +449 -36
  74. package/ts/classes.authoritydatabase.ts +1147 -55
  75. package/ts/classes.authoritymodels.ts +541 -6
  76. package/ts/classes.authoritypreuse.ts +297 -0
  77. package/ts/classes.authorityregistry.ts +118 -0
  78. package/ts/classes.authorityrehearsal.ts +625 -0
  79. package/ts/classes.authorityusage.ts +527 -0
  80. package/ts/classes.claudeauthority.ts +541 -0
  81. package/ts/classes.claudecodeharness.ts +2 -1
  82. package/ts/classes.claudecodelocks.ts +70 -1
  83. package/ts/classes.claudenative.ts +816 -0
  84. package/ts/classes.claudestatus.ts +38 -9
  85. package/ts/classes.claudetokenrefresh.ts +82 -19
  86. package/ts/classes.codexharness.ts +3 -1
  87. package/ts/classes.codexmanaged.ts +75 -12
  88. package/ts/classes.codexpreuse.ts +33 -5
  89. package/ts/classes.fileharness.ts +7 -3
  90. package/ts/classes.limits.ts +11 -6
  91. package/ts/classes.opencodeharness.ts +1 -1
  92. package/ts/claudehttp.ts +31 -2
  93. package/ts/index.ts +6 -0
  94. package/ts/interfaces.harness.ts +6 -0
  95. package/ts/interfaces.list.ts +9 -3
  96. package/ts/plugins.ts +7 -2
  97. package/ts/ts_migration/0001_authority_meta.ts +33 -0
  98. 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;
@@ -75,12 +89,59 @@ export interface IStoredAuthorityEnrollment {
75
89
  export interface IStoredAuthorityCodexHome {
76
90
  id: string;
77
91
  accountId: string;
92
+ grantId: string;
78
93
  scopeId: string;
79
94
  activeRun: { id: string; socketPath: string; pid: number | null; startedAt: string | null } | null;
80
95
  createdAt: string;
81
96
  updateId: string;
82
97
  }
83
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
+
84
145
  /** Journal for a native-home handoff. A prepared grant is never usable. */
85
146
  export interface IStoredAuthorityHandoff {
86
147
  id: string;
@@ -122,6 +183,82 @@ export interface IStoredAuthorityEvent {
122
183
  accountId: string;
123
184
  }
124
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
+
125
262
  const object = (value: unknown): value is Record<string, unknown> =>
126
263
  value !== null && typeof value === 'object' && !Array.isArray(value)
127
264
  && [Object.prototype, null].includes(Object.getPrototypeOf(value));
@@ -137,9 +274,110 @@ const revision = (value: unknown): value is number => Number.isSafeInteger(value
137
274
  const ciphertext = (value: unknown): boolean => value === null
138
275
  || (typeof value === 'string' && value.length > 0 && value.length <= 131072 && /^[A-Za-z0-9_-]+$/.test(value));
139
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
+
140
377
  export const assertStoredAuthorityMeta: (value: unknown) => asserts value is IStoredAuthorityMeta = value => {
141
- if (!object(value) || !exactKeys(value, ['id', 'epoch', 'revision', 'updateId'])
142
- || value.id !== 'authswitch-authority' || !uuid(value.epoch)
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)
143
381
  || !revision(value.revision) || !uuid(value.updateId)) throw new Error('Invalid authswitch authority metadata.');
144
382
  };
145
383
 
@@ -164,7 +402,7 @@ export const assertStoredAuthorityGrant: (value: unknown) => asserts value is IS
164
402
  || typeof value.providerId !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(value.providerId)
165
403
  || !['openai_managed', 'claude_host_native', 'claude_container_setup', 'opencode_native'].includes(String(value.purpose))
166
404
  || !bounded(value.audience)
167
- || !['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))
168
406
  || !['daemon', 'claude_native', 'legacy_native', 'none'].includes(String(value.owner))
169
407
  || !revision(value.grantGeneration) || !revision(value.authorizationGeneration)
170
408
  || !revision(value.revision) || !ciphertext(value.ciphertext)
@@ -180,6 +418,13 @@ export const assertStoredAuthorityGrant: (value: unknown) => asserts value is IS
180
418
  if ((value.state === 'retry_wait') !== (value.retryAt !== null)) throw new Error('Invalid refresh retry marker.');
181
419
  if (value.state === 'removed' && (value.ciphertext !== null || value.owner !== 'none')) throw new Error('A removed grant was retained.');
182
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
+ }
183
428
  if (value.purpose === 'openai_managed' && value.providerId !== 'openai') throw new Error('OpenAI grant provider mismatch.');
184
429
  if (value.purpose === 'claude_container_setup' && value.owner === 'claude_native') throw new Error('Container setup grant has a native host owner.');
185
430
  };
@@ -202,8 +447,8 @@ export const assertStoredAuthorityEnrollment: (value: unknown) => asserts value
202
447
  };
203
448
 
204
449
  export const assertStoredAuthorityCodexHome: (value: unknown) => asserts value is IStoredAuthorityCodexHome = value => {
205
- if (!object(value) || !exactKeys(value, ['id', 'accountId', 'scopeId', 'activeRun', 'createdAt', 'updateId'])
206
- || !hash(value.id) || !hash(value.accountId) || !bounded(value.scopeId)
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)
207
452
  || !iso(value.createdAt) || !uuid(value.updateId)) {
208
453
  throw new Error('Invalid managed Codex home assignment.');
209
454
  }
@@ -218,6 +463,58 @@ export const assertStoredAuthorityCodexHome: (value: unknown) => asserts value i
218
463
  }
219
464
  };
220
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
+
221
518
  export const assertStoredAuthorityHandoff: (value: unknown) => asserts value is IStoredAuthorityHandoff = value => {
222
519
  if (!object(value) || !exactKeys(value, ['id', 'accountId', 'grantId', 'nativeHomeId', 'direction', 'phase',
223
520
  'operationId', 'sourceDigest', 'verifiedSourceDigest', 'backupDigest', 'revision', 'statusObservedAt', 'updateId'])
@@ -257,11 +554,154 @@ export const assertStoredAuthorityEvent: (value: unknown) => asserts value is IS
257
554
  || !['account', 'binding'].includes(String(value.kind)) || !hash(value.accountId)) throw new Error('Invalid authswitch event record.');
258
555
  };
259
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
+
260
698
  @plugins.smartdata.managed({ collectionName: 'authswitch_authority_meta' })
261
699
  @plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityMeta })
262
700
  export class AuthSwitchAuthorityMetaModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityMetaModel, IStoredAuthorityMeta> {
263
701
  declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityMetaModel>;
264
702
  @plugins.smartdata.unI() public id!: 'authswitch-authority';
703
+ @plugins.smartdata.svDb() public schemaVersion!: 2;
704
+ @plugins.smartdata.svDb() public admission!: IStoredAuthorityMeta['admission'];
265
705
  @plugins.smartdata.svDb() public epoch!: string;
266
706
  @plugins.smartdata.svDb() public revision!: number;
267
707
  @plugins.smartdata.svDb() public updateId!: string;
@@ -313,6 +753,26 @@ export class AuthSwitchAuthorityGrantModel extends plugins.smartdata.SmartDataDb
313
753
  @plugins.smartdata.svDb() public updateId!: string;
314
754
  }
315
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
+
316
776
  @plugins.smartdata.compoundIndex({ name: 'authority_binding_account_id', key: { accountId: 1, id: 1 } })
317
777
  @plugins.smartdata.managed({ collectionName: 'authswitch_authority_bindings' })
318
778
  @plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityBinding })
@@ -349,12 +809,55 @@ export class AuthSwitchAuthorityCodexHomeModel extends plugins.smartdata.SmartDa
349
809
  declare static exact: plugins.smartdata.TExact<AuthSwitchAuthorityCodexHomeModel>;
350
810
  @plugins.smartdata.unI() public id!: string;
351
811
  @plugins.smartdata.svDb() public accountId!: string;
812
+ @plugins.smartdata.svDb() public grantId!: string;
352
813
  @plugins.smartdata.svDb() public scopeId!: string;
353
814
  @plugins.smartdata.svDb() public activeRun!: IStoredAuthorityCodexHome['activeRun'];
354
815
  @plugins.smartdata.svDb() public createdAt!: string;
355
816
  @plugins.smartdata.svDb() public updateId!: string;
356
817
  }
357
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
+
358
861
  @plugins.smartdata.compoundIndex({ name: 'authority_handoff_grant_id', key: { grantId: 1, id: 1 } })
359
862
  @plugins.smartdata.managed({ collectionName: 'authswitch_authority_handoffs' })
360
863
  @plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityHandoff })
@@ -376,6 +879,7 @@ export class AuthSwitchAuthorityHandoffModel extends plugins.smartdata.SmartData
376
879
  }
377
880
 
378
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 } })
379
883
  @plugins.smartdata.managed({ collectionName: 'authswitch_authority_migration_ledger' })
380
884
  @plugins.smartdata.exactPersistence({ assertDocument: assertStoredAuthorityMigrationLedger })
381
885
  export class AuthSwitchAuthorityMigrationLedgerModel extends plugins.smartdata.SmartDataDbDoc<AuthSwitchAuthorityMigrationLedgerModel, IStoredAuthorityMigrationLedger> {
@@ -405,3 +909,34 @@ export class AuthSwitchAuthorityEventModel extends plugins.smartdata.SmartDataDb
405
909
  @plugins.smartdata.svDb() public kind!: IStoredAuthorityEvent['kind'];
406
910
  @plugins.smartdata.svDb() public accountId!: string;
407
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
+ }