@modelprofile.com/authswitch 7.0.0 → 8.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 (57) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/authority-contract.d.ts +1 -3
  3. package/dist_ts/authority-contract.js +1 -1
  4. package/dist_ts/classes.authoritybroker.js +1 -5
  5. package/dist_ts/classes.authoritycli.js +2 -2
  6. package/dist_ts/classes.authoritydaemon.js +4 -9
  7. package/dist_ts/classes.authoritydatabase.d.ts +5 -26
  8. package/dist_ts/classes.authoritydatabase.js +49 -129
  9. package/dist_ts/classes.authoritymodels.d.ts +27 -43
  10. package/dist_ts/classes.authoritymodels.js +193 -243
  11. package/dist_ts/classes.authoritypreuse.js +1 -2
  12. package/dist_ts/classes.authorityregistry.d.ts +2 -17
  13. package/dist_ts/classes.authorityregistry.js +18 -74
  14. package/dist_ts/classes.authoritysecrets.d.ts +1 -1
  15. package/dist_ts/classes.authoritysecrets.js +2 -2
  16. package/dist_ts/classes.authorityusage.d.ts +3 -3
  17. package/dist_ts/classes.claudeauthority.js +3 -7
  18. package/dist_ts/classes.claudenative.d.ts +1 -8
  19. package/dist_ts/classes.claudenative.js +2 -25
  20. package/dist_ts/classes.codexmanaged.d.ts +1 -1
  21. package/dist_ts/plugins.d.ts +7 -7
  22. package/dist_ts/plugins.js +8 -8
  23. package/dist_ts/ts_migration/0001_authority_meta.d.ts +13 -3
  24. package/dist_ts/ts_migration/0001_authority_meta.js +29 -17
  25. package/dist_ts/ts_migration/0002_remove_backup_records.d.ts +17 -0
  26. package/dist_ts/ts_migration/0002_remove_backup_records.js +48 -0
  27. package/dist_ts/ts_migration/index.d.ts +6 -3
  28. package/dist_ts/ts_migration/index.js +10 -4
  29. package/package.json +2 -5
  30. package/readme.md +22 -26
  31. package/ts/00_commitinfo_data.ts +1 -1
  32. package/ts/authority-contract.ts +1 -3
  33. package/ts/classes.authoritybroker.ts +0 -4
  34. package/ts/classes.authoritycli.ts +1 -1
  35. package/ts/classes.authoritydaemon.ts +3 -8
  36. package/ts/classes.authoritydatabase.ts +50 -141
  37. package/ts/classes.authoritymodels.ts +232 -269
  38. package/ts/classes.authoritypreuse.ts +0 -1
  39. package/ts/classes.authorityregistry.ts +20 -91
  40. package/ts/classes.authoritysecrets.ts +1 -1
  41. package/ts/classes.authorityusage.ts +3 -3
  42. package/ts/classes.claudeauthority.ts +2 -6
  43. package/ts/classes.claudenative.ts +1 -32
  44. package/ts/classes.codexmanaged.ts +1 -1
  45. package/ts/plugins.ts +7 -7
  46. package/ts/ts_migration/0001_authority_meta.ts +29 -17
  47. package/ts/ts_migration/0002_remove_backup_records.ts +49 -0
  48. package/ts/ts_migration/index.ts +10 -5
  49. package/dist_ts/authorityrehearsal.child.d.ts +0 -1
  50. package/dist_ts/authorityrehearsal.child.js +0 -395
  51. package/dist_ts/classes.authoritybackup.d.ts +0 -134
  52. package/dist_ts/classes.authoritybackup.js +0 -769
  53. package/dist_ts/classes.authorityrehearsal.d.ts +0 -127
  54. package/dist_ts/classes.authorityrehearsal.js +0 -632
  55. package/ts/authorityrehearsal.child.ts +0 -330
  56. package/ts/classes.authoritybackup.ts +0 -780
  57. package/ts/classes.authorityrehearsal.ts +0 -625
@@ -16,9 +16,7 @@ import {
16
16
  type IStoredAuthorityOperation, type IStoredAuthorityPreuseOperation, type IStoredAuthorityUsage,
17
17
  } from './classes.authoritymodels.js';
18
18
  import type { IAuthSwitchStoredUsage, IAuthSwitchUsageContext } from './classes.authorityusage.js';
19
- import { authorityModel, authorityModelRegistry, authorityStoredRecords,
20
- assertAuthorityStoredRecord, type IAuthorityStoredRecord } from './classes.authorityregistry.js';
21
- import type { IAuthorityBackupSnapshotAttempt, IAuthorityBackupSourceCapsule } from './classes.authoritybackup.js';
19
+ import { authorityModelRegistry } from './classes.authorityregistry.js';
22
20
  import { runAuthorityMigrations } from './ts_migration/index.js';
23
21
 
24
22
  export interface IAuthSwitchAuthorityDatabaseOptions {
@@ -26,15 +24,8 @@ export interface IAuthSwitchAuthorityDatabaseOptions {
26
24
  socketPath: string;
27
25
  }
28
26
 
29
- export interface IAuthoritySnapshotCaptureOptions {
30
- /** Recreate capsules on every transaction retry from a source already held under qualified exclusion. */
31
- sourceFactory: () => AsyncIterable<IAuthorityBackupSourceCapsule>;
32
- signal?: AbortSignal;
33
- pageSize?: number;
34
- }
35
-
36
27
  type TEventKind = IStoredAuthorityEvent['kind'];
37
- type TSession = plugins.smartdata.SmartdataSession;
28
+ type TSession = plugins.nosqldb.SmartdataSession;
38
29
  type TStoredAuthorityDeviceOperationAdmission = Omit<IStoredAuthorityDeviceOperation, 'expectedGrantGeneration'>;
39
30
  type TClaudeHandoffDraft = {
40
31
  home: IStoredAuthorityClaudeHome;
@@ -72,10 +63,9 @@ const storedOperation = (stored: Parameters<typeof AuthSwitchAuthorityOperationM
72
63
 
73
64
  /** Separate account, grant, binding and journal records; the only global record is a revision counter. */
74
65
  export class AuthSwitchAuthorityDatabase {
75
- private engine?: plugins.smartdb.LocalSmartDb;
76
- private database?: plugins.smartdata.SmartdataDb;
66
+ private engine?: plugins.nosqldbEngine.LocalNoSqlDb;
67
+ private database?: plugins.nosqldb.SmartdataDb;
77
68
  private started = false;
78
- private mode: 'normal' | 'closed_restore' | null = null;
79
69
 
80
70
  constructor(private readonly options: IAuthSwitchAuthorityDatabaseOptions) {}
81
71
 
@@ -88,20 +78,18 @@ export class AuthSwitchAuthorityDatabase {
88
78
  await plugins.fs.promises.chmod(pathArg, 0o700);
89
79
  }
90
80
 
91
- public async start(options: { mode?: 'normal' | 'closed_restore' } = {}): Promise<void> {
81
+ public async start(): Promise<void> {
92
82
  if (this.started || this.engine || this.database) throw new Error('Authswitch database is already starting or started.');
93
- const mode = options.mode ?? 'normal';
94
- if (mode !== 'normal' && mode !== 'closed_restore') throw new Error('Invalid authority database start mode.');
95
83
  await this.privateDirectory(this.options.dataDirectory);
96
84
  await this.privateDirectory(plugins.path.dirname(this.options.socketPath));
97
- const engine = new plugins.smartdb.LocalSmartDb({ folderPath: this.options.dataDirectory, socketPath: this.options.socketPath });
85
+ const engine = new plugins.nosqldbEngine.LocalNoSqlDb({ folderPath: this.options.dataDirectory, socketPath: this.options.socketPath });
98
86
  this.engine = engine;
99
87
  try {
100
88
  const connection = await engine.start();
101
- const database = new plugins.smartdata.SmartdataDb({ mongoDbUrl: connection.connectionUri, mongoDbName: 'authswitch' });
89
+ const database = new plugins.nosqldb.SmartdataDb({ mongoDbUrl: connection.connectionUri, mongoDbName: 'authswitch' });
102
90
  this.database = database;
103
91
  await database.init();
104
- // The LocalSmartDb root lease excludes another engine during this catalog admission.
92
+ // The LocalNoSqlDb root lease excludes another engine during this catalog admission.
105
93
  const inventory = await database.inspectNamespace({ maxCollections: 1024,
106
94
  documentCountUpTo: 0, timeoutMs: 30_000 });
107
95
  const names = new Set(authorityModelRegistry.map(entry => entry.name));
@@ -111,10 +99,7 @@ export class AuthSwitchAuthorityDatabase {
111
99
  }
112
100
  }
113
101
  const fresh = inventory.collections.length === 0;
114
- if (mode === 'closed_restore' && !fresh) {
115
- throw new Error('Closed authority restore requires an empty database.');
116
- }
117
- if (mode === 'normal' && !fresh) {
102
+ if (!fresh) {
118
103
  if (!inventory.collections.some(item => item.collectionName === 'authswitch_authority_meta')) {
119
104
  throw new Error('Existing authswitch authority database has no metadata collection.');
120
105
  }
@@ -122,19 +107,16 @@ export class AuthSwitchAuthorityDatabase {
122
107
  }
123
108
  await Promise.all(authorityModelRegistry.map(entry => entry.initialize(database)));
124
109
  await Promise.all(authorityModelRegistry.map(entry => entry.prepare()));
125
- if (mode === 'normal') {
126
- if (fresh) {
127
- const initial: IStoredAuthorityMeta = {
128
- id: 'authswitch-authority', schemaVersion: 2, admission: 'open',
129
- epoch: plugins.crypto.randomUUID(), revision: 0, updateId: plugins.crypto.randomUUID(),
130
- };
131
- const result = await AuthSwitchAuthorityMetaModel.exact.insert(initial);
132
- if (result.status !== 'inserted') throw new Error('Authswitch authority could not initialize.');
133
- } else if (!await AuthSwitchAuthorityMetaModel.exact.findStoredOne({ id: 'authswitch-authority' })) {
134
- throw new Error('Existing authswitch authority metadata is missing.');
135
- }
110
+ if (fresh) {
111
+ const initial: IStoredAuthorityMeta = {
112
+ id: 'authswitch-authority',
113
+ epoch: plugins.crypto.randomUUID(), revision: 0, updateId: plugins.crypto.randomUUID(),
114
+ };
115
+ const result = await AuthSwitchAuthorityMetaModel.exact.insert(initial);
116
+ if (result.status !== 'inserted') throw new Error('Authswitch authority could not initialize.');
117
+ } else if (!await AuthSwitchAuthorityMetaModel.exact.findStoredOne({ id: 'authswitch-authority' })) {
118
+ throw new Error('Existing authswitch authority metadata is missing.');
136
119
  }
137
- this.mode = mode;
138
120
  this.started = true;
139
121
  } catch (error) {
140
122
  try { await this.stop(); } catch { /* Preserve the original startup error. */ }
@@ -142,7 +124,7 @@ export class AuthSwitchAuthorityDatabase {
142
124
  }
143
125
  }
144
126
 
145
- private db(): plugins.smartdata.SmartdataDb {
127
+ private db(): plugins.nosqldb.SmartdataDb {
146
128
  if (!this.started || !this.database) throw new Error('Authswitch database is unavailable.');
147
129
  return this.database;
148
130
  }
@@ -156,70 +138,6 @@ export class AuthSwitchAuthorityDatabase {
156
138
  } finally { await session.close(); }
157
139
  }
158
140
 
159
- /** One repeatable SmartData transaction per capture attempt; portable staging happens inside visit. */
160
- public async captureBackupSnapshot(options: IAuthoritySnapshotCaptureOptions,
161
- visit: (attempt: IAuthorityBackupSnapshotAttempt) => Promise<void>): Promise<void> {
162
- if (typeof options.sourceFactory !== 'function' || typeof visit !== 'function') {
163
- throw new Error('Authority backup capture requires an exact source and visitor.');
164
- }
165
- await this.transaction(async session => {
166
- options.signal?.throwIfAborted();
167
- const stored = await AuthSwitchAuthorityMetaModel.exact.findStoredOne({ id: 'authswitch-authority' },
168
- { session, signal: options.signal });
169
- if (!stored) throw new Error('Authority backup metadata is absent.');
170
- const meta = AuthSwitchAuthorityMetaModel.exact.toPersisted(stored);
171
- if (meta.admission !== 'open') throw new Error('Closed restored authority cannot publish a backup.');
172
- let recordsComplete = false;
173
- let sourcesComplete = false;
174
- const records = async function* (): AsyncGenerator<IAuthorityStoredRecord> {
175
- yield* authorityStoredRecords({ session, signal: options.signal, pageSize: options.pageSize });
176
- recordsComplete = true;
177
- };
178
- const sources = async function* (): AsyncGenerator<IAuthorityBackupSourceCapsule> {
179
- for await (const source of options.sourceFactory()) {
180
- options.signal?.throwIfAborted();
181
- yield source;
182
- }
183
- sourcesComplete = true;
184
- };
185
- await visit({ epoch: meta.epoch, revision: meta.revision, records: records(), sources: sources() });
186
- if (!recordsComplete || !sourcesComplete) {
187
- throw new Error('Authority backup visitor did not consume the complete pinned inventory.');
188
- }
189
- return true;
190
- });
191
- }
192
-
193
- /** Reopened closed restore readback uses the same exhaustive registry and stable keyset order. */
194
- public readStoredRecords(options: { signal?: AbortSignal; pageSize?: number } = {}): AsyncIterable<IAuthorityStoredRecord> {
195
- this.db();
196
- return authorityStoredRecords(options);
197
- }
198
-
199
- public async restoreClosedMeta(meta: IStoredAuthorityMeta): Promise<void> {
200
- if (this.mode !== 'closed_restore') throw new Error('Authority database is not a closed restore target.');
201
- const record: IAuthorityStoredRecord = { model: 'authswitch_authority_meta', id: meta.id, value: meta };
202
- assertAuthorityStoredRecord(record);
203
- if (meta.admission !== 'closed_restored') throw new Error('Restored authority metadata must remain closed.');
204
- await authorityModel(record.model).insert(record);
205
- }
206
-
207
- public async insertClosedRestoredRecord(record: IAuthorityStoredRecord): Promise<void> {
208
- if (this.mode !== 'closed_restore' || record.model === 'authswitch_authority_meta') {
209
- throw new Error('Authority database is not admitting this restored record.');
210
- }
211
- if ((await this.readMeta()).admission !== 'closed_restored') {
212
- throw new Error('Closed restore metadata must be installed before records.');
213
- }
214
- assertAuthorityStoredRecord(record);
215
- await authorityModel(record.model).insert(record);
216
- }
217
-
218
- public async assertOpenAdmission(): Promise<void> {
219
- const meta = await this.readMeta();
220
- if (meta.admission !== 'open') throw new Error('Restored authority admission is closed pending ownership reconciliation.');
221
- }
222
-
223
141
  public async readMeta(): Promise<IStoredAuthorityMeta> {
224
142
  this.db();
225
143
  const stored = await AuthSwitchAuthorityMetaModel.exact.findStoredOne({ id: 'authswitch-authority' });
@@ -257,7 +175,7 @@ export class AuthSwitchAuthorityDatabase {
257
175
  return stored.map(item => AuthSwitchAuthorityCodexHomeModel.exact.toPersisted(item));
258
176
  }
259
177
 
260
- /** Home path identity is hashed by the caller; no vendor files or raw paths enter SmartData. */
178
+ /** Home path identity is hashed by the caller; no vendor files or raw paths enter NoSQLDB. */
261
179
  public async reserveCodexHome(accountId: string, grantId: string, scopeId: string, homeId: string,
262
180
  updateId: string): Promise<{ newlyRegistered: boolean }> {
263
181
  try {
@@ -285,7 +203,7 @@ export class AuthSwitchAuthorityDatabase {
285
203
  return { newlyRegistered: true };
286
204
  });
287
205
  } catch (error) {
288
- if (error instanceof plugins.smartdata.SmartdataExactPersistenceError
206
+ if (error instanceof plugins.nosqldb.SmartdataExactPersistenceError
289
207
  && (error.code === 'ambiguous_write' || error.code === 'unique_conflict')) {
290
208
  const assigned = await AuthSwitchAuthorityCodexHomeModel.exact.findStoredOne({ id: homeId });
291
209
  if (assigned?.accountId === accountId && assigned.grantId === grantId && assigned.scopeId === scopeId
@@ -315,7 +233,7 @@ export class AuthSwitchAuthorityDatabase {
315
233
  return true;
316
234
  });
317
235
  } catch (error) {
318
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
236
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
319
237
  const current = await this.readCodexHome(homeId);
320
238
  if (current?.updateId === updateId && JSON.stringify(current.activeRun) === JSON.stringify(activeRun)) return;
321
239
  throw new Error('Managed Codex home run outcome is unknown.');
@@ -428,11 +346,6 @@ export class AuthSwitchAuthorityDatabase {
428
346
  if (!sameRequest(existing)) throw new Error('Account operation ID belongs to a different request.');
429
347
  return { operation: existing, created: false };
430
348
  }
431
- const metaStored = await AuthSwitchAuthorityMetaModel.exact.findStoredOne(
432
- { id: 'authswitch-authority' }, { session });
433
- if (!metaStored || AuthSwitchAuthorityMetaModel.exact.toPersisted(metaStored).admission !== 'open') {
434
- throw new Error('Authswitch authority admission is closed.');
435
- }
436
349
  let expectedGrantGeneration: number | null = null;
437
350
  if (intent.kind === 'reauth_openai') {
438
351
  const accountStored = await AuthSwitchAuthorityAccountModel.exact.findStoredOne(
@@ -456,7 +369,7 @@ export class AuthSwitchAuthorityDatabase {
456
369
  return { operation, created: true };
457
370
  });
458
371
  } catch (error) {
459
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
372
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
460
373
  const stored = await this.readOperation(intent.id);
461
374
  if (stored && sameRequest(stored)) {
462
375
  return { operation: stored, created: stored.updateId === intent.updateId };
@@ -468,13 +381,8 @@ export class AuthSwitchAuthorityDatabase {
468
381
  /** Revalidate the durable owner and exact reauthentication generation after mutable runtime preparation. */
469
382
  public async confirmOperationMayStart(operationId: string): Promise<IStoredAuthorityDeviceOperation> {
470
383
  return this.transaction(async session => {
471
- const metaStored = await AuthSwitchAuthorityMetaModel.exact.findStoredOne(
472
- { id: 'authswitch-authority' }, { session });
473
384
  const operationStored = await AuthSwitchAuthorityOperationModel.exact.findStoredOne(
474
385
  { id: operationId }, { session });
475
- if (!metaStored || AuthSwitchAuthorityMetaModel.exact.toPersisted(metaStored).admission !== 'open') {
476
- throw new Error('Authswitch authority admission is closed.');
477
- }
478
386
  if (!operationStored) throw new Error('Account operation was not found.');
479
387
  const operation = storedOperation(operationStored);
480
388
  if (operation.kind === 'preuse_openai' || operation.state !== 'starting') {
@@ -528,7 +436,7 @@ export class AuthSwitchAuthorityDatabase {
528
436
  if (result.status !== 'transitioned') throw new Error('Account operation changed concurrently.');
529
437
  return draft;
530
438
  } catch (error) {
531
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
439
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
532
440
  const stored = await this.readOperation(operationId);
533
441
  if (stored?.kind !== 'preuse_openai' && stored?.updateId === updateId) return stored;
534
442
  throw new Error('Account operation transition outcome is unknown.');
@@ -569,7 +477,7 @@ export class AuthSwitchAuthorityDatabase {
569
477
  return { operation, created: true };
570
478
  });
571
479
  } catch (error) {
572
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
480
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
573
481
  const stored = await this.readOperation(operation.id);
574
482
  if (stored && sameRequest(stored) && stored.updateId === operation.updateId) {
575
483
  return { operation: stored, created: true };
@@ -611,7 +519,7 @@ export class AuthSwitchAuthorityDatabase {
611
519
  return draft;
612
520
  });
613
521
  } catch (error) {
614
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
522
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
615
523
  const stored = await this.readOperation(operationId);
616
524
  if (stored?.kind === 'preuse_openai' && stored.updateId === updateId
617
525
  && stored.state === 'request_may_have_started') return stored;
@@ -648,7 +556,7 @@ export class AuthSwitchAuthorityDatabase {
648
556
  if (result.status !== 'transitioned') throw new Error('Preuse operation changed concurrently.');
649
557
  return draft;
650
558
  } catch (error) {
651
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
559
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
652
560
  const stored = await this.readOperation(operationId);
653
561
  if (stored?.kind === 'preuse_openai' && stored.updateId === updateId) return stored;
654
562
  throw new Error('Preuse operation transition outcome is unknown.');
@@ -806,7 +714,7 @@ export class AuthSwitchAuthorityDatabase {
806
714
  return true;
807
715
  });
808
716
  } catch (error) {
809
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError)) throw error;
717
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError)) throw error;
810
718
  if (error.code === 'unique_conflict') return false;
811
719
  if (error.code !== 'ambiguous_write') throw error;
812
720
  const [stored, event] = await Promise.all([
@@ -1076,7 +984,7 @@ export class AuthSwitchAuthorityDatabase {
1076
984
  return { meta, ...draft };
1077
985
  });
1078
986
  } catch (error) {
1079
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
987
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1080
988
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1081
989
  const { account, grant } = await this.readAccountAndPrimaryGrant(accountId);
1082
990
  if (event && account?.updateId === updateId && grant?.updateId === updateId) {
@@ -1141,7 +1049,7 @@ export class AuthSwitchAuthorityDatabase {
1141
1049
  return { ...draft, operation: completed };
1142
1050
  });
1143
1051
  } catch (error) {
1144
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1052
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1145
1053
  const [event, operation, pair] = await Promise.all([
1146
1054
  AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId }),
1147
1055
  this.readOperation(operationId), this.readAccountAndPrimaryGrant(accountId),
@@ -1176,7 +1084,7 @@ export class AuthSwitchAuthorityDatabase {
1176
1084
  if (grant.purpose === 'claude_host_native' && draft.state === 'exchange_may_have_been_sent'
1177
1085
  && grant.state !== 'exchange_may_have_been_sent'
1178
1086
  && !(await this.hasVerifiedClaudeGrantReceipt(account.id, grant.id, session))) {
1179
- throw new Error('Claude refresh requires a verified import and backup receipt.');
1087
+ throw new Error('Claude refresh requires a verified import receipt.');
1180
1088
  }
1181
1089
  const accountDraft: IStoredAuthorityAccount = { ...account, revision: account.revision + 1,
1182
1090
  statusObservedAt: draft.statusObservedAt, updateId };
@@ -1187,7 +1095,7 @@ export class AuthSwitchAuthorityDatabase {
1187
1095
  return { meta, account: accountDraft, grant: draft };
1188
1096
  });
1189
1097
  } catch (error) {
1190
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1098
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1191
1099
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1192
1100
  const grant = await this.readGrant(grantId);
1193
1101
  const account = grant ? await this.readAccount(grant.accountId) : null;
@@ -1225,7 +1133,7 @@ export class AuthSwitchAuthorityDatabase {
1225
1133
  return { account: updatedAccount, grant: draft };
1226
1134
  });
1227
1135
  } catch (error) {
1228
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1136
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1229
1137
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1230
1138
  const account = await this.readAccount(accountId);
1231
1139
  const grant = await this.readGrant(grantId);
@@ -1315,7 +1223,7 @@ export class AuthSwitchAuthorityDatabase {
1315
1223
  return removed;
1316
1224
  });
1317
1225
  } catch (error) {
1318
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1226
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1319
1227
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1320
1228
  const account = await this.readAccount(accountId);
1321
1229
  if (event && account?.removed && account.updateId === updateId) return account;
@@ -1341,7 +1249,7 @@ export class AuthSwitchAuthorityDatabase {
1341
1249
  return { meta, account: draft };
1342
1250
  });
1343
1251
  } catch (error) {
1344
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1252
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1345
1253
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1346
1254
  const account = await this.readAccount(accountId);
1347
1255
  if (event && account?.updateId === updateId) return { meta: await this.readMeta(), account };
@@ -1386,7 +1294,7 @@ export class AuthSwitchAuthorityDatabase {
1386
1294
  return { meta, binding: draft };
1387
1295
  });
1388
1296
  } catch (error) {
1389
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1297
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1390
1298
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1391
1299
  const binding = await this.readBinding(bindingId);
1392
1300
  if (event && binding?.updateId === updateId) return { meta: await this.readMeta(), binding };
@@ -1410,7 +1318,7 @@ export class AuthSwitchAuthorityDatabase {
1410
1318
  return true;
1411
1319
  });
1412
1320
  } catch (error) {
1413
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1321
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1414
1322
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1415
1323
  const binding = await this.readBinding(bindingId);
1416
1324
  // Every bind mints a fresh random capability. An event plus absence or a different
@@ -1458,7 +1366,7 @@ export class AuthSwitchAuthorityDatabase {
1458
1366
  return draft;
1459
1367
  });
1460
1368
  } catch (error) {
1461
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1369
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1462
1370
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1463
1371
  const enrollment = await this.readEnrollment(enrollmentId);
1464
1372
  if (event && enrollment?.updateId === updateId) return enrollment;
@@ -1540,7 +1448,7 @@ export class AuthSwitchAuthorityDatabase {
1540
1448
  return draft;
1541
1449
  });
1542
1450
  } catch (error) {
1543
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1451
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1544
1452
  const event = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: updateId });
1545
1453
  const handoff = await this.readHandoff(handoffId);
1546
1454
  const grant = await this.readGrant(grantId);
@@ -1563,7 +1471,7 @@ export class AuthSwitchAuthorityDatabase {
1563
1471
  return stored ? AuthSwitchAuthorityClaudeHandoffModel.exact.toPersisted(stored) : null;
1564
1472
  }
1565
1473
 
1566
- /** A backed-up backend import receipt, not an account snapshot, authorizes an inactive Claude grant. */
1474
+ /** A verified backend import receipt, not an account snapshot, authorizes an inactive Claude grant. */
1567
1475
  public async hasVerifiedClaudeGrantReceipt(accountId: string, grantId: string,
1568
1476
  session?: TSession): Promise<boolean> {
1569
1477
  this.db();
@@ -1575,7 +1483,6 @@ export class AuthSwitchAuthorityDatabase {
1575
1483
  filter: { grantId, status }, sort: { id: 1 }, limit: 128, session,
1576
1484
  });
1577
1485
  if (stored.some(item => item.accountId === accountId
1578
- && item.backupDigest !== null
1579
1486
  && ['authswitch_stash', 'authswitch_backup', 'claude_native'].includes(item.sourceKind))) return true;
1580
1487
  if (stored.length === 128) throw new Error('Claude grant has too many migration receipts to verify.');
1581
1488
  }
@@ -1623,7 +1530,6 @@ export class AuthSwitchAuthorityDatabase {
1623
1530
  const grantStored = await AuthSwitchAuthorityGrantModel.exact.findStoredOne({ id: grantId }, { session });
1624
1531
  const current = await AuthSwitchAuthorityClaudeHomeModel.exact.findStoredOne({ id: homeId }, { session });
1625
1532
  if (!receiptStored || !['verified', 'complete'].includes(receiptStored.status)
1626
- || receiptStored.backupDigest === null
1627
1533
  || receiptStored.sourceKind !== 'claude_native' || receiptStored.sourcePathHash !== homeId
1628
1534
  || receiptStored.sourceDigest !== sourceDigest || receiptStored.accountId !== accountId
1629
1535
  || receiptStored.grantId !== grantId || !accountStored || accountStored.removed
@@ -1649,7 +1555,7 @@ export class AuthSwitchAuthorityDatabase {
1649
1555
  return home;
1650
1556
  });
1651
1557
  } catch (error) {
1652
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError)
1558
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError)
1653
1559
  || !['ambiguous_write', 'unique_conflict'].includes(error.code)) throw error;
1654
1560
  const home = await this.readClaudeHome(homeId);
1655
1561
  if (home?.updateId === updateId && home.activeAccountId === accountId && home.activeGrantId === grantId) return home;
@@ -1772,7 +1678,6 @@ export class AuthSwitchAuthorityDatabase {
1772
1678
  });
1773
1679
  if (receipts.length === 128) throw new Error('Claude grant receipt set is unbounded.');
1774
1680
  verifiedIncoming ||= receipts.some(item => item.accountId === incoming.accountId
1775
- && item.backupDigest !== null
1776
1681
  && ['authswitch_stash', 'authswitch_backup', 'claude_native'].includes(item.sourceKind));
1777
1682
  }
1778
1683
  if (draft.handoff.phase !== 'reserved' || home.pendingOperationId !== null
@@ -1843,7 +1748,7 @@ export class AuthSwitchAuthorityDatabase {
1843
1748
  return draft;
1844
1749
  });
1845
1750
  } catch (error) {
1846
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1751
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1847
1752
  const context = await this.readClaudeHandoffContext(operationId);
1848
1753
  const first = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: eventIds[0] });
1849
1754
  const second = await AuthSwitchAuthorityEventModel.exact.findStoredOne({ id: eventIds[1] });
@@ -1860,7 +1765,7 @@ export class AuthSwitchAuthorityDatabase {
1860
1765
  }
1861
1766
  }
1862
1767
 
1863
- /** Ledger transitions never silently replace an active credential or waive backup proof. */
1768
+ /** Ledger transitions never silently replace an active credential or waive the verified import. */
1864
1769
  public async changeMigrationLedger(updateId: string, ledgerId: string,
1865
1770
  change: (current: IStoredAuthorityMigrationLedger | null) => IStoredAuthorityMigrationLedger): Promise<IStoredAuthorityMigrationLedger> {
1866
1771
  try {
@@ -1869,7 +1774,12 @@ export class AuthSwitchAuthorityDatabase {
1869
1774
  const draft = change(current ? structuredClone(AuthSwitchAuthorityMigrationLedgerModel.exact.toPersisted(current)) : null);
1870
1775
  if (draft.id !== ledgerId || draft.updateId !== updateId) throw new Error('Migration ledger identity is invalid.');
1871
1776
  assertStoredAuthorityMigrationLedger(draft);
1872
- if (draft.status === 'complete' && draft.backupDigest === null) throw new Error('Migration completion requires verified backup proof.');
1777
+ // A source may only be considered migrated after a verified import bound to an account, a grant and a
1778
+ // source digest. This deliberately tightens a flow that has no production caller and has never run.
1779
+ if (draft.status === 'complete' && (current?.status !== 'verified'
1780
+ || current.accountId !== draft.accountId || current.grantId !== draft.grantId)) {
1781
+ throw new Error('Migration completion requires a verified import of the same account and grant.');
1782
+ }
1873
1783
  if (current) {
1874
1784
  if (current.status === 'complete' || current.version !== draft.version
1875
1785
  || current.sourceKind !== draft.sourceKind || current.sourcePathHash !== draft.sourcePathHash
@@ -1888,7 +1798,7 @@ export class AuthSwitchAuthorityDatabase {
1888
1798
  return draft;
1889
1799
  });
1890
1800
  } catch (error) {
1891
- if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1801
+ if (!(error instanceof plugins.nosqldb.SmartdataExactPersistenceError) || error.code !== 'ambiguous_write') throw error;
1892
1802
  const ledger = await this.readMigrationLedger(ledgerId);
1893
1803
  if (ledger?.updateId === updateId) return ledger;
1894
1804
  throw new Error('Authswitch migration ledger write outcome is unknown.');
@@ -1897,7 +1807,6 @@ export class AuthSwitchAuthorityDatabase {
1897
1807
 
1898
1808
  public async stop(): Promise<void> {
1899
1809
  this.started = false;
1900
- this.mode = null;
1901
1810
  const database = this.database;
1902
1811
  const engine = this.engine;
1903
1812
  this.database = undefined;