@enbox/agent 0.1.5 → 0.1.7

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 (79) hide show
  1. package/dist/browser.mjs +11 -11
  2. package/dist/browser.mjs.map +4 -4
  3. package/dist/esm/anonymous-dwn-api.js +184 -0
  4. package/dist/esm/anonymous-dwn-api.js.map +1 -0
  5. package/dist/esm/dwn-api.js +85 -785
  6. package/dist/esm/dwn-api.js.map +1 -1
  7. package/dist/esm/dwn-encryption.js +342 -0
  8. package/dist/esm/dwn-encryption.js.map +1 -0
  9. package/dist/esm/dwn-key-delivery.js +256 -0
  10. package/dist/esm/dwn-key-delivery.js.map +1 -0
  11. package/dist/esm/dwn-record-upgrade.js +119 -0
  12. package/dist/esm/dwn-record-upgrade.js.map +1 -0
  13. package/dist/esm/dwn-type-guards.js +23 -0
  14. package/dist/esm/dwn-type-guards.js.map +1 -0
  15. package/dist/esm/index.js +6 -0
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/permissions-api.js +43 -2
  18. package/dist/esm/permissions-api.js.map +1 -1
  19. package/dist/esm/protocol-utils.js +158 -0
  20. package/dist/esm/protocol-utils.js.map +1 -0
  21. package/dist/esm/store-data-protocols.js +1 -1
  22. package/dist/esm/store-data-protocols.js.map +1 -1
  23. package/dist/esm/store-data.js +3 -0
  24. package/dist/esm/store-data.js.map +1 -1
  25. package/dist/esm/sync-engine-level.js +23 -354
  26. package/dist/esm/sync-engine-level.js.map +1 -1
  27. package/dist/esm/sync-messages.js +237 -0
  28. package/dist/esm/sync-messages.js.map +1 -0
  29. package/dist/esm/sync-topological-sort.js +143 -0
  30. package/dist/esm/sync-topological-sort.js.map +1 -0
  31. package/dist/esm/test-harness.js +20 -0
  32. package/dist/esm/test-harness.js.map +1 -1
  33. package/dist/types/anonymous-dwn-api.d.ts +140 -0
  34. package/dist/types/anonymous-dwn-api.d.ts.map +1 -0
  35. package/dist/types/dwn-api.d.ts +36 -184
  36. package/dist/types/dwn-api.d.ts.map +1 -1
  37. package/dist/types/dwn-encryption.d.ts +144 -0
  38. package/dist/types/dwn-encryption.d.ts.map +1 -0
  39. package/dist/types/dwn-key-delivery.d.ts +112 -0
  40. package/dist/types/dwn-key-delivery.d.ts.map +1 -0
  41. package/dist/types/dwn-record-upgrade.d.ts +33 -0
  42. package/dist/types/dwn-record-upgrade.d.ts.map +1 -0
  43. package/dist/types/dwn-type-guards.d.ts +9 -0
  44. package/dist/types/dwn-type-guards.d.ts.map +1 -0
  45. package/dist/types/index.d.ts +6 -0
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/types/permissions-api.d.ts +6 -1
  48. package/dist/types/permissions-api.d.ts.map +1 -1
  49. package/dist/types/protocol-utils.d.ts +70 -0
  50. package/dist/types/protocol-utils.d.ts.map +1 -0
  51. package/dist/types/store-data.d.ts +4 -0
  52. package/dist/types/store-data.d.ts.map +1 -1
  53. package/dist/types/sync-engine-level.d.ts +5 -42
  54. package/dist/types/sync-engine-level.d.ts.map +1 -1
  55. package/dist/types/sync-messages.d.ts +76 -0
  56. package/dist/types/sync-messages.d.ts.map +1 -0
  57. package/dist/types/sync-topological-sort.d.ts +15 -0
  58. package/dist/types/sync-topological-sort.d.ts.map +1 -0
  59. package/dist/types/test-harness.d.ts +10 -0
  60. package/dist/types/test-harness.d.ts.map +1 -1
  61. package/dist/types/types/permissions.d.ts +2 -0
  62. package/dist/types/types/permissions.d.ts.map +1 -1
  63. package/package.json +5 -5
  64. package/src/anonymous-dwn-api.ts +263 -0
  65. package/src/dwn-api.ts +158 -1024
  66. package/src/dwn-encryption.ts +481 -0
  67. package/src/dwn-key-delivery.ts +370 -0
  68. package/src/dwn-record-upgrade.ts +166 -0
  69. package/src/dwn-type-guards.ts +43 -0
  70. package/src/index.ts +6 -0
  71. package/src/permissions-api.ts +54 -2
  72. package/src/protocol-utils.ts +185 -0
  73. package/src/store-data-protocols.ts +1 -1
  74. package/src/store-data.ts +5 -2
  75. package/src/sync-engine-level.ts +25 -414
  76. package/src/sync-messages.ts +279 -0
  77. package/src/sync-topological-sort.ts +167 -0
  78. package/src/test-harness.ts +19 -0
  79. package/src/types/permissions.ts +2 -0
@@ -0,0 +1,263 @@
1
+ import type { DidUrlDereferencer } from '@enbox/dids';
2
+
3
+ import type {
4
+ DateSort,
5
+ Pagination,
6
+ ProtocolsQueryFilter,
7
+ ProtocolsQueryReply,
8
+ RecordsCountMessage,
9
+ RecordsCountReply,
10
+ RecordsFilter,
11
+ RecordsQueryReply,
12
+ RecordsReadReply,
13
+ RecordsSubscribeReply,
14
+ RecordSubscriptionHandler,
15
+ } from '@enbox/dwn-sdk-js';
16
+ import type { DwnRpcRequest, Web5Rpc } from '@enbox/dwn-clients';
17
+
18
+ import { ProtocolsQuery, RecordsCount, RecordsQuery, RecordsRead, RecordsSubscribe } from '@enbox/dwn-sdk-js';
19
+
20
+ import { getDwnServiceEndpointUrls } from './utils.js';
21
+
22
+ /**
23
+ * Parameters for constructing an {@link AnonymousDwnApi}.
24
+ */
25
+ export type AnonymousDwnApiParams = {
26
+ /** A DID URL dereferencer for resolving target DID service endpoints. */
27
+ didResolver: DidUrlDereferencer;
28
+ /** An RPC client for sending messages to remote DWNs. */
29
+ rpcClient: Web5Rpc;
30
+ };
31
+
32
+ /**
33
+ * Parameters for an anonymous records query.
34
+ * Mirrors the DWN SDK's `RecordsQueryOptions` without `signer` or delegation fields.
35
+ */
36
+ export type AnonymousRecordsQueryParams = {
37
+ filter: RecordsFilter;
38
+ dateSort?: DateSort;
39
+ pagination?: Pagination;
40
+ messageTimestamp?: string;
41
+ };
42
+
43
+ /**
44
+ * Parameters for an anonymous records read.
45
+ */
46
+ export type AnonymousRecordsReadParams = {
47
+ filter: RecordsFilter;
48
+ messageTimestamp?: string;
49
+ };
50
+
51
+ /**
52
+ * Parameters for an anonymous records subscribe.
53
+ */
54
+ export type AnonymousRecordsSubscribeParams = {
55
+ filter: RecordsFilter;
56
+ dateSort?: DateSort;
57
+ pagination?: Pagination;
58
+ messageTimestamp?: string;
59
+ };
60
+
61
+ /**
62
+ * Parameters for an anonymous records count.
63
+ */
64
+ export type AnonymousRecordsCountParams = {
65
+ filter: RecordsFilter;
66
+ messageTimestamp?: string;
67
+ };
68
+
69
+ /**
70
+ * Parameters for an anonymous protocols query.
71
+ */
72
+ export type AnonymousProtocolsQueryParams = {
73
+ filter?: ProtocolsQueryFilter;
74
+ messageTimestamp?: string;
75
+ };
76
+
77
+ /**
78
+ * A lightweight DWN API that creates **unsigned** (anonymous) DWN messages and
79
+ * sends them to remote DWNs via RPC.
80
+ *
81
+ * This class does not require a vault, agent DID, signing keys, or any identity
82
+ * infrastructure. It leverages the DWN SDK's native support for optional
83
+ * `signer` on read-path operations (RecordsQuery, RecordsRead, RecordsSubscribe,
84
+ * RecordsCount, ProtocolsQuery).
85
+ *
86
+ * Anonymous queries return only published records. Anonymous reads succeed for
87
+ * published records and for protocol records with `{ who: 'anyone', can: ['read'] }`.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * const resolver = new UniversalResolver({ didResolvers: [DidDht, DidJwk] });
92
+ * const rpcClient = new Web5RpcClient();
93
+ * const anonymousDwn = new AnonymousDwnApi({ didResolver: resolver, rpcClient });
94
+ *
95
+ * const reply = await anonymousDwn.recordsQuery('did:dht:alice...', {
96
+ * filter: { protocol: 'https://social.example/posts', protocolPath: 'post' },
97
+ * });
98
+ * ```
99
+ */
100
+ export class AnonymousDwnApi {
101
+ private _didResolver: DidUrlDereferencer;
102
+ private _rpcClient: Web5Rpc;
103
+
104
+ constructor({ didResolver, rpcClient }: AnonymousDwnApiParams) {
105
+ this._didResolver = didResolver;
106
+ this._rpcClient = rpcClient;
107
+ }
108
+
109
+ /**
110
+ * Send an anonymous (unsigned) `RecordsQuery` to a remote DWN.
111
+ *
112
+ * Only published records are returned by the remote DWN.
113
+ *
114
+ * @param target - The DID whose DWN will be queried.
115
+ * @param params - Query parameters (filter, sort, pagination).
116
+ * @returns The raw `RecordsQueryReply` from the remote DWN.
117
+ */
118
+ public async recordsQuery(target: string, params: AnonymousRecordsQueryParams): Promise<RecordsQueryReply> {
119
+ const recordsQuery = await RecordsQuery.create({
120
+ filter : params.filter,
121
+ dateSort : params.dateSort,
122
+ pagination : params.pagination,
123
+ messageTimestamp : params.messageTimestamp,
124
+ // No signer — creates an unsigned message.
125
+ });
126
+
127
+ return await this.sendRequest<RecordsQueryReply>(target, recordsQuery.message);
128
+ }
129
+
130
+ /**
131
+ * Send an anonymous (unsigned) `RecordsRead` to a remote DWN.
132
+ *
133
+ * Succeeds for published records and for protocol records with
134
+ * `{ who: 'anyone', can: ['read'] }` rules.
135
+ *
136
+ * @param target - The DID whose DWN will be read from.
137
+ * @param params - Read parameters (filter).
138
+ * @returns The raw `RecordsReadReply` from the remote DWN.
139
+ */
140
+ public async recordsRead(target: string, params: AnonymousRecordsReadParams): Promise<RecordsReadReply> {
141
+ const recordsRead = await RecordsRead.create({
142
+ filter : params.filter,
143
+ messageTimestamp : params.messageTimestamp,
144
+ // No signer — creates an unsigned message.
145
+ });
146
+
147
+ return await this.sendRequest<RecordsReadReply>(target, recordsRead.message);
148
+ }
149
+
150
+ /**
151
+ * Send an anonymous (unsigned) `RecordsSubscribe` to a remote DWN.
152
+ *
153
+ * Only published record events are received.
154
+ *
155
+ * @param target - The DID whose DWN to subscribe to.
156
+ * @param params - Subscribe parameters (filter).
157
+ * @param handler - Callback for incoming record events.
158
+ * @returns The raw `RecordsSubscribeReply` from the remote DWN.
159
+ */
160
+ public async recordsSubscribe(
161
+ target: string,
162
+ params: AnonymousRecordsSubscribeParams,
163
+ handler: RecordSubscriptionHandler,
164
+ ): Promise<RecordsSubscribeReply> {
165
+ const recordsSubscribe = await RecordsSubscribe.create({
166
+ filter : params.filter,
167
+ dateSort : params.dateSort,
168
+ pagination : params.pagination,
169
+ messageTimestamp : params.messageTimestamp,
170
+ // No signer — creates an unsigned message.
171
+ });
172
+
173
+ return await this.sendRequest<RecordsSubscribeReply>(target, recordsSubscribe.message, undefined, handler);
174
+ }
175
+
176
+ /**
177
+ * Send an anonymous (unsigned) `RecordsCount` to a remote DWN.
178
+ *
179
+ * Only published records are counted.
180
+ *
181
+ * @param target - The DID whose DWN to count records in.
182
+ * @param params - Count parameters (filter).
183
+ * @returns The raw `RecordsCountReply` from the remote DWN.
184
+ */
185
+ public async recordsCount(target: string, params: AnonymousRecordsCountParams): Promise<RecordsCountReply> {
186
+ const recordsCount = await RecordsCount.create({
187
+ filter : params.filter,
188
+ messageTimestamp : params.messageTimestamp,
189
+ // No signer — creates an unsigned message.
190
+ });
191
+
192
+ return await this.sendRequest<RecordsCountReply>(target, recordsCount.message as RecordsCountMessage);
193
+ }
194
+
195
+ /**
196
+ * Send an anonymous (unsigned) `ProtocolsQuery` to a remote DWN.
197
+ *
198
+ * Only published protocol definitions are returned.
199
+ *
200
+ * @param target - The DID whose DWN to query protocols from.
201
+ * @param params - Optional query parameters (protocol filter).
202
+ * @returns The raw `ProtocolsQueryReply` from the remote DWN.
203
+ */
204
+ public async protocolsQuery(target: string, params?: AnonymousProtocolsQueryParams): Promise<ProtocolsQueryReply> {
205
+ const protocolsQuery = await ProtocolsQuery.create({
206
+ filter : params?.filter,
207
+ messageTimestamp : params?.messageTimestamp,
208
+ // No signer — creates an unsigned message.
209
+ });
210
+
211
+ return await this.sendRequest<ProtocolsQueryReply>(target, protocolsQuery.message);
212
+ }
213
+
214
+ /**
215
+ * Resolve the target DID's DWN service endpoints and send an unsigned
216
+ * message to the first one that responds.
217
+ *
218
+ * Follows the same retry-over-endpoints pattern as `AgentDwnApi.sendDwnRpcRequest()`.
219
+ */
220
+ private async sendRequest<TReply>(
221
+ target: string,
222
+ message: unknown,
223
+ data?: Blob,
224
+ subscriptionHandler?: RecordSubscriptionHandler,
225
+ ): Promise<TReply> {
226
+ const dwnEndpointUrls = await getDwnServiceEndpointUrls(target, this._didResolver);
227
+ const errorMessages: { url: string; message: string }[] = [];
228
+
229
+ for (let dwnUrl of dwnEndpointUrls) {
230
+ try {
231
+ // For subscriptions, upgrade to WebSocket transport if available.
232
+ if (subscriptionHandler !== undefined) {
233
+ const serverInfo = await this._rpcClient.getServerInfo(dwnUrl);
234
+ if (!serverInfo.webSocketSupport) {
235
+ errorMessages.push({ url: dwnUrl, message: 'WebSocket support is not enabled on the server.' });
236
+ continue;
237
+ }
238
+
239
+ const parsedUrl = new URL(dwnUrl);
240
+ parsedUrl.protocol = parsedUrl.protocol === 'http:' ? 'ws:' : 'wss:';
241
+ dwnUrl = parsedUrl.toString();
242
+ }
243
+
244
+ const reply = await this._rpcClient.sendDwnRequest({
245
+ dwnUrl,
246
+ targetDid : target,
247
+ message,
248
+ data,
249
+ subscriptionHandler : subscriptionHandler,
250
+ } as DwnRpcRequest);
251
+
252
+ return reply as TReply;
253
+ } catch (error: unknown) {
254
+ errorMessages.push({
255
+ url : dwnUrl,
256
+ message : (error instanceof Error) ? error.message : 'Unknown error',
257
+ });
258
+ }
259
+ }
260
+
261
+ throw new Error(`AnonymousDwnApi: Failed to send request to '${target}': ${JSON.stringify(errorMessages)}`);
262
+ }
263
+ }