@enbox/auth 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/esm/auth-manager.js +240 -171
  2. package/dist/esm/auth-manager.js.map +1 -1
  3. package/dist/esm/connect/import.js +131 -0
  4. package/dist/esm/connect/import.js.map +1 -0
  5. package/dist/esm/connect/lifecycle.js +378 -0
  6. package/dist/esm/connect/lifecycle.js.map +1 -0
  7. package/dist/esm/connect/local.js +105 -0
  8. package/dist/esm/connect/local.js.map +1 -0
  9. package/dist/esm/connect/restore.js +117 -0
  10. package/dist/esm/connect/restore.js.map +1 -0
  11. package/dist/esm/connect/wallet.js +80 -0
  12. package/dist/esm/connect/wallet.js.map +1 -0
  13. package/dist/esm/{flows/dwn-discovery.js → discovery.js} +2 -2
  14. package/dist/esm/discovery.js.map +1 -0
  15. package/dist/esm/index.js +13 -19
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/permissions.js +41 -0
  18. package/dist/esm/permissions.js.map +1 -0
  19. package/dist/esm/{flows/dwn-registration.js → registration.js} +2 -2
  20. package/dist/esm/registration.js.map +1 -0
  21. package/dist/esm/types.js +4 -0
  22. package/dist/esm/types.js.map +1 -1
  23. package/dist/esm/wallet-connect-client.js +188 -0
  24. package/dist/esm/wallet-connect-client.js.map +1 -0
  25. package/dist/types/auth-manager.d.ts +89 -11
  26. package/dist/types/auth-manager.d.ts.map +1 -1
  27. package/dist/types/connect/import.d.ts +25 -0
  28. package/dist/types/connect/import.d.ts.map +1 -0
  29. package/dist/types/connect/lifecycle.d.ts +199 -0
  30. package/dist/types/connect/lifecycle.d.ts.map +1 -0
  31. package/dist/types/connect/local.d.ts +23 -0
  32. package/dist/types/connect/local.d.ts.map +1 -0
  33. package/dist/types/connect/restore.d.ts +18 -0
  34. package/dist/types/connect/restore.d.ts.map +1 -0
  35. package/dist/types/connect/wallet.d.ts +21 -0
  36. package/dist/types/connect/wallet.d.ts.map +1 -0
  37. package/dist/types/{flows/dwn-discovery.d.ts → discovery.d.ts} +3 -3
  38. package/dist/types/discovery.d.ts.map +1 -0
  39. package/dist/types/index.d.ts +14 -19
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/types/permissions.d.ts +18 -0
  42. package/dist/types/permissions.d.ts.map +1 -0
  43. package/dist/types/{flows/dwn-registration.d.ts → registration.d.ts} +2 -2
  44. package/dist/types/registration.d.ts.map +1 -0
  45. package/dist/types/types.d.ts +154 -4
  46. package/dist/types/types.d.ts.map +1 -1
  47. package/dist/types/wallet-connect-client.d.ts +86 -0
  48. package/dist/types/wallet-connect-client.d.ts.map +1 -0
  49. package/package.json +9 -5
  50. package/src/auth-manager.ts +258 -191
  51. package/src/connect/import.ts +148 -0
  52. package/src/connect/lifecycle.ts +487 -0
  53. package/src/connect/local.ts +116 -0
  54. package/src/connect/restore.ts +133 -0
  55. package/src/connect/wallet.ts +89 -0
  56. package/src/{flows/dwn-discovery.ts → discovery.ts} +4 -3
  57. package/src/index.ts +20 -19
  58. package/src/permissions.ts +48 -0
  59. package/src/{flows/dwn-registration.ts → registration.ts} +2 -2
  60. package/src/types.ts +171 -4
  61. package/src/wallet-connect-client.ts +275 -0
  62. package/dist/esm/flows/dwn-discovery.js.map +0 -1
  63. package/dist/esm/flows/dwn-registration.js.map +0 -1
  64. package/dist/esm/flows/import-identity.js +0 -177
  65. package/dist/esm/flows/import-identity.js.map +0 -1
  66. package/dist/esm/flows/local-connect.js +0 -158
  67. package/dist/esm/flows/local-connect.js.map +0 -1
  68. package/dist/esm/flows/session-restore.js +0 -125
  69. package/dist/esm/flows/session-restore.js.map +0 -1
  70. package/dist/esm/flows/wallet-connect.js +0 -200
  71. package/dist/esm/flows/wallet-connect.js.map +0 -1
  72. package/dist/esm/vault/vault-manager.js +0 -95
  73. package/dist/esm/vault/vault-manager.js.map +0 -1
  74. package/dist/types/flows/dwn-discovery.d.ts.map +0 -1
  75. package/dist/types/flows/dwn-registration.d.ts.map +0 -1
  76. package/dist/types/flows/import-identity.d.ts +0 -35
  77. package/dist/types/flows/import-identity.d.ts.map +0 -1
  78. package/dist/types/flows/local-connect.d.ts +0 -31
  79. package/dist/types/flows/local-connect.d.ts.map +0 -1
  80. package/dist/types/flows/session-restore.d.ts +0 -29
  81. package/dist/types/flows/session-restore.d.ts.map +0 -1
  82. package/dist/types/flows/wallet-connect.d.ts +0 -44
  83. package/dist/types/flows/wallet-connect.d.ts.map +0 -1
  84. package/dist/types/vault/vault-manager.d.ts +0 -57
  85. package/dist/types/vault/vault-manager.d.ts.map +0 -1
  86. package/src/flows/import-identity.ts +0 -219
  87. package/src/flows/local-connect.ts +0 -192
  88. package/src/flows/session-restore.ts +0 -155
  89. package/src/flows/wallet-connect.ts +0 -226
  90. package/src/vault/vault-manager.ts +0 -89
@@ -18,13 +18,14 @@ import { EnboxUserAgent } from '@enbox/agent';
18
18
  import { AuthEventEmitter } from './events.js';
19
19
  import { AuthSession } from './identity-session.js';
20
20
  import { createDefaultStorage } from './storage/storage.js';
21
- import { discoverLocalDwn } from './flows/dwn-discovery.js';
22
- import { localConnect } from './flows/local-connect.js';
23
- import { restoreSession } from './flows/session-restore.js';
21
+ import { discoverLocalDwn } from './discovery.js';
22
+ import { localConnect } from './connect/local.js';
23
+ import { normalizeProtocolRequests } from './permissions.js';
24
+ import { restoreSession } from './connect/restore.js';
24
25
  import { STORAGE_KEYS } from './types.js';
25
- import { VaultManager } from './vault/vault-manager.js';
26
- import { walletConnect } from './flows/wallet-connect.js';
27
- import { importFromPhrase, importFromPortable } from './flows/import-identity.js';
26
+ import { walletConnect } from './connect/wallet.js';
27
+ import { ensureVaultReady, finalizeDelegateSession, importDelegateAndSetupSync, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './connect/lifecycle.js';
28
+ import { importFromPhrase, importFromPortable } from './connect/import.js';
28
29
  /**
29
30
  * The primary entry point for authentication and identity management.
30
31
  *
@@ -66,13 +67,13 @@ export class AuthManager {
66
67
  this._userAgent = params.userAgent;
67
68
  this._emitter = params.emitter;
68
69
  this._storage = params.storage;
69
- this._vault = params.vault;
70
70
  this._defaultPassword = params.defaultPassword;
71
71
  this._passwordProvider = params.passwordProvider;
72
72
  this._defaultSync = params.defaultSync;
73
73
  this._defaultDwnEndpoints = params.defaultDwnEndpoints;
74
74
  this._registration = params.registration;
75
75
  this._localDwnEndpoint = params.localDwnEndpoint;
76
+ this._connectHandler = params.connectHandler;
76
77
  }
77
78
  /**
78
79
  * Create a new AuthManager instance.
@@ -110,22 +111,21 @@ export class AuthManager {
110
111
  localDwnStrategy: options.localDwnStrategy,
111
112
  localDwnEndpoint,
112
113
  });
113
- const vault = new VaultManager(userAgent.vault, emitter);
114
114
  const manager = new AuthManager({
115
115
  userAgent,
116
116
  emitter,
117
117
  storage,
118
- vault,
119
118
  defaultPassword: options.password,
120
119
  passwordProvider: options.passwordProvider,
121
120
  defaultSync: options.sync,
122
121
  defaultDwnEndpoints: options.dwnEndpoints,
123
122
  registration: options.registration,
124
123
  localDwnEndpoint,
124
+ connectHandler: options.connectHandler,
125
125
  });
126
126
  // Determine initial state.
127
- if (yield vault.isInitialized()) {
128
- manager._setState(vault.isLocked ? 'locked' : 'unlocked');
127
+ if (yield userAgent.vault.isInitialized()) {
128
+ manager._setState(userAgent.vault.isLocked() ? 'locked' : 'unlocked');
129
129
  }
130
130
  else {
131
131
  manager._setState('uninitialized');
@@ -135,37 +135,77 @@ export class AuthManager {
135
135
  }
136
136
  // ─── Connection flows ──────────────────────────────────────────
137
137
  /**
138
- * Create or reconnect a local identity.
138
+ * Connect to a wallet or create a local session.
139
139
  *
140
- * On first use, this creates a new vault, agent DID, and user identity.
141
- * On subsequent uses, it unlocks the vault and reconnects.
140
+ * This is the primary entry point for dapps. It routes to the
141
+ * appropriate flow based on the options:
142
142
  *
143
- * @param options - Optional overrides for password, sync, DWN endpoints.
143
+ * **Handler-based connect** (dapps): Delegates credential acquisition
144
+ * to a {@link ConnectHandler}. Triggered when `protocols` or
145
+ * `connectHandler` is provided.
146
+ *
147
+ * **Local connect** (wallets / CLI): Creates or unlocks a local vault.
148
+ * Triggered when `password`, `createIdentity`, or `recoveryPhrase`
149
+ * is provided.
150
+ *
151
+ * In both cases, `connect()` first attempts to restore a previous
152
+ * session. If a valid session exists, it is returned immediately
153
+ * without any user interaction.
154
+ *
155
+ * @example Dapp (browser)
156
+ * ```ts
157
+ * import { BrowserConnectHandler } from '@enbox/browser';
158
+ *
159
+ * const auth = await AuthManager.create({
160
+ * connectHandler: BrowserConnectHandler(),
161
+ * });
162
+ * const session = await auth.connect({
163
+ * protocols: [NotesProtocol],
164
+ * });
165
+ * ```
166
+ *
167
+ * @example Wallet / CLI
168
+ * ```ts
169
+ * const session = await auth.connect({
170
+ * password: userPin,
171
+ * createIdentity: true,
172
+ * });
173
+ * ```
174
+ *
175
+ * @param options - Connection options. The shape determines the flow.
144
176
  * @returns An active AuthSession.
145
177
  * @throws If a connection attempt is already in progress.
178
+ * @throws If handler-based connect is attempted without a handler.
146
179
  */
147
180
  connect(options) {
148
181
  return __awaiter(this, void 0, void 0, function* () {
149
- this._guardConcurrency();
150
- this._isConnecting = true;
151
- try {
152
- const session = yield localConnect({
153
- userAgent: this._userAgent,
154
- emitter: this._emitter,
155
- storage: this._storage,
156
- defaultPassword: this._defaultPassword,
157
- passwordProvider: this._passwordProvider,
158
- defaultSync: this._defaultSync,
159
- defaultDwnEndpoints: this._defaultDwnEndpoints,
160
- registration: this._registration,
161
- }, options);
162
- this._session = session;
163
- this._setState('connected');
164
- return session;
165
- }
166
- finally {
167
- this._isConnecting = false;
168
- }
182
+ return this._withConnect(() => __awaiter(this, void 0, void 0, function* () {
183
+ // 1. Try to restore a previous session first.
184
+ const restored = yield restoreSession(this._flowContext());
185
+ if (restored) {
186
+ return restored;
187
+ }
188
+ // 2. Route to the appropriate flow.
189
+ if (this._isLocalConnect(options)) {
190
+ return localConnect(this._flowContext(), options);
191
+ }
192
+ return this._handlerConnect(options);
193
+ }));
194
+ });
195
+ }
196
+ /**
197
+ * Create or reconnect a local identity (explicit local connect).
198
+ *
199
+ * Use this when you explicitly want the local vault flow, bypassing
200
+ * auto-detection. This is the preferred method for wallet apps.
201
+ *
202
+ * @param options - Local connect options.
203
+ * @returns An active AuthSession.
204
+ * @throws If a connection attempt is already in progress.
205
+ */
206
+ connectLocal(options) {
207
+ return __awaiter(this, void 0, void 0, function* () {
208
+ return this._withConnect(() => localConnect(this._flowContext(), options));
169
209
  });
170
210
  }
171
211
  /**
@@ -181,43 +221,7 @@ export class AuthManager {
181
221
  */
182
222
  walletConnect(options) {
183
223
  return __awaiter(this, void 0, void 0, function* () {
184
- this._guardConcurrency();
185
- this._isConnecting = true;
186
- try {
187
- // Ensure the agent is initialized and started before wallet connect.
188
- const isFirstLaunch = yield this._userAgent.firstLaunch();
189
- let password = this._defaultPassword;
190
- if (!password && this._passwordProvider) {
191
- try {
192
- password = yield this._passwordProvider.getPassword({
193
- reason: isFirstLaunch ? 'create' : 'unlock',
194
- });
195
- }
196
- catch (_a) {
197
- // Provider failed — fall through to insecure default.
198
- }
199
- }
200
- password !== null && password !== void 0 ? password : (password = 'insecure-static-phrase');
201
- if (isFirstLaunch) {
202
- yield this._userAgent.initialize({ password });
203
- }
204
- yield this._userAgent.start({ password });
205
- this._emitter.emit('vault-unlocked', {});
206
- const session = yield walletConnect({
207
- userAgent: this._userAgent,
208
- emitter: this._emitter,
209
- storage: this._storage,
210
- defaultSync: this._defaultSync,
211
- defaultDwnEndpoints: this._defaultDwnEndpoints,
212
- registration: this._registration,
213
- }, options);
214
- this._session = session;
215
- this._setState('connected');
216
- return session;
217
- }
218
- finally {
219
- this._isConnecting = false;
220
- }
224
+ return this._withConnect(() => walletConnect(this._flowContext(), options));
221
225
  });
222
226
  }
223
227
  /**
@@ -228,24 +232,7 @@ export class AuthManager {
228
232
  */
229
233
  importFromPhrase(options) {
230
234
  return __awaiter(this, void 0, void 0, function* () {
231
- this._guardConcurrency();
232
- this._isConnecting = true;
233
- try {
234
- const session = yield importFromPhrase({
235
- userAgent: this._userAgent,
236
- emitter: this._emitter,
237
- storage: this._storage,
238
- defaultSync: this._defaultSync,
239
- defaultDwnEndpoints: this._defaultDwnEndpoints,
240
- registration: this._registration,
241
- }, options);
242
- this._session = session;
243
- this._setState('connected');
244
- return session;
245
- }
246
- finally {
247
- this._isConnecting = false;
248
- }
235
+ return this._withConnect(() => importFromPhrase(this._flowContext(), options));
249
236
  });
250
237
  }
251
238
  /**
@@ -255,24 +242,7 @@ export class AuthManager {
255
242
  */
256
243
  importFromPortable(options) {
257
244
  return __awaiter(this, void 0, void 0, function* () {
258
- this._guardConcurrency();
259
- this._isConnecting = true;
260
- try {
261
- const session = yield importFromPortable({
262
- userAgent: this._userAgent,
263
- emitter: this._emitter,
264
- storage: this._storage,
265
- defaultSync: this._defaultSync,
266
- defaultDwnEndpoints: this._defaultDwnEndpoints,
267
- registration: this._registration,
268
- }, options);
269
- this._session = session;
270
- this._setState('connected');
271
- return session;
272
- }
273
- finally {
274
- this._isConnecting = false;
275
- }
245
+ return this._withConnect(() => importFromPortable(this._flowContext(), options));
276
246
  });
277
247
  }
278
248
  /**
@@ -286,14 +256,7 @@ export class AuthManager {
286
256
  this._guardConcurrency();
287
257
  this._isConnecting = true;
288
258
  try {
289
- const session = yield restoreSession({
290
- userAgent: this._userAgent,
291
- emitter: this._emitter,
292
- storage: this._storage,
293
- defaultPassword: this._defaultPassword,
294
- passwordProvider: this._passwordProvider,
295
- defaultSync: this._defaultSync,
296
- }, options);
259
+ const session = yield restoreSession(this._flowContext(), options);
297
260
  if (session) {
298
261
  this._session = session;
299
262
  this._setState('connected');
@@ -330,11 +293,11 @@ export class AuthManager {
330
293
  */
331
294
  connectHeadless(options) {
332
295
  return __awaiter(this, void 0, void 0, function* () {
333
- var _a, _b, _c;
296
+ var _a, _b;
334
297
  let password = (_a = options === null || options === void 0 ? void 0 : options.password) !== null && _a !== void 0 ? _a : this._defaultPassword;
298
+ const isFirstLaunch = yield this._userAgent.firstLaunch();
335
299
  // Try the password provider if no explicit password.
336
300
  if (!password && this._passwordProvider) {
337
- const isFirstLaunch = yield this._userAgent.firstLaunch();
338
301
  password = yield this._passwordProvider.getPassword({
339
302
  reason: isFirstLaunch ? 'create' : 'unlock',
340
303
  });
@@ -343,14 +306,13 @@ export class AuthManager {
343
306
  throw new Error('[@enbox/auth] connectHeadless() requires a password. ' +
344
307
  'Provide one via options.password, a passwordProvider, or the AuthManager default.');
345
308
  }
346
- // Unlock the vault (initialise on first launch).
347
- if (yield this._userAgent.firstLaunch()) {
348
- yield this._userAgent.initialize({ password });
349
- }
350
- else {
351
- yield this._userAgent.start({ password });
352
- }
353
- this._emitter.emit('vault-unlocked', {});
309
+ // Unlock the vault (initialise on first launch, always start).
310
+ yield ensureVaultReady({
311
+ userAgent: this._userAgent,
312
+ emitter: this._emitter,
313
+ password,
314
+ isFirstLaunch,
315
+ });
354
316
  // Find the active identity.
355
317
  const identities = yield this._userAgent.identity.list();
356
318
  if (identities.length === 0) {
@@ -361,8 +323,7 @@ export class AuthManager {
361
323
  const identity = (_b = (savedDid
362
324
  ? identities.find(id => id.did.uri === savedDid || id.metadata.connectedDid === savedDid)
363
325
  : undefined)) !== null && _b !== void 0 ? _b : identities[0];
364
- const connectedDid = (_c = identity.metadata.connectedDid) !== null && _c !== void 0 ? _c : identity.did.uri;
365
- const delegateDid = identity.metadata.connectedDid ? identity.did.uri : undefined;
326
+ const { connectedDid, delegateDid } = resolveIdentityDids(identity);
366
327
  const identityInfo = {
367
328
  didUri: connectedDid,
368
329
  name: identity.metadata.name,
@@ -399,17 +360,16 @@ export class AuthManager {
399
360
  */
400
361
  lock() {
401
362
  return __awaiter(this, arguments, void 0, function* (options = {}) {
402
- var _a, _b;
363
+ var _a;
403
364
  const { timeout = 2000 } = options;
404
365
  const did = (_a = this._session) === null || _a === void 0 ? void 0 : _a.did;
405
366
  // 1. Stop sync.
406
- if ('sync' in this._userAgent && typeof ((_b = this._userAgent.sync) === null || _b === void 0 ? void 0 : _b.stopSync) === 'function') {
407
- yield this._userAgent.sync.stopSync(timeout);
408
- }
367
+ yield this._userAgent.sync.stopSync(timeout);
409
368
  // 2. Clear the session (but keep storage markers for restore).
410
369
  this._session = undefined;
411
- // 3. Lock the vault (also emits 'vault-locked').
412
- yield this._vault.lock();
370
+ // 3. Lock the vault.
371
+ yield this._userAgent.vault.lock();
372
+ this._emitter.emit('vault-locked', {});
413
373
  // 4. Transition state.
414
374
  this._setState('locked');
415
375
  // 5. Emit session-end if there was an active session.
@@ -428,14 +388,12 @@ export class AuthManager {
428
388
  */
429
389
  disconnect() {
430
390
  return __awaiter(this, arguments, void 0, function* (options = {}) {
431
- var _a, _b;
391
+ var _a;
432
392
  const { clearStorage = false, timeout = 2000 } = options;
433
393
  const did = (_a = this._session) === null || _a === void 0 ? void 0 : _a.did;
434
394
  // Stop sync.
435
395
  if (this._session) {
436
- if ('sync' in this._userAgent && typeof ((_b = this._userAgent.sync) === null || _b === void 0 ? void 0 : _b.stopSync) === 'function') {
437
- yield this._userAgent.sync.stopSync(timeout);
438
- }
396
+ yield this._userAgent.sync.stopSync(timeout);
439
397
  }
440
398
  this._session = undefined;
441
399
  if (clearStorage) {
@@ -454,7 +412,7 @@ export class AuthManager {
454
412
  }
455
413
  }
456
414
  }
457
- catch (_c) {
415
+ catch (_b) {
458
416
  // indexedDB.databases() not available in all browsers.
459
417
  }
460
418
  }
@@ -497,47 +455,42 @@ export class AuthManager {
497
455
  */
498
456
  shutdown() {
499
457
  return __awaiter(this, arguments, void 0, function* (options = {}) {
500
- var _a, _b, _c;
458
+ var _a;
501
459
  if (this._isShutDown) {
502
460
  return;
503
461
  }
504
462
  const { timeout = 2000 } = options;
505
463
  const did = (_a = this._session) === null || _a === void 0 ? void 0 : _a.did;
506
464
  // 1. Stop sync.
507
- if ('sync' in this._userAgent &&
508
- typeof ((_b = this._userAgent.sync) === null || _b === void 0 ? void 0 : _b.stopSync) === 'function') {
509
- try {
510
- yield this._userAgent.sync.stopSync(timeout);
511
- }
512
- catch (_d) {
513
- // Best-effort — don't block shutdown on sync errors.
514
- }
465
+ try {
466
+ yield this._userAgent.sync.stopSync(timeout);
467
+ }
468
+ catch (_b) {
469
+ // Best-effort — don't block shutdown on sync errors.
515
470
  }
516
471
  // 2. Clear the active session.
517
472
  this._session = undefined;
518
- // 3. Lock the vault (emits 'vault-locked').
473
+ // 3. Lock the vault.
519
474
  try {
520
- yield this._vault.lock();
475
+ yield this._userAgent.vault.lock();
476
+ this._emitter.emit('vault-locked', {});
521
477
  }
522
- catch (_e) {
478
+ catch (_c) {
523
479
  // Vault may already be locked or uninitialised — safe to ignore.
524
480
  }
525
481
  // 4. Close the sync engine (releases LevelDB handles, timers).
526
- if ('sync' in this._userAgent &&
527
- typeof ((_c = this._userAgent.sync) === null || _c === void 0 ? void 0 : _c.close) === 'function') {
528
- try {
529
- yield this._userAgent.sync.close();
530
- }
531
- catch (_f) {
532
- // Best-effort.
533
- }
482
+ try {
483
+ yield this._userAgent.sync.close();
484
+ }
485
+ catch (_d) {
486
+ // Best-effort.
534
487
  }
535
488
  // 5. Close the storage adapter (e.g. LevelDB session store).
536
489
  if (typeof this._storage.close === 'function') {
537
490
  try {
538
491
  yield this._storage.close();
539
492
  }
540
- catch (_g) {
493
+ catch (_e) {
541
494
  // Best-effort.
542
495
  }
543
496
  }
@@ -575,7 +528,6 @@ export class AuthManager {
575
528
  */
576
529
  switchIdentity(didUri) {
577
530
  return __awaiter(this, void 0, void 0, function* () {
578
- var _a;
579
531
  // Disconnect current session cleanly (keep data).
580
532
  if (this._session) {
581
533
  yield this.disconnect();
@@ -584,8 +536,7 @@ export class AuthManager {
584
536
  if (!identity) {
585
537
  throw new Error(`[@enbox/auth] Identity not found: ${didUri}`);
586
538
  }
587
- const connectedDid = (_a = identity.metadata.connectedDid) !== null && _a !== void 0 ? _a : identity.did.uri;
588
- const delegateDid = identity.metadata.connectedDid ? identity.did.uri : undefined;
539
+ const { connectedDid, delegateDid } = resolveIdentityDids(identity);
589
540
  // Persist the switch.
590
541
  yield this._storage.set(STORAGE_KEYS.PREVIOUSLY_CONNECTED, 'true');
591
542
  yield this._storage.set(STORAGE_KEYS.ACTIVE_IDENTITY, connectedDid);
@@ -604,13 +555,10 @@ export class AuthManager {
604
555
  options: { delegateDid, protocols: [] },
605
556
  });
606
557
  }
607
- catch (_b) {
558
+ catch (_a) {
608
559
  // Already registered — safe to ignore.
609
560
  }
610
- const syncMode = sync === undefined ? 'live' : 'poll';
611
- const syncInterval = sync !== null && sync !== void 0 ? sync : (syncMode === 'live' ? '5m' : '2m');
612
- this._userAgent.sync.startSync({ mode: syncMode, interval: syncInterval })
613
- .catch((err) => console.error('[@enbox/auth] Sync failed:', err));
561
+ startSyncIfEnabled(this._userAgent, sync);
614
562
  }
615
563
  this._session = new AuthSession({
616
564
  agent: this._userAgent,
@@ -671,9 +619,9 @@ export class AuthManager {
671
619
  });
672
620
  }
673
621
  // ─── Vault ─────────────────────────────────────────────────────
674
- /** Access the vault manager for lock/unlock/backup operations. */
622
+ /** Access the underlying identity vault for lock/unlock/backup operations. */
675
623
  get vault() {
676
- return this._vault;
624
+ return this._userAgent.vault;
677
625
  }
678
626
  // ─── Events ────────────────────────────────────────────────────
679
627
  /**
@@ -697,7 +645,7 @@ export class AuthManager {
697
645
  }
698
646
  /** Whether the vault is currently locked. */
699
647
  get isLocked() {
700
- return this._vault.isLocked;
648
+ return this._userAgent.vault.isLocked();
701
649
  }
702
650
  /** Whether a connection attempt is in progress. */
703
651
  get isConnecting() {
@@ -718,6 +666,127 @@ export class AuthManager {
718
666
  return this._localDwnEndpoint;
719
667
  }
720
668
  // ─── Private helpers ───────────────────────────────────────────
669
+ /**
670
+ * Determine whether the given options indicate a local connect flow.
671
+ *
672
+ * Local connect is indicated by the presence of `password`,
673
+ * `createIdentity`, or `recoveryPhrase` — signals that the caller
674
+ * is managing its own vault/identity lifecycle. In non-browser
675
+ * environments, local connect is the fallback.
676
+ */
677
+ _isLocalConnect(options) {
678
+ const o = (options !== null && options !== void 0 ? options : {});
679
+ // If any local-connect-specific keys are present, it's definitely local.
680
+ const hasLocalSignals = (o.password !== undefined ||
681
+ o.createIdentity !== undefined ||
682
+ o.recoveryPhrase !== undefined ||
683
+ o.dwnEndpoints !== undefined ||
684
+ o.metadata !== undefined);
685
+ if (hasLocalSignals) {
686
+ return true;
687
+ }
688
+ // If any handler-connect signals are present, use the handler flow.
689
+ const hasHandlerSignals = (o.protocols !== undefined ||
690
+ o.connectHandler !== undefined);
691
+ if (hasHandlerSignals) {
692
+ return false;
693
+ }
694
+ // No explicit signals → default to local connect.
695
+ // Callers that want handler-based connect must provide protocols
696
+ // or a connectHandler.
697
+ return true;
698
+ }
699
+ /**
700
+ * Run a handler-based (delegated) connect flow.
701
+ *
702
+ * 1. Initialize the vault (agent-only, no identity).
703
+ * 2. Normalize protocol permission requests.
704
+ * 3. Delegate to the connect handler for credential acquisition.
705
+ * 4. Import the delegate DID, process grants, set up sync.
706
+ * 5. Finalize and return the AuthSession.
707
+ */
708
+ _handlerConnect(options) {
709
+ return __awaiter(this, void 0, void 0, function* () {
710
+ var _a, _b;
711
+ const ctx = this._flowContext();
712
+ const { userAgent, emitter, storage } = ctx;
713
+ const sync = (_a = options === null || options === void 0 ? void 0 : options.sync) !== null && _a !== void 0 ? _a : ctx.defaultSync;
714
+ if (sync === 'off') {
715
+ throw new Error('[@enbox/auth] Sync must be enabled for delegated connect. ' +
716
+ 'Remove sync: "off" or set an interval like "15s".');
717
+ }
718
+ // 1. Initialize vault (agent-only, no identity).
719
+ const isFirstLaunch = yield userAgent.firstLaunch();
720
+ const password = yield resolvePassword(ctx, undefined, isFirstLaunch);
721
+ yield ensureVaultReady({ userAgent, emitter, password, isFirstLaunch });
722
+ // 2. Normalize protocol requests.
723
+ const permissionRequests = normalizeProtocolRequests(options === null || options === void 0 ? void 0 : options.protocols);
724
+ // 3. Resolve the handler.
725
+ const handler = (_b = options === null || options === void 0 ? void 0 : options.connectHandler) !== null && _b !== void 0 ? _b : this._connectHandler;
726
+ if (!handler) {
727
+ throw new Error('[@enbox/auth] No connect handler provided. ' +
728
+ 'Install @enbox/browser and pass BrowserConnectHandler(), ' +
729
+ 'or provide a custom ConnectHandler.');
730
+ }
731
+ // 4. Delegate to the handler.
732
+ const result = yield handler.requestAccess({ permissionRequests });
733
+ if (!result) {
734
+ throw new Error('[@enbox/auth] Connect was denied or cancelled by the user.');
735
+ }
736
+ // 5. Import delegate DID, process grants, set up sync.
737
+ const { delegatePortableDid, connectedDid, delegateGrants } = result;
738
+ const identity = yield importDelegateAndSetupSync({
739
+ userAgent, delegatePortableDid, connectedDid, delegateGrants,
740
+ flowName: 'Connect',
741
+ });
742
+ // 6. Finalize session.
743
+ return finalizeDelegateSession({
744
+ userAgent, emitter, storage, identity,
745
+ connectedDid, delegateDid: delegatePortableDid.uri, sync,
746
+ });
747
+ });
748
+ }
749
+ /**
750
+ * Build a `FlowContext` from the manager's current state.
751
+ *
752
+ * Replaces the 5 manual inline context constructions that were
753
+ * previously duplicated across `connect()`, `walletConnect()`,
754
+ * `importFromPhrase()`, `importFromPortable()`, and `restoreSession()`.
755
+ */
756
+ _flowContext() {
757
+ return {
758
+ userAgent: this._userAgent,
759
+ emitter: this._emitter,
760
+ storage: this._storage,
761
+ defaultPassword: this._defaultPassword,
762
+ passwordProvider: this._passwordProvider,
763
+ defaultSync: this._defaultSync,
764
+ defaultDwnEndpoints: this._defaultDwnEndpoints,
765
+ registration: this._registration,
766
+ };
767
+ }
768
+ /**
769
+ * Template for connection flows that follow the guard → try/finally → setState pattern.
770
+ *
771
+ * Consolidates the duplicated concurrency guard, `_isConnecting` flag management,
772
+ * session assignment, and state transition across `connect()`, `walletConnect()`,
773
+ * `importFromPhrase()`, and `importFromPortable()`.
774
+ */
775
+ _withConnect(fn) {
776
+ return __awaiter(this, void 0, void 0, function* () {
777
+ this._guardConcurrency();
778
+ this._isConnecting = true;
779
+ try {
780
+ const session = yield fn();
781
+ this._session = session;
782
+ this._setState('connected');
783
+ return session;
784
+ }
785
+ finally {
786
+ this._isConnecting = false;
787
+ }
788
+ });
789
+ }
721
790
  _setState(state) {
722
791
  if (state === this._state) {
723
792
  return;