@enbox/agent 0.2.1 → 0.3.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/browser.mjs +9 -9
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/agent-did-resolver-cache.js.map +1 -1
- package/dist/esm/anonymous-dwn-api.js +1 -1
- package/dist/esm/bearer-identity.js +1 -1
- package/dist/esm/connect.js +3 -3
- package/dist/esm/connect.js.map +1 -1
- package/dist/esm/did-api.js +3 -3
- package/dist/esm/did-api.js.map +1 -1
- package/dist/esm/dwn-api.js +150 -10
- package/dist/esm/dwn-api.js.map +1 -1
- package/dist/esm/dwn-discovery-file.js +244 -0
- package/dist/esm/dwn-discovery-file.js.map +1 -0
- package/dist/esm/dwn-discovery-payload.js +253 -0
- package/dist/esm/dwn-discovery-payload.js.map +1 -0
- package/dist/esm/dwn-encryption.js.map +1 -1
- package/dist/esm/dwn-key-delivery.js +6 -5
- package/dist/esm/dwn-key-delivery.js.map +1 -1
- package/dist/esm/dwn-protocol-cache.js +6 -7
- package/dist/esm/dwn-protocol-cache.js.map +1 -1
- package/dist/esm/dwn-record-upgrade.js.map +1 -1
- package/dist/esm/{web5-user-agent.js → enbox-user-agent.js} +18 -9
- package/dist/esm/enbox-user-agent.js.map +1 -0
- package/dist/esm/identity-api.js +4 -5
- package/dist/esm/identity-api.js.map +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/local-dwn.js +197 -0
- package/dist/esm/local-dwn.js.map +1 -0
- package/dist/esm/local-key-manager.js +2 -2
- package/dist/esm/local-key-manager.js.map +1 -1
- package/dist/esm/oidc.js +11 -11
- package/dist/esm/oidc.js.map +1 -1
- package/dist/esm/permissions-api.js.map +1 -1
- package/dist/esm/store-data.js.map +1 -1
- package/dist/esm/sync-api.js +2 -2
- package/dist/esm/sync-api.js.map +1 -1
- package/dist/esm/sync-engine-level.js +3 -4
- package/dist/esm/sync-engine-level.js.map +1 -1
- package/dist/esm/test-harness.js +5 -4
- package/dist/esm/test-harness.js.map +1 -1
- package/dist/esm/utils-internal.js +2 -2
- package/dist/types/agent-did-resolver-cache.d.ts +7 -7
- package/dist/types/agent-did-resolver-cache.d.ts.map +1 -1
- package/dist/types/anonymous-dwn-api.d.ts +3 -3
- package/dist/types/anonymous-dwn-api.d.ts.map +1 -1
- package/dist/types/bearer-identity.d.ts +1 -1
- package/dist/types/connect.d.ts +8 -8
- package/dist/types/connect.d.ts.map +1 -1
- package/dist/types/did-api.d.ts +12 -11
- package/dist/types/did-api.d.ts.map +1 -1
- package/dist/types/dwn-api.d.ts +58 -11
- package/dist/types/dwn-api.d.ts.map +1 -1
- package/dist/types/dwn-discovery-file.d.ts +122 -0
- package/dist/types/dwn-discovery-file.d.ts.map +1 -0
- package/dist/types/dwn-discovery-payload.d.ts +105 -0
- package/dist/types/dwn-discovery-payload.d.ts.map +1 -0
- package/dist/types/dwn-encryption.d.ts +8 -8
- package/dist/types/dwn-encryption.d.ts.map +1 -1
- package/dist/types/dwn-key-delivery.d.ts +9 -7
- package/dist/types/dwn-key-delivery.d.ts.map +1 -1
- package/dist/types/dwn-protocol-cache.d.ts +6 -5
- package/dist/types/dwn-protocol-cache.d.ts.map +1 -1
- package/dist/types/dwn-record-upgrade.d.ts +2 -2
- package/dist/types/dwn-record-upgrade.d.ts.map +1 -1
- package/dist/types/{web5-user-agent.d.ts → enbox-user-agent.d.ts} +21 -13
- package/dist/types/enbox-user-agent.d.ts.map +1 -0
- package/dist/types/identity-api.d.ts +10 -10
- package/dist/types/identity-api.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/local-dwn.d.ts +121 -0
- package/dist/types/local-dwn.d.ts.map +1 -0
- package/dist/types/local-key-manager.d.ts +9 -9
- package/dist/types/local-key-manager.d.ts.map +1 -1
- package/dist/types/oidc.d.ts +23 -19
- package/dist/types/oidc.d.ts.map +1 -1
- package/dist/types/permissions-api.d.ts +4 -4
- package/dist/types/permissions-api.d.ts.map +1 -1
- package/dist/types/store-data.d.ts +3 -3
- package/dist/types/store-data.d.ts.map +1 -1
- package/dist/types/store-did.d.ts +2 -2
- package/dist/types/store-did.d.ts.map +1 -1
- package/dist/types/store-identity.d.ts +2 -2
- package/dist/types/store-identity.d.ts.map +1 -1
- package/dist/types/store-key.d.ts +2 -2
- package/dist/types/store-key.d.ts.map +1 -1
- package/dist/types/sync-api.d.ts +9 -9
- package/dist/types/sync-api.d.ts.map +1 -1
- package/dist/types/sync-engine-level.d.ts +9 -9
- package/dist/types/sync-engine-level.d.ts.map +1 -1
- package/dist/types/sync-messages.d.ts +5 -5
- package/dist/types/sync-messages.d.ts.map +1 -1
- package/dist/types/test-harness.d.ts +4 -4
- package/dist/types/test-harness.d.ts.map +1 -1
- package/dist/types/types/agent.d.ts +24 -19
- package/dist/types/types/agent.d.ts.map +1 -1
- package/dist/types/types/identity.d.ts +1 -1
- package/dist/types/types/key-manager.d.ts +2 -2
- package/dist/types/types/key-manager.d.ts.map +1 -1
- package/dist/types/types/sync.d.ts +2 -2
- package/dist/types/types/sync.d.ts.map +1 -1
- package/dist/types/utils-internal.d.ts +4 -4
- package/dist/types/utils-internal.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/agent-did-resolver-cache.ts +8 -8
- package/src/anonymous-dwn-api.ts +4 -4
- package/src/bearer-identity.ts +1 -1
- package/src/connect.ts +12 -12
- package/src/did-api.ts +13 -11
- package/src/dwn-api.ts +196 -16
- package/src/dwn-discovery-file.ts +305 -0
- package/src/dwn-discovery-payload.ts +308 -0
- package/src/dwn-encryption.ts +8 -8
- package/src/dwn-key-delivery.ts +11 -8
- package/src/dwn-protocol-cache.ts +9 -8
- package/src/dwn-record-upgrade.ts +2 -2
- package/src/{web5-user-agent.ts → enbox-user-agent.ts} +39 -19
- package/src/identity-api.ts +12 -13
- package/src/index.ts +4 -1
- package/src/local-dwn.ts +207 -0
- package/src/local-key-manager.ts +10 -10
- package/src/oidc.ts +40 -30
- package/src/permissions-api.ts +5 -5
- package/src/store-data.ts +7 -7
- package/src/store-did.ts +2 -2
- package/src/store-identity.ts +2 -2
- package/src/store-key.ts +2 -2
- package/src/sync-api.ts +10 -10
- package/src/sync-engine-level.ts +13 -14
- package/src/sync-messages.ts +5 -5
- package/src/test-harness.ts +11 -10
- package/src/types/agent.ts +31 -20
- package/src/types/identity.ts +1 -1
- package/src/types/key-manager.ts +2 -2
- package/src/types/sync.ts +2 -2
- package/src/utils-internal.ts +4 -4
- package/dist/esm/web5-user-agent.js.map +0 -1
- package/dist/types/web5-user-agent.d.ts.map +0 -1
package/src/dwn-key-delivery.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
RecordsReadReply,
|
|
7
7
|
} from '@enbox/dwn-sdk-js';
|
|
8
8
|
|
|
9
|
-
import type {
|
|
9
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
10
10
|
import type {
|
|
11
11
|
DwnMessage,
|
|
12
12
|
DwnMessageReply,
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
Records,
|
|
23
23
|
} from '@enbox/dwn-sdk-js';
|
|
24
24
|
|
|
25
|
-
import { getDwnServiceEndpointUrls } from './utils.js';
|
|
26
25
|
import { KeyDeliveryProtocolDefinition } from './store-data-protocols.js';
|
|
27
26
|
import { buildEncryptionInput, encryptAndComputeCid, getEncryptionKeyDeriver, getKeyDecrypter, ivLength } from './dwn-encryption.js';
|
|
28
27
|
import { DwnInterface, dwnMessageConstructors } from './types/dwn.js';
|
|
@@ -66,7 +65,7 @@ type ProcessRequestFn = <T extends DwnInterface>(
|
|
|
66
65
|
* @param installedCache - Cache for installation status
|
|
67
66
|
*/
|
|
68
67
|
export async function ensureKeyDeliveryProtocol(
|
|
69
|
-
agent:
|
|
68
|
+
agent: EnboxPlatformAgent,
|
|
70
69
|
tenantDid: string,
|
|
71
70
|
processRequest: ProcessRequestFn,
|
|
72
71
|
getProtocolDefinition: (tenantDid: string, protocolUri: string) => Promise<any>,
|
|
@@ -121,7 +120,7 @@ export async function ensureKeyDeliveryProtocol(
|
|
|
121
120
|
* @returns The recordId of the written contextKey record
|
|
122
121
|
*/
|
|
123
122
|
export async function writeContextKeyRecord(
|
|
124
|
-
agent:
|
|
123
|
+
agent: EnboxPlatformAgent,
|
|
125
124
|
params: WriteContextKeyParams,
|
|
126
125
|
processRequest: ProcessRequestFn,
|
|
127
126
|
ensureProtocol: (tenantDid: string) => Promise<void>,
|
|
@@ -219,17 +218,19 @@ export async function writeContextKeyRecord(
|
|
|
219
218
|
* @param contextKeyMessage - The context key message to send
|
|
220
219
|
* @param getDwnMessage - Function to read a full message from local DWN
|
|
221
220
|
* @param sendDwnRpcRequest - Function to send a DWN RPC request
|
|
221
|
+
* @param getDwnEndpointUrlsForTarget - Function to resolve DWN endpoint URLs (with local discovery)
|
|
222
222
|
*/
|
|
223
223
|
export async function eagerSendContextKeyRecord(
|
|
224
|
-
agent:
|
|
224
|
+
agent: EnboxPlatformAgent,
|
|
225
225
|
tenantDid: string,
|
|
226
226
|
contextKeyMessage: DwnMessage[DwnInterface.RecordsWrite],
|
|
227
227
|
getDwnMessage: (params: { author: string; messageType: DwnInterface; messageCid: string }) => Promise<{ message: any; data?: Blob }>,
|
|
228
228
|
sendDwnRpcRequest: (params: { targetDid: string; dwnEndpointUrls: string[]; message: any; data?: Blob }) => Promise<any>,
|
|
229
|
+
getDwnEndpointUrlsForTarget: (targetDid: string) => Promise<string[]>,
|
|
229
230
|
): Promise<void> {
|
|
230
231
|
let dwnEndpointUrls: string[];
|
|
231
232
|
try {
|
|
232
|
-
dwnEndpointUrls = await
|
|
233
|
+
dwnEndpointUrls = await getDwnEndpointUrlsForTarget(tenantDid);
|
|
233
234
|
} catch {
|
|
234
235
|
// DID resolution or endpoint lookup failed — not fatal, sync will handle it.
|
|
235
236
|
return;
|
|
@@ -266,14 +267,16 @@ export async function eagerSendContextKeyRecord(
|
|
|
266
267
|
* @param processRequest - The agent's processRequest method (bound)
|
|
267
268
|
* @param getSigner - Function to get a signer for a DID
|
|
268
269
|
* @param sendDwnRpcRequest - Function to send a DWN RPC request
|
|
270
|
+
* @param getDwnEndpointUrlsForTarget - Function to resolve DWN endpoint URLs (with local discovery)
|
|
269
271
|
* @returns The decrypted `DerivedPrivateJwk`, or `undefined` if no matching record found
|
|
270
272
|
*/
|
|
271
273
|
export async function fetchContextKeyRecord(
|
|
272
|
-
agent:
|
|
274
|
+
agent: EnboxPlatformAgent,
|
|
273
275
|
params: FetchContextKeyParams,
|
|
274
276
|
processRequest: ProcessRequestFn,
|
|
275
277
|
getSigner: (author: string) => Promise<any>,
|
|
276
278
|
sendDwnRpcRequest: (params: { targetDid: string; dwnEndpointUrls: string[]; message: any; data?: Blob }) => Promise<any>,
|
|
279
|
+
getDwnEndpointUrlsForTarget: (targetDid: string) => Promise<string[]>,
|
|
277
280
|
): Promise<DerivedPrivateJwk | undefined> {
|
|
278
281
|
const { ownerDid, requesterDid, sourceProtocol, sourceContextId } = params;
|
|
279
282
|
const protocolUri = KeyDeliveryProtocolDefinition.protocol;
|
|
@@ -323,7 +326,7 @@ export async function fetchContextKeyRecord(
|
|
|
323
326
|
} else {
|
|
324
327
|
// Remote query: participant queries the context owner's DWN
|
|
325
328
|
const signer = await getSigner(requesterDid);
|
|
326
|
-
const dwnEndpointUrls = await
|
|
329
|
+
const dwnEndpointUrls = await getDwnEndpointUrlsForTarget(ownerDid);
|
|
327
330
|
|
|
328
331
|
const recordsQuery = await dwnMessageConstructors[DwnInterface.RecordsQuery].create({
|
|
329
332
|
signer,
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { DidUrlDereferencer } from '@enbox/dids';
|
|
11
10
|
import type { PublicKeyJwk } from '@enbox/crypto';
|
|
12
11
|
import type { TtlCache } from '@enbox/common';
|
|
13
12
|
import type {
|
|
@@ -26,13 +25,15 @@ import type {
|
|
|
26
25
|
|
|
27
26
|
import { KeyDerivationScheme } from '@enbox/dwn-sdk-js';
|
|
28
27
|
|
|
29
|
-
import { getDwnServiceEndpointUrls } from './utils.js';
|
|
30
28
|
import { DwnInterface as DwnInterfaceEnum, dwnMessageConstructors } from './types/dwn.js';
|
|
31
29
|
|
|
32
30
|
// ---------------------------------------------------------------------------
|
|
33
31
|
// Dependency signatures — keep the extracted code free of `this` references.
|
|
34
32
|
// ---------------------------------------------------------------------------
|
|
35
33
|
|
|
34
|
+
/** Callback to resolve DWN endpoint URLs for a target DID (with local discovery). */
|
|
35
|
+
type GetDwnEndpointUrlsFn = (targetDid: string) => Promise<string[]>;
|
|
36
|
+
|
|
36
37
|
/** Callback to obtain a DWN signer for a given DID. */
|
|
37
38
|
type GetSignerFn = (author: string) => Promise<DwnSigner>;
|
|
38
39
|
|
|
@@ -106,7 +107,7 @@ export async function getProtocolDefinition(
|
|
|
106
107
|
*
|
|
107
108
|
* @param targetDid - The remote DWN owner
|
|
108
109
|
* @param protocolUri - The protocol URI to look up
|
|
109
|
-
* @param
|
|
110
|
+
* @param getDwnEndpointUrls - Callback to resolve DWN endpoint URLs (with local discovery)
|
|
110
111
|
* @param sendDwnRpcRequest - Callback to send the RPC query
|
|
111
112
|
* @param cache - The shared protocol definition cache
|
|
112
113
|
* @returns The protocol definition
|
|
@@ -115,7 +116,7 @@ export async function getProtocolDefinition(
|
|
|
115
116
|
export async function fetchRemoteProtocolDefinition(
|
|
116
117
|
targetDid: string,
|
|
117
118
|
protocolUri: string,
|
|
118
|
-
|
|
119
|
+
getDwnEndpointUrls: GetDwnEndpointUrlsFn,
|
|
119
120
|
sendDwnRpcRequest: SendDwnRpcRequestFn,
|
|
120
121
|
cache: TtlCache<string, ProtocolDefinition>,
|
|
121
122
|
): Promise<ProtocolDefinition> {
|
|
@@ -131,7 +132,7 @@ export async function fetchRemoteProtocolDefinition(
|
|
|
131
132
|
|
|
132
133
|
const reply = await sendDwnRpcRequest({
|
|
133
134
|
targetDid,
|
|
134
|
-
dwnEndpointUrls : await
|
|
135
|
+
dwnEndpointUrls : await getDwnEndpointUrls(targetDid),
|
|
135
136
|
message : protocolsQuery.message,
|
|
136
137
|
}) as ProtocolsQueryReply;
|
|
137
138
|
|
|
@@ -158,7 +159,7 @@ export async function fetchRemoteProtocolDefinition(
|
|
|
158
159
|
* @param protocolUri - The protocol URI to search
|
|
159
160
|
* @param rootContextId - The root context ID
|
|
160
161
|
* @param requesterDid - The DID of the requester (used for signing the query)
|
|
161
|
-
* @param
|
|
162
|
+
* @param getDwnEndpointUrls - Callback to resolve DWN endpoint URLs (with local discovery)
|
|
162
163
|
* @param getSigner - Callback to obtain the signer for `requesterDid`
|
|
163
164
|
* @param sendDwnRpcRequest - Callback to send the RPC query
|
|
164
165
|
* @returns The rootKeyId and derivedPublicKey, or `undefined` if no
|
|
@@ -169,7 +170,7 @@ export async function extractDerivedPublicKey(
|
|
|
169
170
|
protocolUri: string,
|
|
170
171
|
rootContextId: string,
|
|
171
172
|
requesterDid: string,
|
|
172
|
-
|
|
173
|
+
getDwnEndpointUrls: GetDwnEndpointUrlsFn,
|
|
173
174
|
getSigner: GetSignerFn,
|
|
174
175
|
sendDwnRpcRequest: SendDwnRpcRequestFn,
|
|
175
176
|
): Promise<{ rootKeyId: string; derivedPublicKey: PublicKeyJwk } | undefined> {
|
|
@@ -184,7 +185,7 @@ export async function extractDerivedPublicKey(
|
|
|
184
185
|
},
|
|
185
186
|
});
|
|
186
187
|
|
|
187
|
-
const dwnEndpointUrls = await
|
|
188
|
+
const dwnEndpointUrls = await getDwnEndpointUrls(targetDid);
|
|
188
189
|
const queryReply = await sendDwnRpcRequest<DwnInterfaceEnum.RecordsQuery>({
|
|
189
190
|
targetDid,
|
|
190
191
|
dwnEndpointUrls,
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
} from '@enbox/dwn-sdk-js';
|
|
9
9
|
|
|
10
10
|
import type { DwnSigner } from './types/dwn.js';
|
|
11
|
-
import type {
|
|
11
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
Encoder,
|
|
@@ -42,7 +42,7 @@ import { DwnInterface, dwnMessageConstructors } from './types/dwn.js';
|
|
|
42
42
|
* @param contextKeyCache - Cache for context key info
|
|
43
43
|
*/
|
|
44
44
|
export async function upgradeExternalRootRecord(
|
|
45
|
-
agent:
|
|
45
|
+
agent: EnboxPlatformAgent,
|
|
46
46
|
tenantDid: string,
|
|
47
47
|
recordsWrite: RecordsWriteMessage,
|
|
48
48
|
dwn: Dwn,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { AgentKeyManager } from './types/key-manager.js';
|
|
2
2
|
import type { BearerDid } from '@enbox/dids';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
4
|
+
import type { EnboxRpc } from '@enbox/dwn-clients';
|
|
5
|
+
import type { LocalDwnStrategy } from './local-dwn.js';
|
|
5
6
|
import type { DidInterface, DidRequest, DidResponse } from './did-api.js';
|
|
6
7
|
import type { DwnInterface, DwnResponse, ProcessDwnRequest, SendDwnRequest } from './types/dwn.js';
|
|
7
8
|
import type { ProcessVcRequest, SendVcRequest, VcResponse } from './types/vc.js';
|
|
@@ -16,15 +17,15 @@ import { AgentSyncApi } from './sync-api.js';
|
|
|
16
17
|
import { DwnDidStore } from './store-did.js';
|
|
17
18
|
import { DwnIdentityStore } from './store-identity.js';
|
|
18
19
|
import { DwnKeyStore } from './store-key.js';
|
|
20
|
+
import { EnboxRpcClient } from '@enbox/dwn-clients';
|
|
19
21
|
import { HdIdentityVault } from './hd-identity-vault.js';
|
|
20
22
|
import { LevelStore } from '@enbox/common';
|
|
21
23
|
import { LocalKeyManager } from './local-key-manager.js';
|
|
22
24
|
import { SyncEngineLevel } from './sync-engine-level.js';
|
|
23
|
-
import { Web5RpcClient } from '@enbox/dwn-clients';
|
|
24
25
|
import { DidDht, DidJwk } from '@enbox/dids';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* Initialization parameters for {@link
|
|
28
|
+
* Initialization parameters for {@link EnboxUserAgent}, including an optional recovery phrase that
|
|
28
29
|
* can be used to derive keys to encrypt the vault and generate a DID.
|
|
29
30
|
*/
|
|
30
31
|
export type AgentInitializeParams = {
|
|
@@ -45,10 +46,10 @@ export type AgentInitializeParams = {
|
|
|
45
46
|
recoveryPhrase?: string;
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
|
-
* Optional dwnEndpoints to register didService endpoints during
|
|
49
|
+
* Optional dwnEndpoints to register didService endpoints during EnboxUserAgent initialization
|
|
49
50
|
*
|
|
50
51
|
* The dwnEndpoints are used to register DWN endpoints against the agent DID created during
|
|
51
|
-
*
|
|
52
|
+
* EnboxUserAgent.initialize() => DidDht.create(). This allows the
|
|
52
53
|
* agent to properly recover connectedDids from DWN. Also, this pattern can be used on the server
|
|
53
54
|
* side in place of the agentDid-->connectedDids pattern.
|
|
54
55
|
*/
|
|
@@ -63,7 +64,7 @@ export type AgentStartParams = {
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
export type AgentParams<TKeyManager extends AgentKeyManager = LocalKeyManager> = {
|
|
66
|
-
/** Optional. The Decentralized Identifier (DID) representing this
|
|
67
|
+
/** Optional. The Decentralized Identifier (DID) representing this Enbox User Agent. */
|
|
67
68
|
agentDid?: BearerDid;
|
|
68
69
|
/** Encrypted vault used for managing the Agent's DID and associated keys. */
|
|
69
70
|
agentVault: HdIdentityVault;
|
|
@@ -81,20 +82,24 @@ export type AgentParams<TKeyManager extends AgentKeyManager = LocalKeyManager> =
|
|
|
81
82
|
keyManager: TKeyManager;
|
|
82
83
|
/** Facilitates fetching, requesting, creating, revoking and validating revocation status of permissions */
|
|
83
84
|
permissionsApi: AgentPermissionsApi;
|
|
84
|
-
/** Remote procedure call (RPC) client used to communicate with other
|
|
85
|
-
rpcClient:
|
|
85
|
+
/** Remote procedure call (RPC) client used to communicate with other Enbox services. */
|
|
86
|
+
rpcClient: EnboxRpc;
|
|
86
87
|
/** Facilitates data synchronization of DWN records between nodes. */
|
|
87
88
|
syncApi: AgentSyncApi;
|
|
88
89
|
};
|
|
89
90
|
|
|
90
|
-
export
|
|
91
|
+
export type CreateUserAgentParams = Partial<AgentParams> & {
|
|
92
|
+
localDwnStrategy?: LocalDwnStrategy;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export class EnboxUserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager> implements EnboxPlatformAgent<TKeyManager> {
|
|
91
96
|
public crypto: AgentCryptoApi;
|
|
92
97
|
public did: AgentDidApi<TKeyManager>;
|
|
93
98
|
public dwn: AgentDwnApi;
|
|
94
99
|
public identity: AgentIdentityApi<TKeyManager>;
|
|
95
100
|
public keyManager: TKeyManager;
|
|
96
101
|
public permissions: AgentPermissionsApi;
|
|
97
|
-
public rpc:
|
|
102
|
+
public rpc: EnboxRpc;
|
|
98
103
|
public sync: AgentSyncApi;
|
|
99
104
|
public vault: HdIdentityVault;
|
|
100
105
|
|
|
@@ -124,7 +129,7 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
124
129
|
get agentDid(): BearerDid {
|
|
125
130
|
if (this._agentDid === undefined) {
|
|
126
131
|
throw new Error(
|
|
127
|
-
'
|
|
132
|
+
'EnboxUserAgent: The "agentDid" property is not set. Ensure the agent is properly ' +
|
|
128
133
|
'initialized and a DID is assigned.'
|
|
129
134
|
);
|
|
130
135
|
}
|
|
@@ -140,9 +145,10 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
140
145
|
*/
|
|
141
146
|
public static async create({
|
|
142
147
|
dataPath = 'DATA/AGENT',
|
|
148
|
+
localDwnStrategy,
|
|
143
149
|
agentDid, agentVault, cryptoApi, didApi, dwnApi, identityApi, keyManager, permissionsApi, rpcClient, syncApi
|
|
144
|
-
}:
|
|
145
|
-
): Promise<
|
|
150
|
+
}: CreateUserAgentParams = {}
|
|
151
|
+
): Promise<EnboxUserAgent> {
|
|
146
152
|
|
|
147
153
|
agentVault ??= new HdIdentityVault({
|
|
148
154
|
keyDerivationWorkFactor : 210_000,
|
|
@@ -158,8 +164,12 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
158
164
|
});
|
|
159
165
|
|
|
160
166
|
dwnApi ??= new AgentDwnApi({
|
|
161
|
-
dwn: await AgentDwnApi.createDwn({ dataPath, didResolver: didApi })
|
|
167
|
+
dwn : await AgentDwnApi.createDwn({ dataPath, didResolver: didApi }),
|
|
168
|
+
localDwnStrategy : localDwnStrategy ?? 'prefer',
|
|
162
169
|
});
|
|
170
|
+
if (localDwnStrategy) {
|
|
171
|
+
dwnApi.setLocalDwnStrategy(localDwnStrategy);
|
|
172
|
+
}
|
|
163
173
|
|
|
164
174
|
identityApi ??= new AgentIdentityApi({ store: new DwnIdentityStore() });
|
|
165
175
|
|
|
@@ -167,12 +177,12 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
167
177
|
|
|
168
178
|
permissionsApi ??= new AgentPermissionsApi();
|
|
169
179
|
|
|
170
|
-
rpcClient ??= new
|
|
180
|
+
rpcClient ??= new EnboxRpcClient();
|
|
171
181
|
|
|
172
182
|
syncApi ??= new AgentSyncApi({ syncEngine: new SyncEngineLevel({ dataPath }) });
|
|
173
183
|
|
|
174
184
|
// Instantiate the Agent using the provided or default components.
|
|
175
|
-
return new
|
|
185
|
+
return new EnboxUserAgent({
|
|
176
186
|
agentDid,
|
|
177
187
|
agentVault,
|
|
178
188
|
cryptoApi,
|
|
@@ -196,7 +206,7 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
196
206
|
*
|
|
197
207
|
* This method is typically called once, the first time the Agent is launched, and is responsible
|
|
198
208
|
* for setting up the agent's operational environment, cryptographic key material, and readiness
|
|
199
|
-
* for processing
|
|
209
|
+
* for processing requests.
|
|
200
210
|
*
|
|
201
211
|
* The password is used to secure the Agent vault, and the recovery phrase is used to derive the
|
|
202
212
|
* cryptographic keys for the vault. If a recovery phrase is not provided, a new recovery phrase
|
|
@@ -250,4 +260,14 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
250
260
|
// Set the Agent's DID.
|
|
251
261
|
this.agentDid = await this.vault.getDid();
|
|
252
262
|
}
|
|
253
|
-
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// Deprecated aliases — migration aid
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
/** @deprecated Use {@link EnboxUserAgent} instead. Will be removed in a future version. */
|
|
270
|
+
export const Web5UserAgent = EnboxUserAgent;
|
|
271
|
+
|
|
272
|
+
/** @deprecated Use {@link EnboxUserAgent} instead. Will be removed in a future version. */
|
|
273
|
+
export type Web5UserAgent = EnboxUserAgent;
|
package/src/identity-api.ts
CHANGED
|
@@ -3,17 +3,16 @@ import type { RequireOnly } from '@enbox/common';
|
|
|
3
3
|
import type { AgentDataStore } from './store-data.js';
|
|
4
4
|
import type { AgentKeyManager } from './types/key-manager.js';
|
|
5
5
|
import type { DidMethodCreateOptions } from './did-api.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
7
7
|
import type { IdentityMetadata, PortableIdentity } from './types/identity.js';
|
|
8
8
|
|
|
9
9
|
import { isPortableDid } from '@enbox/dids';
|
|
10
10
|
|
|
11
11
|
import { BearerIdentity } from './bearer-identity.js';
|
|
12
|
-
import { getDwnServiceEndpointUrls } from './utils.js';
|
|
13
12
|
import { InMemoryIdentityStore } from './store-identity.js';
|
|
14
13
|
|
|
15
14
|
export interface IdentityApiParams<TKeyManager extends AgentKeyManager> {
|
|
16
|
-
agent?:
|
|
15
|
+
agent?: EnboxPlatformAgent<TKeyManager>;
|
|
17
16
|
|
|
18
17
|
store?: AgentDataStore<IdentityMetadata>;
|
|
19
18
|
}
|
|
@@ -37,7 +36,7 @@ export function isPortableIdentity(obj: unknown): obj is PortableIdentity {
|
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
/**
|
|
40
|
-
* This API is used to manage and interact with Identities within the
|
|
39
|
+
* This API is used to manage and interact with Identities within the Enbox Agent framework.
|
|
41
40
|
* An Identity is a DID that is associated with metadata that describes the Identity.
|
|
42
41
|
* Metadata includes A name(label), and whether or not the Identity is connected (delegated to act on the behalf of another DID).
|
|
43
42
|
*
|
|
@@ -48,12 +47,12 @@ export function isPortableIdentity(obj: unknown): obj is PortableIdentity {
|
|
|
48
47
|
*/
|
|
49
48
|
export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyManager> {
|
|
50
49
|
/**
|
|
51
|
-
* Holds the instance of a `
|
|
52
|
-
* the `AgentIdentityApi`. This agent is used to interact with other
|
|
50
|
+
* Holds the instance of a `EnboxPlatformAgent` that represents the current execution context for
|
|
51
|
+
* the `AgentIdentityApi`. This agent is used to interact with other Enbox agent components. It's
|
|
53
52
|
* vital to ensure this instance is set to correctly contextualize operations within the broader
|
|
54
|
-
*
|
|
53
|
+
* Enbox Agent framework.
|
|
55
54
|
*/
|
|
56
|
-
private _agent?:
|
|
55
|
+
private _agent?: EnboxPlatformAgent<TKeyManager>;
|
|
57
56
|
|
|
58
57
|
private _store: AgentDataStore<IdentityMetadata>;
|
|
59
58
|
|
|
@@ -65,12 +64,12 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
/**
|
|
68
|
-
* Retrieves the `
|
|
67
|
+
* Retrieves the `EnboxPlatformAgent` execution context.
|
|
69
68
|
*
|
|
70
|
-
* @returns The `
|
|
69
|
+
* @returns The `EnboxPlatformAgent` instance that represents the current execution context.
|
|
71
70
|
* @throws Will throw an error if the `agent` instance property is undefined.
|
|
72
71
|
*/
|
|
73
|
-
get agent():
|
|
72
|
+
get agent(): EnboxPlatformAgent<TKeyManager> {
|
|
74
73
|
if (this._agent === undefined) {
|
|
75
74
|
throw new Error('AgentIdentityApi: Unable to determine agent execution context.');
|
|
76
75
|
}
|
|
@@ -78,7 +77,7 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
|
|
|
78
77
|
return this._agent;
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
set agent(agent:
|
|
80
|
+
set agent(agent: EnboxPlatformAgent<TKeyManager>) {
|
|
82
81
|
this._agent = agent;
|
|
83
82
|
}
|
|
84
83
|
|
|
@@ -226,7 +225,7 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
|
|
|
226
225
|
* @throws An error if the DID is not found, or no DWN service exists.
|
|
227
226
|
*/
|
|
228
227
|
public getDwnEndpoints({ didUri }: { didUri: string; }): Promise<string[]> {
|
|
229
|
-
return
|
|
228
|
+
return this.agent.dwn.getDwnEndpointUrlsForTarget(didUri);
|
|
230
229
|
}
|
|
231
230
|
|
|
232
231
|
/**
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export * from './bearer-identity.js';
|
|
|
13
13
|
export * from './crypto-api.js';
|
|
14
14
|
export * from './did-api.js';
|
|
15
15
|
export * from './dwn-api.js';
|
|
16
|
+
export * from './dwn-discovery-file.js';
|
|
17
|
+
export * from './dwn-discovery-payload.js';
|
|
16
18
|
export * from './dwn-encryption.js';
|
|
17
19
|
export * from './dwn-key-delivery.js';
|
|
18
20
|
export * from './dwn-record-upgrade.js';
|
|
@@ -20,6 +22,7 @@ export * from './dwn-type-guards.js';
|
|
|
20
22
|
export * from './protocol-utils.js';
|
|
21
23
|
export * from './hd-identity-vault.js';
|
|
22
24
|
export * from './identity-api.js';
|
|
25
|
+
export * from './local-dwn.js';
|
|
23
26
|
export * from './local-key-manager.js';
|
|
24
27
|
export * from './permissions-api.js';
|
|
25
28
|
export * from './store-data.js';
|
|
@@ -32,4 +35,4 @@ export * from './test-harness.js';
|
|
|
32
35
|
export * from './utils.js';
|
|
33
36
|
export * from './connect.js';
|
|
34
37
|
export * from './oidc.js';
|
|
35
|
-
export * from './
|
|
38
|
+
export * from './enbox-user-agent.js';
|
package/src/local-dwn.ts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local DWN discovery — discovers a running `@enbox/dwn-server` instance
|
|
3
|
+
* so the agent can route traffic to it.
|
|
4
|
+
*
|
|
5
|
+
* Discovery channels (tried in order):
|
|
6
|
+
* 1. **In-memory cache** — serves a recent positive or negative result.
|
|
7
|
+
* 2. **Discovery file** (`~/.enbox/dwn.json`) — written by `electrobun-dwn`
|
|
8
|
+
* on startup. Fast filesystem read, no network. Available for CLI and
|
|
9
|
+
* native apps; skipped in browsers.
|
|
10
|
+
* 3. **Port probing** (fallback) — sequential HTTP `GET /info` on well-known
|
|
11
|
+
* localhost ports. Works everywhere but is slower.
|
|
12
|
+
*
|
|
13
|
+
* @see https://github.com/enboxorg/enbox/issues/585
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { EnboxRpc } from '@enbox/dwn-clients';
|
|
18
|
+
|
|
19
|
+
import type { DwnDiscoveryFile } from './dwn-discovery-file.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Well-known ports the local DWN desktop app may bind to.
|
|
23
|
+
*
|
|
24
|
+
* Per the DWN Transport Spec, clients probe ports `55500` through `55509`
|
|
25
|
+
* (inclusive). Port `3000` is included as a development convenience.
|
|
26
|
+
*
|
|
27
|
+
* @see https://identity.foundation/dwn-transport/#port-probing
|
|
28
|
+
*/
|
|
29
|
+
export const localDwnPortCandidates = [3000, 55500, 55501, 55502, 55503, 55504, 55505, 55506, 55507, 55508, 55509] as const;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Hosts probed when discovering a local DWN server.
|
|
33
|
+
*
|
|
34
|
+
* Per the DWN Transport Spec, clients MUST use `127.0.0.1` rather than
|
|
35
|
+
* `localhost` to avoid DNS resolution ambiguity.
|
|
36
|
+
*
|
|
37
|
+
* @see https://identity.foundation/dwn-transport/#port-probing
|
|
38
|
+
*/
|
|
39
|
+
export const localDwnHostCandidates = ['127.0.0.1'] as const;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Controls how the agent discovers and routes to a local DWN server.
|
|
43
|
+
*
|
|
44
|
+
* - `'off'` — (default) skip local discovery entirely.
|
|
45
|
+
* - `'prefer'` — probe localhost first; fall back to DID-document endpoints.
|
|
46
|
+
* - `'only'` — require a local server; throw if none is found.
|
|
47
|
+
*/
|
|
48
|
+
export type LocalDwnStrategy = 'prefer' | 'only' | 'off';
|
|
49
|
+
|
|
50
|
+
/** The `server` field returned by `GET /info` on `@enbox/dwn-server`. */
|
|
51
|
+
export const localDwnServerName = '@enbox/dwn-server';
|
|
52
|
+
|
|
53
|
+
/** Strips a trailing slash from a URL so endpoint comparisons are consistent. */
|
|
54
|
+
export function normalizeBaseUrl(url: string): string {
|
|
55
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Discovers a running local DWN server.
|
|
60
|
+
*
|
|
61
|
+
* Results are cached for {@link _cacheTtlMs} milliseconds (default 10 s) to
|
|
62
|
+
* avoid repeated I/O on hot paths such as sync.
|
|
63
|
+
*
|
|
64
|
+
* @example Discovery with file-based channel
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { DwnDiscoveryFile } from './dwn-discovery-file.js';
|
|
67
|
+
*
|
|
68
|
+
* const discoveryFile = new DwnDiscoveryFile();
|
|
69
|
+
* const discovery = new LocalDwnDiscovery(rpcClient, 10_000, discoveryFile);
|
|
70
|
+
* const endpoint = await discovery.getEndpoint();
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example Browser: inject cached endpoint from `dwn://register` redirect
|
|
74
|
+
* ```ts
|
|
75
|
+
* const discovery = new LocalDwnDiscovery(rpcClient);
|
|
76
|
+
* discovery.setCachedEndpoint('http://127.0.0.1:55557');
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export class LocalDwnDiscovery {
|
|
80
|
+
private _cachedEndpoint?: string;
|
|
81
|
+
private _cacheExpiry = 0;
|
|
82
|
+
|
|
83
|
+
constructor(
|
|
84
|
+
private _rpcClient: EnboxRpc,
|
|
85
|
+
private _cacheTtlMs = 10_000,
|
|
86
|
+
private _discoveryFile?: DwnDiscoveryFile,
|
|
87
|
+
) {}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns the base URL of a local DWN server, or `undefined` if none
|
|
91
|
+
* is discoverable.
|
|
92
|
+
*
|
|
93
|
+
* The discovery order is:
|
|
94
|
+
* 1. In-memory cache (if not expired).
|
|
95
|
+
* 2. `~/.enbox/dwn.json` discovery file (if a {@link DwnDiscoveryFile}
|
|
96
|
+
* was provided). The endpoint from the file is validated via
|
|
97
|
+
* `GET /info` to ensure the server is still running.
|
|
98
|
+
* 3. Sequential port probing on well-known localhost ports (fallback).
|
|
99
|
+
*/
|
|
100
|
+
public async getEndpoint(): Promise<string | undefined> {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
if (now < this._cacheExpiry) {
|
|
103
|
+
return this._cachedEndpoint;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Channel 1: file-based discovery.
|
|
107
|
+
const fileEndpoint = await this._tryDiscoveryFile();
|
|
108
|
+
if (fileEndpoint !== undefined) {
|
|
109
|
+
this._setCacheEntry(fileEndpoint, now);
|
|
110
|
+
return fileEndpoint;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Channel 2: sequential port probing (fallback).
|
|
114
|
+
const probeEndpoint = await this._probePortCandidates();
|
|
115
|
+
// Cache both positive and negative results.
|
|
116
|
+
this._setCacheEntry(probeEndpoint, now);
|
|
117
|
+
return probeEndpoint;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Inject a cached endpoint (e.g. from a `dwn://register` browser redirect
|
|
122
|
+
* or from `localStorage`). The endpoint is validated via `GET /info` before
|
|
123
|
+
* caching.
|
|
124
|
+
*
|
|
125
|
+
* @returns `true` if the endpoint was validated and cached, `false` otherwise.
|
|
126
|
+
*/
|
|
127
|
+
public async setCachedEndpoint(endpoint: string): Promise<boolean> {
|
|
128
|
+
const normalized = normalizeBaseUrl(endpoint);
|
|
129
|
+
const valid = await this._validateEndpoint(normalized);
|
|
130
|
+
if (valid) {
|
|
131
|
+
this._setCacheEntry(normalized, Date.now());
|
|
132
|
+
}
|
|
133
|
+
return valid;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Clear the in-memory cache, forcing the next {@link getEndpoint} call
|
|
138
|
+
* to perform a fresh discovery.
|
|
139
|
+
*/
|
|
140
|
+
public clearCache(): void {
|
|
141
|
+
this._cachedEndpoint = undefined;
|
|
142
|
+
this._cacheExpiry = 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ─── Private discovery channels ────────────────────────────────
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Try the `~/.enbox/dwn.json` discovery file. Returns the endpoint if
|
|
149
|
+
* the file exists, is valid, and the endpoint passes `GET /info`
|
|
150
|
+
* validation. Returns `undefined` otherwise.
|
|
151
|
+
*/
|
|
152
|
+
private async _tryDiscoveryFile(): Promise<string | undefined> {
|
|
153
|
+
if (!this._discoveryFile) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const record = await this._discoveryFile.read();
|
|
159
|
+
if (!record) {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Validate that the server is actually alive and is ours.
|
|
164
|
+
const valid = await this._validateEndpoint(record.endpoint);
|
|
165
|
+
return valid ? record.endpoint : undefined;
|
|
166
|
+
} catch {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Sequential HTTP probe on well-known localhost port candidates.
|
|
173
|
+
* Returns the first endpoint whose `GET /info` response identifies
|
|
174
|
+
* as `@enbox/dwn-server`, or `undefined` if none is found.
|
|
175
|
+
*/
|
|
176
|
+
private async _probePortCandidates(): Promise<string | undefined> {
|
|
177
|
+
for (const port of localDwnPortCandidates) {
|
|
178
|
+
for (const host of localDwnHostCandidates) {
|
|
179
|
+
const endpoint = `http://${host}:${port}`;
|
|
180
|
+
const valid = await this._validateEndpoint(endpoint);
|
|
181
|
+
if (valid) {
|
|
182
|
+
return normalizeBaseUrl(endpoint);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Call `GET /info` on the endpoint and check that
|
|
191
|
+
* `serverInfo.server === '@enbox/dwn-server'`.
|
|
192
|
+
*/
|
|
193
|
+
private async _validateEndpoint(endpoint: string): Promise<boolean> {
|
|
194
|
+
try {
|
|
195
|
+
const serverInfo = await this._rpcClient.getServerInfo(endpoint);
|
|
196
|
+
return serverInfo.server === localDwnServerName;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Update the in-memory cache entry. */
|
|
203
|
+
private _setCacheEntry(endpoint: string | undefined, now: number): void {
|
|
204
|
+
this._cachedEndpoint = endpoint;
|
|
205
|
+
this._cacheExpiry = now + this._cacheTtlMs;
|
|
206
|
+
}
|
|
207
|
+
}
|