@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.
- package/dist/esm/auth-manager.js +244 -121
- package/dist/esm/auth-manager.js.map +1 -1
- package/dist/esm/connect/import.js +131 -0
- package/dist/esm/connect/import.js.map +1 -0
- package/dist/esm/connect/lifecycle.js +235 -0
- package/dist/esm/connect/lifecycle.js.map +1 -0
- package/dist/esm/connect/local.js +91 -0
- package/dist/esm/connect/local.js.map +1 -0
- package/dist/esm/{flows/session-restore.js → connect/restore.js} +39 -50
- package/dist/esm/connect/restore.js.map +1 -0
- package/dist/esm/{flows/wallet-connect.js → connect/wallet.js} +33 -39
- package/dist/esm/connect/wallet.js.map +1 -0
- package/dist/esm/{flows/dwn-discovery.js → discovery.js} +98 -83
- package/dist/esm/discovery.js.map +1 -0
- package/dist/esm/index.js +7 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/password-provider.js +319 -0
- package/dist/esm/password-provider.js.map +1 -0
- package/dist/esm/{flows/dwn-registration.js → registration.js} +50 -4
- package/dist/esm/registration.js.map +1 -0
- package/dist/esm/types.js +11 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/wallet-connect-client.js +188 -0
- package/dist/esm/wallet-connect-client.js.map +1 -0
- package/dist/types/auth-manager.d.ts +86 -7
- package/dist/types/auth-manager.d.ts.map +1 -1
- package/dist/types/connect/import.d.ts +25 -0
- package/dist/types/connect/import.d.ts.map +1 -0
- package/dist/types/connect/lifecycle.d.ts +152 -0
- package/dist/types/connect/lifecycle.d.ts.map +1 -0
- package/dist/types/connect/local.d.ts +18 -0
- package/dist/types/connect/local.d.ts.map +1 -0
- package/dist/types/connect/restore.d.ts +18 -0
- package/dist/types/connect/restore.d.ts.map +1 -0
- package/dist/types/{flows/wallet-connect.d.ts → connect/wallet.d.ts} +7 -16
- package/dist/types/connect/wallet.d.ts.map +1 -0
- package/dist/types/{flows/dwn-discovery.d.ts → discovery.d.ts} +43 -56
- package/dist/types/discovery.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/password-provider.d.ts +194 -0
- package/dist/types/password-provider.d.ts.map +1 -0
- package/dist/types/{flows/dwn-registration.d.ts → registration.d.ts} +21 -2
- package/dist/types/registration.d.ts.map +1 -0
- package/dist/types/types.d.ts +92 -4
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/wallet-connect-client.d.ts +89 -0
- package/dist/types/wallet-connect-client.d.ts.map +1 -0
- package/package.json +15 -12
- package/src/auth-manager.ts +279 -145
- package/src/connect/import.ts +148 -0
- package/src/connect/lifecycle.ts +321 -0
- package/src/connect/local.ts +101 -0
- package/src/connect/restore.ts +117 -0
- package/src/{flows/wallet-connect.ts → connect/wallet.ts} +42 -58
- package/src/{flows/dwn-discovery.ts → discovery.ts} +103 -82
- package/src/index.ts +14 -4
- package/src/password-provider.ts +383 -0
- package/src/{flows/dwn-registration.ts → registration.ts} +61 -6
- package/src/types.ts +100 -4
- package/src/wallet-connect-client.ts +278 -0
- package/dist/esm/flows/dwn-discovery.js.map +0 -1
- package/dist/esm/flows/dwn-registration.js.map +0 -1
- package/dist/esm/flows/import-identity.js +0 -175
- package/dist/esm/flows/import-identity.js.map +0 -1
- package/dist/esm/flows/local-connect.js +0 -141
- package/dist/esm/flows/local-connect.js.map +0 -1
- package/dist/esm/flows/session-restore.js.map +0 -1
- package/dist/esm/flows/wallet-connect.js.map +0 -1
- package/dist/esm/vault/vault-manager.js +0 -95
- package/dist/esm/vault/vault-manager.js.map +0 -1
- package/dist/types/flows/dwn-discovery.d.ts.map +0 -1
- package/dist/types/flows/dwn-registration.d.ts.map +0 -1
- package/dist/types/flows/import-identity.d.ts +0 -35
- package/dist/types/flows/import-identity.d.ts.map +0 -1
- package/dist/types/flows/local-connect.d.ts +0 -29
- package/dist/types/flows/local-connect.d.ts.map +0 -1
- package/dist/types/flows/session-restore.d.ts +0 -27
- package/dist/types/flows/session-restore.d.ts.map +0 -1
- package/dist/types/flows/wallet-connect.d.ts.map +0 -1
- package/dist/types/vault/vault-manager.d.ts +0 -57
- package/dist/types/vault/vault-manager.d.ts.map +0 -1
- package/src/flows/import-identity.ts +0 -217
- package/src/flows/local-connect.ts +0 -171
- package/src/flows/session-restore.ts +0 -142
- package/src/vault/vault-manager.ts +0 -89
|
@@ -1,32 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wallet connect (
|
|
2
|
+
* Wallet connect (Enbox Connect relay) flow.
|
|
3
3
|
*
|
|
4
|
-
* Connects to an external wallet via the
|
|
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 {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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:
|
|
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
|
-
//
|
|
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 ?? '
|
|
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 ??
|
|
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
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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://
|
|
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,
|
|
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
|
|
27
|
-
* on its own.
|
|
22
|
+
* are not needed in those environments.
|
|
28
23
|
*
|
|
29
|
-
* @see https://github.com/enboxorg/enbox/issues/
|
|
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 {
|
|
30
|
+
import { EnboxRpcClient } from '@enbox/dwn-clients';
|
|
31
|
+
import { buildDwnConnectUrl, localDwnServerName, normalizeBaseUrl, readDwnDiscoveryPayloadFromUrl } from '@enbox/agent';
|
|
36
32
|
|
|
37
|
-
import type { AuthEventEmitter } from '
|
|
38
|
-
import {
|
|
39
|
-
|
|
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://
|
|
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://
|
|
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://
|
|
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://
|
|
261
|
+
// ─── dwn://connect trigger ──────────────────────────────────────
|
|
195
262
|
|
|
196
263
|
/**
|
|
197
|
-
* Initiate the `dwn://
|
|
264
|
+
* Initiate the `dwn://connect` flow by opening the connect URL.
|
|
198
265
|
*
|
|
199
|
-
* This asks the operating system to route `dwn://
|
|
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
|
-
* **
|
|
205
|
-
*
|
|
206
|
-
* will silently fail or show an OS-level error dialog.
|
|
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
|
|
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
|
-
* //
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
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 =
|
|
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 './
|
|
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 './
|
|
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,
|