@enbox/auth 0.6.39 → 0.6.40

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 (38) hide show
  1. package/dist/esm/auth-manager.js +30 -33
  2. package/dist/esm/auth-manager.js.map +1 -1
  3. package/dist/esm/connect/import.js +1 -100
  4. package/dist/esm/connect/import.js.map +1 -1
  5. package/dist/esm/connect/lifecycle.js +21 -3
  6. package/dist/esm/connect/lifecycle.js.map +1 -1
  7. package/dist/esm/connect/vault.js +17 -18
  8. package/dist/esm/connect/vault.js.map +1 -1
  9. package/dist/esm/errors.js +11 -0
  10. package/dist/esm/errors.js.map +1 -0
  11. package/dist/esm/identity-session.js +1 -1
  12. package/dist/esm/index.js +2 -1
  13. package/dist/esm/index.js.map +1 -1
  14. package/dist/esm/types.js.map +1 -1
  15. package/dist/types/auth-manager.d.ts +20 -27
  16. package/dist/types/auth-manager.d.ts.map +1 -1
  17. package/dist/types/connect/import.d.ts +1 -11
  18. package/dist/types/connect/import.d.ts.map +1 -1
  19. package/dist/types/connect/lifecycle.d.ts +5 -2
  20. package/dist/types/connect/lifecycle.d.ts.map +1 -1
  21. package/dist/types/connect/vault.d.ts +2 -2
  22. package/dist/types/connect/vault.d.ts.map +1 -1
  23. package/dist/types/errors.d.ts +6 -0
  24. package/dist/types/errors.d.ts.map +1 -0
  25. package/dist/types/identity-session.d.ts +1 -1
  26. package/dist/types/index.d.ts +3 -2
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/types.d.ts +20 -19
  29. package/dist/types/types.d.ts.map +1 -1
  30. package/package.json +2 -2
  31. package/src/auth-manager.ts +33 -33
  32. package/src/connect/import.ts +2 -114
  33. package/src/connect/lifecycle.ts +19 -3
  34. package/src/connect/vault.ts +15 -18
  35. package/src/errors.ts +12 -0
  36. package/src/identity-session.ts +1 -1
  37. package/src/index.ts +3 -3
  38. package/src/types.ts +21 -23
@@ -29,9 +29,9 @@ import type {
29
29
  DisconnectOptions,
30
30
  HandlerConnectOptions,
31
31
  HeadlessConnectOptions,
32
- ImportFromPhraseOptions,
33
32
  ImportFromPortableOptions,
34
33
  RegistrationOptions,
34
+ RestoreFromPhraseOptions,
35
35
  RestoreSessionOptions,
36
36
  ShutdownOptions,
37
37
  StorageAdapter,
@@ -48,13 +48,13 @@ import { AuthEventEmitter } from './events.js';
48
48
  import { AuthSession } from './identity-session.js';
49
49
  import { createDefaultStorage } from './storage/storage.js';
50
50
  import { discoverLocalDwn } from './discovery.js';
51
+ import { importFromPortable } from './connect/import.js';
51
52
  import { normalizeProtocolRequests } from './permissions.js';
52
53
  import { restoreSession } from './connect/restore.js';
53
54
  import { STORAGE_KEYS } from './types.js';
54
55
  import { vaultConnect } from './connect/vault.js';
55
56
  import { walletConnect } from './connect/wallet.js';
56
57
  import { deriveActiveSyncScope, ensureVaultReady, finalizeDelegateSession, importDelegateAndSetupSync, resolveIdentityDids, resolvePassword, startSyncIfEnabled, toSyncIdentityProtocols } from './connect/lifecycle.js';
57
- import { importFromPhrase, importFromPortable } from './connect/import.js';
58
58
 
59
59
  /**
60
60
  * The primary entry point for authentication and identity management.
@@ -71,7 +71,7 @@ import { importFromPhrase, importFromPortable } from './connect/import.js';
71
71
  *
72
72
  * // First time: creates a new identity
73
73
  * // Subsequent times: restores the previous session
74
- * const session = await auth.restoreSession() ?? await auth.connect();
74
+ * const session = await auth.restoreSession() ?? await auth.connectVault({ createIdentity: true });
75
75
  *
76
76
  * // session.agent — the authenticated Enbox agent
77
77
  * // session.did — the connected DID URI
@@ -206,17 +206,20 @@ export class AuthManager {
206
206
  * This is the primary entry point for dapps. It routes to the
207
207
  * appropriate flow based on the options:
208
208
  *
209
+ * **Recovery phrase restore** (wallets / CLI): Explicitly restores or
210
+ * re-unlocks a vault. Triggered first when `recoveryPhrase` is provided.
211
+ *
209
212
  * **Handler-based connect** (dapps): Delegates credential acquisition
210
213
  * to a {@link ConnectHandler}. Triggered when `protocols` or
211
- * `connectHandler` is provided.
214
+ * `connectHandler` is provided and no `recoveryPhrase` is present.
212
215
  *
213
216
  * **Local connect** (wallets / CLI): Creates or unlocks a local vault.
214
217
  * Triggered when `password`, `createIdentity`, or `recoveryPhrase`
215
218
  * is provided.
216
219
  *
217
- * In both cases, `connect()` first attempts to restore a previous
218
- * session. If a valid session exists, it is returned immediately
219
- * without any user interaction.
220
+ * `connect()` first attempts to restore a previous session unless a
221
+ * recovery phrase is provided. Recovery is an explicit user action and
222
+ * bypasses stored-session restore.
220
223
  *
221
224
  * @example Dapp (browser)
222
225
  * ```ts
@@ -245,6 +248,11 @@ export class AuthManager {
245
248
  */
246
249
  async connect(options?: ConnectOptions): Promise<AuthSession> {
247
250
  return this._withConnect(async () => {
251
+ // Recovery is an explicit user action. Do not let a stale stored session intercept it.
252
+ if (this._isPhraseRestore(options)) {
253
+ return vaultConnect(this._flowContext(), options);
254
+ }
255
+
248
256
  // 1. Try to restore a previous session first.
249
257
  const restored = await restoreSession(this._flowContext());
250
258
  if (restored) { return restored; }
@@ -261,32 +269,28 @@ export class AuthManager {
261
269
  }
262
270
 
263
271
  /**
264
- * Create or reconnect a local identity (explicit vault connect).
272
+ * Create or reconnect an identity via the local HD vault.
265
273
  *
266
274
  * Use this when you explicitly want the vault flow, bypassing
267
- * auto-detection. This is the preferred method for wallet apps.
275
+ * auto-detection. This is the preferred method for wallet apps
276
+ * and CLI tools that own the identity vault directly.
268
277
  *
269
278
  * @param options - Vault connect options.
270
279
  * @returns An active AuthSession.
271
280
  * @throws If a connection attempt is already in progress.
272
- * @deprecated Use {@link connectVault} instead. Will be removed in 1.0.
273
281
  */
274
- async connectLocal(options?: VaultConnectOptions): Promise<AuthSession> {
275
- return this.connectVault(options);
282
+ async connectVault(options?: VaultConnectOptions): Promise<AuthSession> {
283
+ return this._withConnect(() => vaultConnect(this._flowContext(), options));
276
284
  }
277
285
 
278
286
  /**
279
- * Create or reconnect an identity via the local HD vault.
287
+ * Restore or re-unlock the local vault from a BIP-39 recovery phrase.
280
288
  *
281
- * Use this when you explicitly want the vault flow, bypassing
282
- * auto-detection. This is the preferred method for wallet apps
283
- * and CLI tools that own the identity vault directly.
284
- *
285
- * @param options - Vault connect options.
286
- * @returns An active AuthSession.
287
- * @throws If a connection attempt is already in progress.
289
+ * - Fresh device: initializes the vault from the phrase and recovers remote identities.
290
+ * - Same local vault: verifies the phrase matches, resets the local password, and preserves data.
291
+ * - Different local vault: throws without clearing or replacing the existing vault.
288
292
  */
289
- async connectVault(options?: VaultConnectOptions): Promise<AuthSession> {
293
+ async restoreFromPhrase(options: RestoreFromPhraseOptions): Promise<AuthSession> {
290
294
  return this._withConnect(() => vaultConnect(this._flowContext(), options));
291
295
  }
292
296
 
@@ -305,16 +309,6 @@ export class AuthManager {
305
309
  return this._withConnect(() => walletConnect(this._flowContext(), options));
306
310
  }
307
311
 
308
- /**
309
- * Import an identity from a BIP-39 recovery phrase.
310
- *
311
- * This re-derives the vault and agent DID from the mnemonic,
312
- * recovering the identity on this device.
313
- */
314
- async importFromPhrase(options: ImportFromPhraseOptions): Promise<AuthSession> {
315
- return this._withConnect(() => importFromPhrase(this._flowContext(), options));
316
- }
317
-
318
312
  /**
319
313
  * Import an identity from a PortableIdentity JSON object.
320
314
  *
@@ -1014,6 +1008,12 @@ export class AuthManager {
1014
1008
  return true;
1015
1009
  }
1016
1010
 
1011
+ private _isPhraseRestore(options?: ConnectOptions): options is RestoreFromPhraseOptions {
1012
+ return options !== undefined
1013
+ && options !== null
1014
+ && typeof (options as { recoveryPhrase?: unknown }).recoveryPhrase === 'string';
1015
+ }
1016
+
1017
1017
  /**
1018
1018
  * Run a handler-based (delegated) connect flow.
1019
1019
  *
@@ -1093,7 +1093,7 @@ export class AuthManager {
1093
1093
  *
1094
1094
  * Replaces the 5 manual inline context constructions that were
1095
1095
  * previously duplicated across `connect()`, `walletConnect()`,
1096
- * `importFromPhrase()`, `importFromPortable()`, and `restoreSession()`.
1096
+ * `restoreFromPhrase()`, `importFromPortable()`, and `restoreSession()`.
1097
1097
  */
1098
1098
  private _flowContext(): FlowContext {
1099
1099
  return {
@@ -1113,7 +1113,7 @@ export class AuthManager {
1113
1113
  *
1114
1114
  * Consolidates the duplicated concurrency guard, `_isConnecting` flag management,
1115
1115
  * session assignment, and state transition across `connect()`, `walletConnect()`,
1116
- * `importFromPhrase()`, and `importFromPortable()`.
1116
+ * `restoreFromPhrase()`, and `importFromPortable()`.
1117
1117
  *
1118
1118
  * Also short-circuits if the manager has already been shut down — using
1119
1119
  * a closed manager would otherwise fail deep inside sync/storage with an
@@ -1,129 +1,17 @@
1
1
  /**
2
2
  * Identity import flows.
3
3
  *
4
- * - Import from BIP-39 recovery phrase (re-derive vault + identity).
5
4
  * - Import from PortableIdentity JSON.
6
5
  * @module
7
6
  */
8
7
 
9
8
  import type { AuthSession } from '../identity-session.js';
10
9
  import type { FlowContext } from './lifecycle.js';
11
- import type { ImportFromPhraseOptions, ImportFromPortableOptions } from '../types.js';
10
+ import type { ImportFromPortableOptions } from '../types.js';
12
11
 
13
12
  import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
14
13
  import { registerWithDwnEndpoints } from '../registration.js';
15
- import { createDefaultIdentity, ensureVaultReady, finalizeSession, registerSyncScopeForIdentity, resolveIdentityDids, startSyncIfEnabled } from './lifecycle.js';
16
- import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
17
-
18
- /**
19
- * Import (or recover) an identity from a BIP-39 recovery phrase.
20
- *
21
- * This re-initializes the vault with the given phrase and password,
22
- * recovering the agent DID and all derived keys. If the recovery phrase
23
- * was previously used to create identities, they are pulled from the
24
- * remote DWN. Otherwise a new default identity is created.
25
- */
26
- export async function importFromPhrase(
27
- ctx: FlowContext,
28
- options: ImportFromPhraseOptions,
29
- ): Promise<AuthSession> {
30
- const { userAgent, emitter, storage } = ctx;
31
- const { recoveryPhrase, password } = options;
32
- const sync = options.sync ?? ctx.defaultSync;
33
- const dwnEndpoints = options.dwnEndpoints ?? ctx.defaultDwnEndpoints ?? DEFAULT_DWN_ENDPOINTS;
34
-
35
- // Initialize the vault with the recovery phrase and start the agent.
36
- const isFirstLaunch = await userAgent.firstLaunch();
37
- await ensureVaultReady({
38
- userAgent,
39
- emitter,
40
- password,
41
- isFirstLaunch,
42
- recoveryPhrase,
43
- dwnEndpoints,
44
- });
45
-
46
- // Register agent DID as tenant and for sync — prerequisites for recovery.
47
- if (ctx.registration) {
48
- await registerWithDwnEndpoints(
49
- {
50
- userAgent,
51
- dwnEndpoints,
52
- agentDid : userAgent.agentDid.uri,
53
- connectedDid : userAgent.agentDid.uri,
54
- secretStore : userAgent.secrets,
55
- storage,
56
- },
57
- ctx.registration,
58
- );
59
- }
60
- if (sync !== 'off') {
61
- await registerAgentDidForSync(userAgent);
62
- }
63
-
64
- // Try to recover identities from the remote DWN before falling back
65
- // to creating a new one.
66
- let identities = await userAgent.identity.list();
67
- let identity = identities[0];
68
- let isNewIdentity = false;
69
-
70
- if (!identity && sync !== 'off') {
71
- try {
72
- identities = await recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
73
- identity = identities[0];
74
- } catch (err) {
75
- console.warn('[@enbox/auth] Seed phrase recovery failed:', err);
76
- }
77
- }
78
-
79
- if (!identity) {
80
- isNewIdentity = true;
81
- identity = await createDefaultIdentity(userAgent, dwnEndpoints);
82
- }
83
-
84
- const { connectedDid, delegateDid } = resolveIdentityDids(identity);
85
-
86
- // Register sync for the identity DID.
87
- if (isNewIdentity) {
88
- // New identity: register as tenant first, then for sync.
89
- if (ctx.registration) {
90
- await registerWithDwnEndpoints(
91
- {
92
- userAgent,
93
- dwnEndpoints,
94
- agentDid : userAgent.agentDid.uri,
95
- connectedDid,
96
- secretStore : userAgent.secrets,
97
- storage,
98
- },
99
- ctx.registration,
100
- );
101
- }
102
- if (delegateDid) {
103
- await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
104
- } else if (sync !== 'off') {
105
- await registerSyncScopeForIdentity({ userAgent, connectedDid });
106
- }
107
- } else if (delegateDid) {
108
- // Pre-existing delegate identity: repair sync scope so revoked
109
- // grants don't remain in a stale registration.
110
- await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
111
- }
112
-
113
- // Start sync.
114
- await startSyncIfEnabled(userAgent, sync);
115
-
116
- // Persist session info, build AuthSession, and emit lifecycle events.
117
- return finalizeSession({
118
- userAgent,
119
- emitter,
120
- storage,
121
- connectedDid,
122
- delegateDid,
123
- identityName : identity.metadata.name,
124
- identityConnectedDid : identity.metadata.connectedDid,
125
- });
126
- }
14
+ import { finalizeSession, registerSyncScopeForIdentity, resolveIdentityDids, startSyncIfEnabled } from './lifecycle.js';
127
15
 
128
16
  /**
129
17
  * Import an identity from a PortableIdentity JSON object.
@@ -25,9 +25,10 @@ import { Convert } from '@enbox/common';
25
25
  import type { GenericMessage } from '@enbox/dwn-sdk-js';
26
26
 
27
27
  import { DataStream, PermissionsProtocol } from '@enbox/dwn-sdk-js';
28
- import { DwnInterface, DwnPermissionGrant, KeyDeliveryProtocolDefinition } from '@enbox/agent';
28
+ import { DwnInterface, DwnPermissionGrant, HdIdentityVaultRecoveryPhraseMismatchError, KeyDeliveryProtocolDefinition } from '@enbox/agent';
29
29
 
30
30
  import { AuthSession } from '../identity-session.js';
31
+ import { RecoveryPhraseMismatchError } from '../errors.js';
31
32
  import { DEFAULT_DWN_ENDPOINTS, INSECURE_DEFAULT_PASSWORD, STORAGE_KEYS } from '../types.js';
32
33
 
33
34
  // ─── FlowContext ─────────────────────────────────────────────────
@@ -109,7 +110,7 @@ export async function resolvePassword(
109
110
  // ─── ensureVaultReady ────────────────────────────────────────────
110
111
 
111
112
  /**
112
- * Initialize (on first launch) and start the agent, then emit `vault-unlocked`.
113
+ * Initialize or recover the vault, start the agent, then emit `vault-unlocked`.
113
114
  *
114
115
  * This consolidates the 5 copies of:
115
116
  * ```ts
@@ -118,6 +119,9 @@ export async function resolvePassword(
118
119
  * emitter.emit('vault-unlocked', {});
119
120
  * ```
120
121
  *
122
+ * When `recoveryPhrase` is supplied for an already-initialized vault, the phrase is verified
123
+ * against the stored agent DID and the vault password is reset without replacing local data.
124
+ *
121
125
  * @returns The recovery phrase if the vault was just initialized, otherwise `undefined`.
122
126
  *
123
127
  * @internal
@@ -139,6 +143,18 @@ export async function ensureVaultReady(params: {
139
143
  recoveryPhrase : params.recoveryPhrase,
140
144
  dwnEndpoints : params.dwnEndpoints,
141
145
  });
146
+ } else if (params.recoveryPhrase) {
147
+ try {
148
+ await userAgent.vault.resetPasswordWithRecoveryPhrase({
149
+ recoveryPhrase: params.recoveryPhrase,
150
+ password,
151
+ });
152
+ } catch (error) {
153
+ if (error instanceof HdIdentityVaultRecoveryPhraseMismatchError) {
154
+ throw new RecoveryPhraseMismatchError();
155
+ }
156
+ throw error;
157
+ }
142
158
  }
143
159
 
144
160
  await userAgent.start({ password });
@@ -184,7 +200,7 @@ export async function startSyncIfEnabled(
184
200
  * encryption keys, and a DWN service endpoint.
185
201
  *
186
202
  * This consolidates the identical identity creation block that was
187
- * duplicated in `vaultConnect` and `importFromPhrase`.
203
+ * duplicated across vault recovery and identity import flows.
188
204
  *
189
205
  * @internal
190
206
  */
@@ -16,7 +16,7 @@ import type { VaultConnectOptions } from '../types.js';
16
16
  import { applyLocalDwnDiscovery } from '../discovery.js';
17
17
  import { DEFAULT_DWN_ENDPOINTS } from '../types.js';
18
18
  import { registerWithDwnEndpoints } from '../registration.js';
19
- import { createDefaultIdentity, ensureVaultReady, finalizeSession, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
19
+ import { createDefaultIdentity, ensureVaultReady, finalizeSession, registerSyncScopeForIdentity, resolveIdentityDids, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
20
20
  import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery.js';
21
21
 
22
22
  /**
@@ -26,8 +26,8 @@ import { recoverIdentitiesFromRemote, registerAgentDidForSync } from './recovery
26
26
  * `options.createIdentity: true`.
27
27
  * - On subsequent launches: unlocks the vault and reconnects to the existing identity.
28
28
  * - On recovery: when `recoveryPhrase` is provided on a fresh vault, pulls
29
- * identities and their data from the remote DWN before falling back to
30
- * identity creation.
29
+ * identities and their data from the remote DWN before optionally creating
30
+ * a default identity.
31
31
  *
32
32
  * When no identities exist and `createIdentity` is not `true`, the session
33
33
  * is returned with the **agent DID** as the connected DID. This allows apps to
@@ -88,9 +88,9 @@ export async function vaultConnect(
88
88
  let identity = identities[0];
89
89
  let isNewIdentity = false;
90
90
 
91
- // Seed phrase recovery: when a recovery phrase was provided on a fresh
92
- // vault and no identities exist locally, pull them from the remote DWN.
93
- if (!identity && isFirstLaunch && options.recoveryPhrase && sync !== 'off') {
91
+ // Seed phrase recovery: when a recovery phrase was provided and no identities exist locally,
92
+ // pull them from the remote DWN before deciding whether to create a new identity.
93
+ if (!identity && options.recoveryPhrase && sync !== 'off') {
94
94
  try {
95
95
  identities = await recoverIdentitiesFromRemote({ userAgent, dwnEndpoints, registration: ctx.registration, storage });
96
96
  identity = identities[0];
@@ -99,7 +99,7 @@ export async function vaultConnect(
99
99
  }
100
100
  }
101
101
 
102
- // Create a default identity if none were found or recovered.
102
+ // Create a default identity if none were found or recovered and the caller asked for one.
103
103
  if (!identity && shouldCreateIdentity) {
104
104
  isNewIdentity = true;
105
105
  identity = await createDefaultIdentity(userAgent, dwnEndpoints, options.metadata?.name ?? 'Default');
@@ -108,13 +108,9 @@ export async function vaultConnect(
108
108
  // When no identity exists (createIdentity: false on first launch), use the
109
109
  // agent DID as the session's connected DID. The session is still valid but
110
110
  // operates in the agent's context rather than a user identity's context.
111
- const connectedDid = identity
112
- ? resolveIdentityDids(identity).connectedDid
113
- : userAgent.agentDid.uri;
114
-
115
- const delegateDid = identity
116
- ? resolveIdentityDids(identity).delegateDid
117
- : undefined;
111
+ const identityDids = identity ? resolveIdentityDids(identity) : undefined;
112
+ const connectedDid = identityDids?.connectedDid ?? userAgent.agentDid.uri;
113
+ const delegateDid = identityDids?.delegateDid;
118
114
 
119
115
  // Register the new identity DID as a tenant and for sync.
120
116
  // Tenant registration must come before sync registration — with live
@@ -134,10 +130,11 @@ export async function vaultConnect(
134
130
  );
135
131
  }
136
132
  if (isNewIdentity && sync !== 'off') {
137
- await userAgent.sync.registerIdentity({
138
- did : connectedDid,
139
- options : { delegateDid, protocols: 'all' },
140
- });
133
+ await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
134
+ } else if (!isNewIdentity && delegateDid) {
135
+ // Persisted delegate identities need their sync scope refreshed from
136
+ // current grants so revoked protocols do not keep syncing after restore.
137
+ await registerSyncScopeForIdentity({ userAgent, connectedDid, delegateDid });
141
138
  }
142
139
 
143
140
  // Start sync.
package/src/errors.ts ADDED
@@ -0,0 +1,12 @@
1
+ export class RecoveryPhraseMismatchError extends Error {
2
+ public readonly code = 'RECOVERY_PHRASE_MISMATCH';
3
+
4
+ constructor(message = 'Recovery phrase does not match the initialized vault.') {
5
+ super(message);
6
+ this.name = 'RecoveryPhraseMismatchError';
7
+ }
8
+ }
9
+
10
+ export function isRecoveryPhraseMismatchError(error: unknown): error is RecoveryPhraseMismatchError {
11
+ return error instanceof RecoveryPhraseMismatchError;
12
+ }
@@ -11,7 +11,7 @@
11
11
  * ```ts
12
12
  * import { Enbox } from '@enbox/api';
13
13
  *
14
- * const session = await auth.connect();
14
+ * const session = await auth.connectVault({ createIdentity: true });
15
15
  * const enbox = Enbox.fromSession(session);
16
16
  * ```
17
17
  *
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  * import { AuthManager } from '@enbox/auth';
11
11
  *
12
12
  * const auth = await AuthManager.create({ sync: '15s' });
13
- * const session = await auth.connectVault({ password: userPin });
13
+ * const session = await auth.connectVault({ password: userPin, createIdentity: true });
14
14
  * ```
15
15
  *
16
16
  * @example Dapp with browser connect handler
@@ -31,6 +31,7 @@
31
31
  export { AuthManager } from './auth-manager.js';
32
32
  export { AuthSession } from './identity-session.js';
33
33
  export { AuthEventEmitter } from './events.js';
34
+ export { RecoveryPhraseMismatchError, isRecoveryPhraseMismatchError } from './errors.js';
34
35
 
35
36
  // Password providers
36
37
  export { PasswordProvider } from './password-provider.js';
@@ -86,9 +87,7 @@ export type {
86
87
  HeadlessConnectOptions,
87
88
  IdentityInfo,
88
89
  IdentityVaultBackup,
89
- ImportFromPhraseOptions,
90
90
  ImportFromPortableOptions,
91
- LocalConnectOptions,
92
91
  LocalDwnStrategy,
93
92
  VaultConnectOptions,
94
93
  Permission,
@@ -98,6 +97,7 @@ export type {
98
97
  ProviderAuthResult,
99
98
  RegistrationOptions,
100
99
  RegistrationTokenData,
100
+ RestoreFromPhraseOptions,
101
101
  RestoreSessionOptions,
102
102
  ShutdownOptions,
103
103
  StorageAdapter,
package/src/types.ts CHANGED
@@ -403,7 +403,7 @@ export interface VaultConnectOptions {
403
403
  /** Vault password (overrides manager default). */
404
404
  password?: string;
405
405
 
406
- /** Re-derive identity from an existing BIP-39 recovery phrase. */
406
+ /** Initialize or recover the vault from an existing BIP-39 recovery phrase. */
407
407
  recoveryPhrase?: string;
408
408
 
409
409
  /** Override manager default sync interval. */
@@ -434,8 +434,18 @@ export interface VaultConnectOptions {
434
434
  createIdentity?: boolean;
435
435
  }
436
436
 
437
- /** @deprecated Use {@link VaultConnectOptions} instead. */
438
- export type LocalConnectOptions = VaultConnectOptions;
437
+ /** Options for {@link AuthManager.restoreFromPhrase}. */
438
+ export interface RestoreFromPhraseOptions extends Omit<VaultConnectOptions, 'password' | 'recoveryPhrase'> {
439
+ /** The BIP-39 recovery phrase for the existing or remote wallet vault. */
440
+ recoveryPhrase: string;
441
+
442
+ /**
443
+ * Password to protect the restored vault locally.
444
+ *
445
+ * If the local vault already belongs to this phrase, this becomes the new local unlock password.
446
+ */
447
+ password: string;
448
+ }
439
449
 
440
450
  // ─── DWeb Connect ────────────────────────────────────────────────
441
451
 
@@ -508,16 +518,19 @@ export interface HandlerConnectOptions {
508
518
  *
509
519
  * `connect()` routes to the appropriate flow based on the options:
510
520
  *
521
+ * - **Recovery phrase restore** (wallets / CLI): triggered first when
522
+ * `recoveryPhrase` is provided.
523
+ *
511
524
  * - **Handler-based connect** (dapps): triggered when `protocols` or
512
- * `connectHandler` is provided. Delegates to the connect handler
513
- * for credential acquisition.
525
+ * `connectHandler` is provided and no `recoveryPhrase` is present.
526
+ * Delegates to the connect handler for credential acquisition.
514
527
  *
515
528
  * - **Vault connect** (wallets / CLI): triggered when `password`,
516
529
  * `createIdentity`, or `recoveryPhrase` is provided.
517
530
  *
518
- * In both cases, `connect()` first attempts to restore a previous session
519
- * from storage. If a valid session exists, it is returned immediately
520
- * without any user interaction.
531
+ * `connect()` first attempts to restore a previous session from storage
532
+ * unless `recoveryPhrase` is provided. Recovery is treated as an explicit
533
+ * user action and routes directly to the phrase restore flow.
521
534
  */
522
535
  export type ConnectOptions = HandlerConnectOptions | VaultConnectOptions;
523
536
 
@@ -552,21 +565,6 @@ export interface WalletConnectOptions {
552
565
  sync?: SyncOption;
553
566
  }
554
567
 
555
- /** Options for {@link AuthManager.importFromPhrase}. */
556
- export interface ImportFromPhraseOptions {
557
- /** The BIP-39 recovery phrase. */
558
- recoveryPhrase: string;
559
-
560
- /** Password to protect the vault. */
561
- password: string;
562
-
563
- /** Override manager default sync interval. */
564
- sync?: SyncOption;
565
-
566
- /** Override manager default DWN endpoints. */
567
- dwnEndpoints?: string[];
568
- }
569
-
570
568
  /** Options for {@link AuthManager.importFromPortable}. */
571
569
  export interface ImportFromPortableOptions {
572
570
  /** The portable identity JSON to import. */