@enbox/auth 0.4.0 → 0.6.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 (86) hide show
  1. package/dist/esm/auth-manager.js +244 -121
  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 +235 -0
  6. package/dist/esm/connect/lifecycle.js.map +1 -0
  7. package/dist/esm/connect/local.js +91 -0
  8. package/dist/esm/connect/local.js.map +1 -0
  9. package/dist/esm/{flows/session-restore.js → connect/restore.js} +39 -50
  10. package/dist/esm/connect/restore.js.map +1 -0
  11. package/dist/esm/{flows/wallet-connect.js → connect/wallet.js} +33 -39
  12. package/dist/esm/connect/wallet.js.map +1 -0
  13. package/dist/esm/{flows/dwn-discovery.js → discovery.js} +98 -83
  14. package/dist/esm/discovery.js.map +1 -0
  15. package/dist/esm/index.js +7 -3
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/password-provider.js +319 -0
  18. package/dist/esm/password-provider.js.map +1 -0
  19. package/dist/esm/{flows/dwn-registration.js → registration.js} +50 -4
  20. package/dist/esm/registration.js.map +1 -0
  21. package/dist/esm/types.js +11 -1
  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 +86 -7
  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 +152 -0
  30. package/dist/types/connect/lifecycle.d.ts.map +1 -0
  31. package/dist/types/connect/local.d.ts +18 -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/{flows/wallet-connect.d.ts → connect/wallet.d.ts} +7 -16
  36. package/dist/types/connect/wallet.d.ts.map +1 -0
  37. package/dist/types/{flows/dwn-discovery.d.ts → discovery.d.ts} +43 -56
  38. package/dist/types/discovery.d.ts.map +1 -0
  39. package/dist/types/index.d.ts +8 -4
  40. package/dist/types/index.d.ts.map +1 -1
  41. package/dist/types/password-provider.d.ts +194 -0
  42. package/dist/types/password-provider.d.ts.map +1 -0
  43. package/dist/types/{flows/dwn-registration.d.ts → registration.d.ts} +21 -2
  44. package/dist/types/registration.d.ts.map +1 -0
  45. package/dist/types/types.d.ts +92 -4
  46. package/dist/types/types.d.ts.map +1 -1
  47. package/dist/types/wallet-connect-client.d.ts +89 -0
  48. package/dist/types/wallet-connect-client.d.ts.map +1 -0
  49. package/package.json +15 -12
  50. package/src/auth-manager.ts +279 -145
  51. package/src/connect/import.ts +148 -0
  52. package/src/connect/lifecycle.ts +321 -0
  53. package/src/connect/local.ts +101 -0
  54. package/src/connect/restore.ts +117 -0
  55. package/src/{flows/wallet-connect.ts → connect/wallet.ts} +42 -58
  56. package/src/{flows/dwn-discovery.ts → discovery.ts} +103 -82
  57. package/src/index.ts +14 -4
  58. package/src/password-provider.ts +383 -0
  59. package/src/{flows/dwn-registration.ts → registration.ts} +61 -6
  60. package/src/types.ts +100 -4
  61. package/src/wallet-connect-client.ts +278 -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 -175
  65. package/dist/esm/flows/import-identity.js.map +0 -1
  66. package/dist/esm/flows/local-connect.js +0 -141
  67. package/dist/esm/flows/local-connect.js.map +0 -1
  68. package/dist/esm/flows/session-restore.js.map +0 -1
  69. package/dist/esm/flows/wallet-connect.js.map +0 -1
  70. package/dist/esm/vault/vault-manager.js +0 -95
  71. package/dist/esm/vault/vault-manager.js.map +0 -1
  72. package/dist/types/flows/dwn-discovery.d.ts.map +0 -1
  73. package/dist/types/flows/dwn-registration.d.ts.map +0 -1
  74. package/dist/types/flows/import-identity.d.ts +0 -35
  75. package/dist/types/flows/import-identity.d.ts.map +0 -1
  76. package/dist/types/flows/local-connect.d.ts +0 -29
  77. package/dist/types/flows/local-connect.d.ts.map +0 -1
  78. package/dist/types/flows/session-restore.d.ts +0 -27
  79. package/dist/types/flows/session-restore.d.ts.map +0 -1
  80. package/dist/types/flows/wallet-connect.d.ts.map +0 -1
  81. package/dist/types/vault/vault-manager.d.ts +0 -57
  82. package/dist/types/vault/vault-manager.d.ts.map +0 -1
  83. package/src/flows/import-identity.ts +0 -217
  84. package/src/flows/local-connect.ts +0 -171
  85. package/src/flows/session-restore.ts +0 -142
  86. package/src/vault/vault-manager.ts +0 -89
@@ -1,32 +1,24 @@
1
1
  /**
2
- * Wallet connect (OIDC/QR) flow.
2
+ * Wallet connect (Enbox Connect relay) flow.
3
3
  *
4
- * Connects to an external wallet via the WalletConnect relay protocol,
4
+ * Connects to an external wallet via the Enbox Connect relay protocol,
5
5
  * importing a delegated DID with permission grants.
6
6
  * This replaces the "Mode B/C" paths in Enbox.connect().
7
7
  * @module
8
8
  */
9
9
 
10
- import { Convert } from '@enbox/common';
11
- import { WalletConnect } from '@enbox/agent';
12
10
  import type { DwnDataEncodedRecordsWriteMessage, DwnMessagesPermissionScope, DwnRecordsPermissionScope, EnboxUserAgent } from '@enbox/agent';
13
- import { DwnInterface, DwnPermissionGrant } from '@enbox/agent';
14
11
 
15
- import type { AuthEventEmitter } from '../events.js';
16
- import { AuthSession } from '../identity-session.js';
17
- import { registerWithDwnEndpoints } from './dwn-registration.js';
18
- import { STORAGE_KEYS } from '../types.js';
19
- import type { RegistrationOptions, StorageAdapter, SyncOption, WalletConnectOptions } from '../types.js';
20
-
21
- /** @internal */
22
- export interface WalletConnectContext {
23
- userAgent: EnboxUserAgent;
24
- emitter: AuthEventEmitter;
25
- storage: StorageAdapter;
26
- defaultSync?: SyncOption;
27
- defaultDwnEndpoints?: string[];
28
- registration?: RegistrationOptions;
29
- }
12
+ import type { AuthSession } from '../identity-session.js';
13
+ import type { FlowContext } from './lifecycle.js';
14
+ import type { WalletConnectOptions } from '../types.js';
15
+
16
+ import { Convert } from '@enbox/common';
17
+ import { registerWithDwnEndpoints } from '../registration.js';
18
+ import { WalletConnect } from '../wallet-connect-client.js';
19
+ import { DEFAULT_DWN_ENDPOINTS, STORAGE_KEYS } from '../types.js';
20
+ import { DwnInterface, DwnPermissionGrant } from '@enbox/agent';
21
+ import { ensureVaultReady, finalizeSession, resolvePassword, startSyncIfEnabled } from './lifecycle.js';
30
22
 
31
23
  /**
32
24
  * Process connected grants by storing them in the local DWN as the owner.
@@ -86,7 +78,7 @@ export async function processConnectedGrants(params: {
86
78
  * 3. Sets up sync and returns an AuthSession.
87
79
  */
88
80
  export async function walletConnect(
89
- ctx: WalletConnectContext,
81
+ ctx: FlowContext,
90
82
  options: WalletConnectOptions,
91
83
  ): Promise<AuthSession> {
92
84
  const { userAgent, emitter, storage } = ctx;
@@ -99,12 +91,23 @@ export async function walletConnect(
99
91
  );
100
92
  }
101
93
 
102
- // Run the full OIDC wallet connect flow.
94
+ // Ensure the agent is initialized and started before the relay flow.
95
+ const isFirstLaunch = await userAgent.firstLaunch();
96
+ const password = await resolvePassword(ctx, undefined, isFirstLaunch);
97
+
98
+ await ensureVaultReady({
99
+ userAgent,
100
+ emitter,
101
+ password,
102
+ isFirstLaunch,
103
+ });
104
+
105
+ // Run the Enbox Connect relay flow.
103
106
  // permissionRequests are already agent-level ConnectPermissionRequest objects.
104
107
  const result = await WalletConnect.initClient({
105
108
  displayName : options.displayName,
106
109
  connectServerUrl : options.connectServerUrl,
107
- walletUri : options.walletUri ?? 'web5://connect',
110
+ walletUri : options.walletUri ?? 'enbox://connect',
108
111
  permissionRequests : options.permissionRequests,
109
112
  onWalletUriReady : options.onWalletUriReady,
110
113
  validatePin : options.validatePin,
@@ -140,13 +143,14 @@ export async function walletConnect(
140
143
 
141
144
  // Register with DWN endpoints (if registration options are provided).
142
145
  if (ctx.registration) {
143
- const dwnEndpoints = ctx.defaultDwnEndpoints ?? ['https://enbox-dwn.fly.dev'];
146
+ const dwnEndpoints = ctx.defaultDwnEndpoints ?? DEFAULT_DWN_ENDPOINTS;
144
147
  await registerWithDwnEndpoints(
145
148
  {
146
149
  userAgent : userAgent,
147
150
  dwnEndpoints,
148
151
  agentDid : userAgent.agentDid.uri,
149
152
  connectedDid,
153
+ storage : storage,
150
154
  },
151
155
  ctx.registration,
152
156
  );
@@ -183,43 +187,23 @@ export async function walletConnect(
183
187
  throw new Error(`[@enbox/auth] Wallet connect failed: ${message}`);
184
188
  }
185
189
 
186
- // Start sync.
187
- const syncMode = sync === undefined ? 'live' : 'poll';
188
- const syncInterval = sync ?? (syncMode === 'live' ? '5m' : '2m');
189
- userAgent.sync.startSync({ mode: syncMode, interval: syncInterval })
190
- .catch((err: unknown) => {
191
- console.error('[@enbox/auth] Sync failed:', err);
192
- });
193
-
194
190
  const delegateDid = delegatePortableDid.uri;
195
191
 
196
- // Persist session info.
197
- await storage.set(STORAGE_KEYS.PREVIOUSLY_CONNECTED, 'true');
198
- await storage.set(STORAGE_KEYS.ACTIVE_IDENTITY, connectedDid);
199
- await storage.set(STORAGE_KEYS.DELEGATE_DID, delegateDid);
200
- await storage.set(STORAGE_KEYS.CONNECTED_DID, connectedDid);
201
-
202
- const identityInfo = {
203
- didUri : connectedDid,
204
- name : identity.metadata.name,
205
- connectedDid : identity.metadata.connectedDid,
206
- };
207
-
208
- const session = new AuthSession({
209
- agent : userAgent,
210
- did : connectedDid,
192
+ // Start sync.
193
+ startSyncIfEnabled(userAgent, sync);
194
+
195
+ // Persist session info, build AuthSession, and emit lifecycle events.
196
+ return finalizeSession({
197
+ userAgent,
198
+ emitter,
199
+ storage,
200
+ connectedDid,
211
201
  delegateDid,
212
- identity : identityInfo,
213
- });
214
-
215
- emitter.emit('identity-added', { identity: identityInfo });
216
- emitter.emit('session-start', {
217
- session: {
218
- did : session.did,
219
- delegateDid,
220
- identity : identityInfo,
202
+ identityName : identity.metadata.name,
203
+ identityConnectedDid : identity.metadata.connectedDid,
204
+ extraStorageKeys : {
205
+ [STORAGE_KEYS.DELEGATE_DID] : delegateDid,
206
+ [STORAGE_KEYS.CONNECTED_DID] : connectedDid,
221
207
  },
222
208
  });
223
-
224
- return session;
225
209
  }
@@ -7,42 +7,39 @@
7
7
  *
8
8
  * ## Discovery channels (browser, highest to lowest priority)
9
9
  *
10
- * 1. **URL fragment payload** — A `dwn://register` redirect just landed
10
+ * 1. **URL fragment payload** — A `dwn://connect` redirect just landed
11
11
  * on the page with the endpoint in `#`. Highest priority because it's
12
12
  * fresh and explicit.
13
13
  * 2. **Persisted endpoint** (localStorage) — A previously discovered
14
14
  * endpoint restored and re-validated via `GET /info`.
15
- * 3. **Agent-level discovery** (transparent, runs on every `sendRequest`)
16
- * — `~/.enbox/dwn.json` discovery file (Node/Bun only; skipped in
17
- * browsers) and sequential port probing on `127.0.0.1:{3000,55500–55509}`.
18
- * This channel works even if the browser-specific functions here
19
- * return `false`.
20
15
  *
21
16
  * ## Discovery channels (CLI / native, all transparent)
22
17
  *
23
- * In Node/Bun environments, all discovery happens automatically inside
18
+ * In Node/Bun environments, the agent's `LocalDwnDiscovery` reads the
19
+ * `~/.enbox/dwn.json` discovery file automatically inside
24
20
  * `AgentDwnApi.getLocalDwnEndpoint()`. The browser-specific functions
25
21
  * in this module (`checkUrlForDwnDiscoveryPayload`, `requestLocalDwnDiscovery`)
26
- * are not needed the agent reads `~/.enbox/dwn.json` and probes ports
27
- * on its own.
22
+ * are not needed in those environments.
28
23
  *
29
- * @see https://github.com/enboxorg/enbox/issues/589
24
+ * @see https://github.com/enboxorg/enbox/issues/677
30
25
  * @module
31
26
  */
32
27
 
33
28
  import type { EnboxUserAgent } from '@enbox/agent';
34
29
 
35
- import { buildDwnRegisterUrl, readDwnDiscoveryPayloadFromUrl } from '@enbox/agent';
30
+ import { EnboxRpcClient } from '@enbox/dwn-clients';
31
+ import { buildDwnConnectUrl, localDwnServerName, normalizeBaseUrl, readDwnDiscoveryPayloadFromUrl } from '@enbox/agent';
36
32
 
37
- import type { AuthEventEmitter } from '../events.js';
38
- import { STORAGE_KEYS } from '../types.js';
39
- import type { StorageAdapter } from '../types.js';
33
+ import type { AuthEventEmitter } from './events.js';
34
+ import type { StorageAdapter } from './types.js';
35
+
36
+ import { STORAGE_KEYS } from './types.js';
40
37
 
41
38
  /**
42
39
  * Check the current page URL for a `DwnDiscoveryPayload` in the fragment.
43
40
  *
44
41
  * This is called once at the start of a connection flow to detect whether
45
- * the user was just redirected back from a `dwn://register` handler. If a
42
+ * the user was just redirected back from a `dwn://connect` handler. If a
46
43
  * valid payload is found, the endpoint is persisted and the fragment is
47
44
  * cleared to prevent double-reads.
48
45
  *
@@ -69,6 +66,83 @@ export function checkUrlForDwnDiscoveryPayload(): string | undefined {
69
66
  return payload.endpoint;
70
67
  }
71
68
 
69
+ // ─── Standalone (pre-agent) discovery ───────────────────────────
70
+
71
+ /**
72
+ * Validate a local DWN endpoint by calling `GET /info` and checking
73
+ * that the server identifies itself as `@enbox/dwn-server`.
74
+ *
75
+ * This function has **zero** agent or vault dependencies — it only uses
76
+ * the network. It is safe to call before the agent exists.
77
+ *
78
+ * @param endpoint - The candidate endpoint URL.
79
+ * @returns The normalised endpoint if valid, `undefined` otherwise.
80
+ */
81
+ async function validateEndpointStandalone(endpoint: string): Promise<string | undefined> {
82
+ const normalized = normalizeBaseUrl(endpoint);
83
+ try {
84
+ const rpc = new EnboxRpcClient();
85
+ const serverInfo = await rpc.getServerInfo(normalized);
86
+ if (serverInfo.server === localDwnServerName) {
87
+ return normalized;
88
+ }
89
+ } catch {
90
+ // Server not reachable or not ours.
91
+ }
92
+ return undefined;
93
+ }
94
+
95
+ /**
96
+ * Run local DWN discovery **before the agent exists**.
97
+ *
98
+ * This is the standalone counterpart of {@link applyLocalDwnDiscovery} and
99
+ * is designed to be called in `AuthManager.create()`, before
100
+ * `EnboxUserAgent.create()`, so the agent creation can decide whether to
101
+ * spin up an in-process DWN or operate in remote mode.
102
+ *
103
+ * Discovery channels (highest → lowest priority):
104
+ * 1. **URL fragment payload** — A `dwn://connect` redirect just landed.
105
+ * 2. **Persisted endpoint** (localStorage) — A previously discovered
106
+ * endpoint, re-validated via `GET /info`.
107
+ *
108
+ * When a valid endpoint is found it is persisted to storage. When a
109
+ * previously-persisted endpoint is stale, it is removed.
110
+ *
111
+ * @param storage - The auth storage adapter (for reading/writing the
112
+ * cached endpoint).
113
+ * @returns The validated endpoint URL, or `undefined` if no local DWN
114
+ * server is available.
115
+ */
116
+ export async function discoverLocalDwn(
117
+ storage: StorageAdapter,
118
+ ): Promise<string | undefined> {
119
+ // Channel 1: Fresh redirect payload in the URL fragment.
120
+ const freshEndpoint = checkUrlForDwnDiscoveryPayload();
121
+ if (freshEndpoint) {
122
+ const validated = await validateEndpointStandalone(freshEndpoint);
123
+ if (validated) {
124
+ await persistLocalDwnEndpoint(storage, validated);
125
+ return validated;
126
+ }
127
+ // Payload was in the URL but the server is unreachable — fall through.
128
+ }
129
+
130
+ // Channel 2: Persisted endpoint from a previous session.
131
+ const cached = await storage.get(STORAGE_KEYS.LOCAL_DWN_ENDPOINT);
132
+ if (cached) {
133
+ const validated = await validateEndpointStandalone(cached);
134
+ if (validated) {
135
+ return validated;
136
+ }
137
+ // Stale — server no longer running.
138
+ await clearLocalDwnEndpoint(storage);
139
+ }
140
+
141
+ return undefined;
142
+ }
143
+
144
+ // ─── Storage helpers ────────────────────────────────────────────
145
+
72
146
  /**
73
147
  * Persist a discovered local DWN endpoint in auth storage.
74
148
  *
@@ -130,25 +204,18 @@ export async function restoreLocalDwnEndpoint(
130
204
  * Run the full local DWN discovery sequence for a browser connection flow.
131
205
  *
132
206
  * This function handles the **receiving** side of local DWN discovery in
133
- * the browser. It does NOT trigger the `dwn://register` redirect — use
207
+ * the browser. It does NOT trigger the `dwn://connect` redirect — use
134
208
  * {@link requestLocalDwnDiscovery} for that.
135
209
  *
136
210
  * The discovery channels, from highest to lowest priority:
137
211
  *
138
- * 1. **URL fragment payload** — A `dwn://register` redirect just landed on
212
+ * 1. **URL fragment payload** — A `dwn://connect` redirect just landed on
139
213
  * this page with the DWN endpoint in `#`. This is the highest-priority
140
214
  * signal because it's fresh and explicit.
141
215
  *
142
216
  * 2. **Persisted endpoint** (localStorage) — A previously discovered
143
217
  * endpoint is restored and re-validated via `GET /info`.
144
218
  *
145
- * 3. **Agent-level discovery** (transparent) — Even if this function
146
- * returns `false`, the agent's `LocalDwnDiscovery` will independently
147
- * try the discovery file (`~/.enbox/dwn.json`) and port probing on
148
- * every `sendRequest()` call. Those channels are not available in
149
- * browsers (no filesystem access, CORS may block probes), but they
150
- * work transparently in Node/Bun CLI environments.
151
- *
152
219
  * When an `emitter` is provided, this function emits:
153
220
  * - `'local-dwn-available'` with the endpoint when discovery succeeds.
154
221
  * - `'local-dwn-unavailable'` when no local DWN could be reached.
@@ -191,37 +258,31 @@ export async function applyLocalDwnDiscovery(
191
258
  return restored;
192
259
  }
193
260
 
194
- // ─── dwn://register trigger ─────────────────────────────────────
261
+ // ─── dwn://connect trigger ──────────────────────────────────────
195
262
 
196
263
  /**
197
- * Initiate the `dwn://register` flow by opening the register URL.
264
+ * Initiate the `dwn://connect` flow by opening the connect URL.
198
265
  *
199
- * This asks the operating system to route `dwn://register?callback=<url>`
266
+ * This asks the operating system to route `dwn://connect?callback=<url>`
200
267
  * to the registered handler (electrobun-dwn), which will redirect the
201
268
  * user's browser back to `callbackUrl` with the local DWN endpoint
202
269
  * encoded in the URL fragment.
203
270
  *
204
- * **Important:** There is no reliable cross-browser API to detect whether
205
- * a `dwn://` handler is installed. If no handler is registered, this call
206
- * will silently fail or show an OS-level error dialog. Use
207
- * {@link probeLocalDwn} first to check if a local DWN is already
208
- * reachable via port probing — if it is, you can skip the register flow
209
- * entirely and call {@link applyLocalDwnDiscovery} instead.
271
+ * **Note:** There is no reliable cross-browser API to detect whether a
272
+ * `dwn://` handler is installed. If no handler is registered, this call
273
+ * will silently fail or show an OS-level error dialog.
210
274
  *
211
275
  * @param callbackUrl - The URL to redirect back to. Defaults to the
212
276
  * current page URL (without its fragment) if running in a browser.
213
- * @returns `true` if the register URL was opened, `false` if no
277
+ * @returns `true` if the connect URL was opened, `false` if no
214
278
  * callback URL could be determined (e.g. no `globalThis.location`).
215
279
  *
216
280
  * @example
217
281
  * ```ts
218
- * // Check if local DWN is already available via direct probe.
219
- * const alreadyAvailable = await probeLocalDwn();
220
- * if (!alreadyAvailable) {
221
- * // No local DWN found trigger the dwn://register flow.
222
- * requestLocalDwnDiscovery();
223
- * // The page will reload with the endpoint in the URL fragment.
224
- * }
282
+ * // Trigger the dwn://connect flow to discover a local DWN.
283
+ * requestLocalDwnDiscovery();
284
+ * // The page will reload with the endpoint in the URL fragment.
285
+ * // On the next connect/restore, applyLocalDwnDiscovery() reads it.
225
286
  * ```
226
287
  */
227
288
  export function requestLocalDwnDiscovery(callbackUrl?: string): boolean {
@@ -230,7 +291,7 @@ export function requestLocalDwnDiscovery(callbackUrl?: string): boolean {
230
291
  return false;
231
292
  }
232
293
 
233
- const registerUrl = buildDwnRegisterUrl(resolvedCallback);
294
+ const registerUrl = buildDwnConnectUrl(resolvedCallback);
234
295
 
235
296
  // Open the dwn:// URL. Use window.open() rather than location.href
236
297
  // assignment to avoid navigating away from the current page if the
@@ -249,46 +310,6 @@ export function requestLocalDwnDiscovery(callbackUrl?: string): boolean {
249
310
  return false;
250
311
  }
251
312
 
252
- /**
253
- * Probe whether a local DWN server is reachable via direct HTTP fetch.
254
- *
255
- * Attempts `GET http://127.0.0.1:{port}/info` on the well-known port
256
- * candidates and returns the endpoint URL of the first server that
257
- * responds with a valid `@enbox/dwn-server` identity.
258
- *
259
- * This is useful in browsers to check if a local DWN is available
260
- * *before* triggering the `dwn://register` redirect flow — if the
261
- * server is already reachable (CORS permitting), the redirect is
262
- * unnecessary.
263
- *
264
- * @returns The local DWN endpoint URL, or `undefined` if no server
265
- * was found. Returns `undefined` (rather than throwing) on CORS
266
- * errors or network failures.
267
- */
268
- export async function probeLocalDwn(): Promise<string | undefined> {
269
- // Import port candidates from @enbox/agent. Using a dynamic import
270
- // here keeps the function self-contained and avoids circular deps.
271
- const { localDwnPortCandidates, localDwnHostCandidates } = await import('@enbox/agent');
272
-
273
- for (const port of localDwnPortCandidates) {
274
- for (const host of localDwnHostCandidates) {
275
- const endpoint = `http://${host}:${port}`;
276
- try {
277
- const response = await fetch(`${endpoint}/info`, { signal: AbortSignal.timeout(2_000) });
278
- if (!response.ok) { continue; }
279
-
280
- const serverInfo = await response.json() as { server?: string };
281
- if (serverInfo?.server === '@enbox/dwn-server') {
282
- return endpoint;
283
- }
284
- } catch {
285
- // Network error, CORS block, or timeout — try next candidate.
286
- }
287
- }
288
- }
289
- return undefined;
290
- }
291
-
292
313
  // ─── Internal helpers ───────────────────────────────────────────
293
314
 
294
315
  /** Return the current page URL without the fragment, or `undefined`. */
package/src/index.ts CHANGED
@@ -37,26 +37,34 @@
37
37
  // Core classes
38
38
  export { AuthManager } from './auth-manager.js';
39
39
  export { AuthSession } from './identity-session.js';
40
- export { VaultManager } from './vault/vault-manager.js';
41
40
  export { AuthEventEmitter } from './events.js';
42
41
 
42
+ // Password providers
43
+ export { PasswordProvider } from './password-provider.js';
44
+ export type { PasswordContext } from './password-provider.js';
45
+
43
46
  // Re-export agent classes so consumers can construct custom agents/vaults
44
47
  // without a direct @enbox/agent dependency.
45
48
  export { EnboxUserAgent, HdIdentityVault } from '@enbox/agent';
46
49
 
47
50
  // Wallet-connect helpers
48
- export { processConnectedGrants } from './flows/wallet-connect.js';
51
+ export { processConnectedGrants } from './connect/wallet.js';
52
+ export { WalletConnect } from './wallet-connect-client.js';
53
+ export type { Permission, ProtocolPermissionOptions, WalletConnectClientOptions } from './wallet-connect-client.js';
54
+
55
+ // Registration token storage helpers
56
+ export { loadTokensFromStorage, saveTokensToStorage } from './registration.js';
49
57
 
50
58
  // Local DWN discovery (browser dwn:// protocol integration)
51
59
  export {
52
60
  applyLocalDwnDiscovery,
53
61
  checkUrlForDwnDiscoveryPayload,
54
62
  clearLocalDwnEndpoint,
63
+ discoverLocalDwn,
55
64
  persistLocalDwnEndpoint,
56
- probeLocalDwn,
57
65
  requestLocalDwnDiscovery,
58
66
  restoreLocalDwnEndpoint,
59
- } from './flows/dwn-discovery.js';
67
+ } from './discovery.js';
60
68
 
61
69
  // Storage adapters
62
70
  export { BrowserStorage, LevelStorage, MemoryStorage, createDefaultStorage } from './storage/storage.js';
@@ -71,6 +79,7 @@ export type {
71
79
  AuthState,
72
80
  ConnectPermissionRequest,
73
81
  DisconnectOptions,
82
+ HeadlessConnectOptions,
74
83
  IdentityInfo,
75
84
  IdentityVaultBackup,
76
85
  ImportFromPhraseOptions,
@@ -83,6 +92,7 @@ export type {
83
92
  RegistrationOptions,
84
93
  RegistrationTokenData,
85
94
  RestoreSessionOptions,
95
+ ShutdownOptions,
86
96
  StorageAdapter,
87
97
  SyncOption,
88
98
  WalletConnectOptions,