@enbox/api 0.1.0 → 0.2.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/README.md +140 -159
- package/dist/browser.mjs +23 -13
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/advanced.js +11 -0
- package/dist/esm/advanced.js.map +1 -0
- package/dist/esm/define-protocol.js +3 -3
- package/dist/esm/dwn-api.js +84 -130
- package/dist/esm/dwn-api.js.map +1 -1
- package/dist/esm/dwn-reader-api.js +128 -0
- package/dist/esm/dwn-reader-api.js.map +1 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/live-query.js +154 -0
- package/dist/esm/live-query.js.map +1 -0
- package/dist/esm/read-only-record.js +255 -0
- package/dist/esm/read-only-record.js.map +1 -0
- package/dist/esm/record.js +46 -57
- package/dist/esm/record.js.map +1 -1
- package/dist/esm/typed-web5.js +242 -0
- package/dist/esm/typed-web5.js.map +1 -0
- package/dist/esm/web5.js +71 -3
- package/dist/esm/web5.js.map +1 -1
- package/dist/types/advanced.d.ts +12 -0
- package/dist/types/advanced.d.ts.map +1 -0
- package/dist/types/define-protocol.d.ts +3 -3
- package/dist/types/dwn-api.d.ts +20 -104
- package/dist/types/dwn-api.d.ts.map +1 -1
- package/dist/types/dwn-reader-api.d.ts +138 -0
- package/dist/types/dwn-reader-api.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/live-query.d.ts +148 -0
- package/dist/types/live-query.d.ts.map +1 -0
- package/dist/types/protocol-types.d.ts +2 -2
- package/dist/types/read-only-record.d.ts +133 -0
- package/dist/types/read-only-record.d.ts.map +1 -0
- package/dist/types/record.d.ts +37 -17
- package/dist/types/record.d.ts.map +1 -1
- package/dist/types/{typed-dwn-api.d.ts → typed-web5.d.ts} +75 -76
- package/dist/types/typed-web5.d.ts.map +1 -0
- package/dist/types/web5.d.ts +79 -3
- package/dist/types/web5.d.ts.map +1 -1
- package/package.json +10 -6
- package/src/advanced.ts +29 -0
- package/src/define-protocol.ts +3 -3
- package/src/dwn-api.ts +141 -266
- package/src/dwn-reader-api.ts +255 -0
- package/src/index.ts +4 -2
- package/src/live-query.ts +261 -0
- package/src/protocol-types.ts +2 -2
- package/src/read-only-record.ts +328 -0
- package/src/record.ts +116 -86
- package/src/typed-web5.ts +445 -0
- package/src/web5.ts +104 -5
- package/dist/esm/subscription-util.js +0 -35
- package/dist/esm/subscription-util.js.map +0 -1
- package/dist/esm/typed-dwn-api.js +0 -181
- package/dist/esm/typed-dwn-api.js.map +0 -1
- package/dist/types/subscription-util.d.ts +0 -19
- package/dist/types/subscription-util.d.ts.map +0 -1
- package/dist/types/typed-dwn-api.d.ts.map +0 -1
- package/src/subscription-util.ts +0 -44
- package/src/typed-dwn-api.ts +0 -370
package/src/dwn-api.ts
CHANGED
|
@@ -8,9 +8,7 @@ import type {
|
|
|
8
8
|
CreateGrantParams,
|
|
9
9
|
CreateRequestParams,
|
|
10
10
|
DwnMessage,
|
|
11
|
-
DwnMessageParams
|
|
12
|
-
,
|
|
13
|
-
DwnMessageSubscription,
|
|
11
|
+
DwnMessageParams,
|
|
14
12
|
DwnPaginationCursor,
|
|
15
13
|
DwnResponse,
|
|
16
14
|
DwnResponseStatus,
|
|
@@ -23,20 +21,14 @@ import {
|
|
|
23
21
|
AgentPermissionsApi,
|
|
24
22
|
} from '@enbox/agent';
|
|
25
23
|
|
|
26
|
-
import { isEmptyObject } from '@enbox/common';
|
|
27
24
|
import { DwnInterface, getRecordAuthor } from '@enbox/agent';
|
|
28
25
|
|
|
29
|
-
import type { ProtocolDefinition } from '@enbox/dwn-sdk-js';
|
|
30
|
-
|
|
31
|
-
import type { SchemaMap, TypedProtocol } from './protocol-types.js';
|
|
32
|
-
|
|
33
26
|
import { dataToBlob } from './utils.js';
|
|
27
|
+
import { LiveQuery } from './live-query.js';
|
|
34
28
|
import { PermissionGrant } from './permission-grant.js';
|
|
35
29
|
import { PermissionRequest } from './permission-request.js';
|
|
36
30
|
import { Protocol } from './protocol.js';
|
|
37
31
|
import { Record } from './record.js';
|
|
38
|
-
import { SubscriptionUtil } from './subscription-util.js';
|
|
39
|
-
import { TypedDwnApi } from './typed-dwn-api.js';
|
|
40
32
|
|
|
41
33
|
/**
|
|
42
34
|
* Represents the request payload for fetching permission requests from a Decentralized Web Node (DWN).
|
|
@@ -66,9 +58,7 @@ export type FetchGrantsRequest = Omit<FetchPermissionsParams, 'author' | 'target
|
|
|
66
58
|
*
|
|
67
59
|
* This request type is used to specify the configuration options for the protocol.
|
|
68
60
|
*/
|
|
69
|
-
export type ProtocolsConfigureRequest = {
|
|
70
|
-
/** Configuration options for the protocol. */
|
|
71
|
-
message: Omit<DwnMessageParams[DwnInterface.ProtocolsConfigure], 'signer'>;
|
|
61
|
+
export type ProtocolsConfigureRequest = Omit<DwnMessageParams[DwnInterface.ProtocolsConfigure], 'signer'> & {
|
|
72
62
|
/** When true, derives and injects $encryption public keys into the protocol definition. */
|
|
73
63
|
encryption?: boolean;
|
|
74
64
|
};
|
|
@@ -94,12 +84,9 @@ export type ProtocolsConfigureResponse = DwnResponseStatus & {
|
|
|
94
84
|
* target the local DWN. If the `from` property is provided, the query will target the specified
|
|
95
85
|
* remote DWN.
|
|
96
86
|
*/
|
|
97
|
-
export type ProtocolsQueryRequest = {
|
|
87
|
+
export type ProtocolsQueryRequest = Omit<DwnMessageParams[DwnInterface.ProtocolsQuery], 'signer'> & {
|
|
98
88
|
/** Optional DID specifying the remote target DWN tenant to be queried. */
|
|
99
89
|
from?: string;
|
|
100
|
-
|
|
101
|
-
/** Query filters and options that influence the results returned. */
|
|
102
|
-
message: Omit<DwnMessageParams[DwnInterface.ProtocolsQuery], 'signer'>
|
|
103
90
|
};
|
|
104
91
|
|
|
105
92
|
/**
|
|
@@ -111,40 +98,6 @@ export type ProtocolsQueryResponse = DwnResponseStatus & {
|
|
|
111
98
|
protocols: Protocol[];
|
|
112
99
|
};
|
|
113
100
|
|
|
114
|
-
/**
|
|
115
|
-
* Type alias for {@link RecordsWriteRequest}
|
|
116
|
-
*/
|
|
117
|
-
export type RecordsCreateRequest = RecordsWriteRequest;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Type alias for {@link RecordsWriteResponse}
|
|
121
|
-
*/
|
|
122
|
-
export type RecordsCreateResponse = RecordsWriteResponse;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Represents a request to create a new record based on an existing one.
|
|
126
|
-
*
|
|
127
|
-
* This request type allows specifying the new data for the record, along with any additional
|
|
128
|
-
* message parameters required for the write operation.
|
|
129
|
-
*/
|
|
130
|
-
export type RecordsCreateFromRequest = {
|
|
131
|
-
/** The DID of the entity authoring the record. */
|
|
132
|
-
author: string;
|
|
133
|
-
/** The new data for the record. */
|
|
134
|
-
data: unknown;
|
|
135
|
-
/** Optional additional parameters for the record write operation */
|
|
136
|
-
message?: Omit<DwnMessageParams[DwnInterface.RecordsWrite], 'signer'>;
|
|
137
|
-
/** The existing record instance that is being used as a basis for the new record. */
|
|
138
|
-
record: Record;
|
|
139
|
-
/**
|
|
140
|
-
* Controls whether the new record should be auto-encrypted.
|
|
141
|
-
*
|
|
142
|
-
* If omitted, auto-detected from the source record: if the source record was
|
|
143
|
-
* encrypted, the new record is automatically encrypted with a fresh DEK.
|
|
144
|
-
*/
|
|
145
|
-
encryption?: boolean;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
101
|
/**
|
|
149
102
|
* Defines a request to delete a record from the Decentralized Web Node (DWN).
|
|
150
103
|
*
|
|
@@ -152,15 +105,12 @@ export type RecordsCreateFromRequest = {
|
|
|
152
105
|
* message parameters for the delete operation. If the `from` property is not provided, the record
|
|
153
106
|
* will be deleted from the local DWN.
|
|
154
107
|
*/
|
|
155
|
-
export type RecordsDeleteRequest = {
|
|
108
|
+
export type RecordsDeleteRequest = Omit<DwnMessageParams[DwnInterface.RecordsDelete], 'signer'> & {
|
|
156
109
|
/** Optional DID specifying the remote target DWN tenant the record will be deleted from. */
|
|
157
110
|
from?: string;
|
|
158
111
|
|
|
159
|
-
/**
|
|
112
|
+
/** Protocol URI for permission grant resolution. */
|
|
160
113
|
protocol?: string;
|
|
161
|
-
|
|
162
|
-
/** The parameters for the delete operation. */
|
|
163
|
-
message: Omit<DwnMessageParams[DwnInterface.RecordsDelete], 'signer'>;
|
|
164
114
|
};
|
|
165
115
|
|
|
166
116
|
/**
|
|
@@ -170,16 +120,10 @@ export type RecordsDeleteRequest = {
|
|
|
170
120
|
* parameters, and optionally the target DWN to query from. If the `from` property is not provided,
|
|
171
121
|
* the query will target the local DWN.
|
|
172
122
|
*/
|
|
173
|
-
export type RecordsQueryRequest = {
|
|
123
|
+
export type RecordsQueryRequest = Omit<DwnMessageParams[DwnInterface.RecordsQuery], 'signer'> & {
|
|
174
124
|
/** Optional DID specifying the remote target DWN tenant to query from and return results. */
|
|
175
125
|
from?: string;
|
|
176
126
|
|
|
177
|
-
/** Records must be scoped to a specific protocol */
|
|
178
|
-
protocol?: string;
|
|
179
|
-
|
|
180
|
-
/** The parameters for the query operation, detailing the criteria for selecting records. */
|
|
181
|
-
message: Omit<DwnMessageParams[DwnInterface.RecordsQuery], 'signer'>;
|
|
182
|
-
|
|
183
127
|
/** When true, automatically decrypts encrypted records in the query results. */
|
|
184
128
|
encryption?: boolean;
|
|
185
129
|
};
|
|
@@ -190,7 +134,7 @@ export type RecordsQueryRequest = {
|
|
|
190
134
|
*/
|
|
191
135
|
export type RecordsQueryResponse = DwnResponseStatus & {
|
|
192
136
|
/** Array of records matching the query. */
|
|
193
|
-
records
|
|
137
|
+
records: Record[];
|
|
194
138
|
|
|
195
139
|
/** If there are additional results, the messageCid of the last record will be returned as a pagination cursor. */
|
|
196
140
|
cursor?: DwnPaginationCursor;
|
|
@@ -203,16 +147,13 @@ export type RecordsQueryResponse = DwnResponseStatus & {
|
|
|
203
147
|
* additional parameters for the read operation. It's useful for fetching the details of a single
|
|
204
148
|
* record by its identifier or other criteria.
|
|
205
149
|
*/
|
|
206
|
-
export type RecordsReadRequest = {
|
|
150
|
+
export type RecordsReadRequest = Omit<DwnMessageParams[DwnInterface.RecordsRead], 'signer'> & {
|
|
207
151
|
/** Optional DID specifying the remote target DWN tenant the record will be read from. */
|
|
208
152
|
from?: string;
|
|
209
153
|
|
|
210
|
-
/**
|
|
154
|
+
/** Protocol URI for permission grant resolution. */
|
|
211
155
|
protocol?: string;
|
|
212
156
|
|
|
213
|
-
/** The parameters for the read operation, detailing the criteria for selecting the record. */
|
|
214
|
-
message: Omit<DwnMessageParams[DwnInterface.RecordsRead], 'signer'>;
|
|
215
|
-
|
|
216
157
|
/** When true, automatically decrypts the encrypted record data. */
|
|
217
158
|
encryption?: boolean;
|
|
218
159
|
};
|
|
@@ -226,39 +167,22 @@ export type RecordsReadResponse = DwnResponseStatus & {
|
|
|
226
167
|
record: Record;
|
|
227
168
|
};
|
|
228
169
|
|
|
229
|
-
/** Subscription handler for Records */
|
|
230
|
-
export type RecordsSubscriptionHandler = (record: Record) => void;
|
|
231
|
-
|
|
232
170
|
/**
|
|
233
171
|
* Represents a request to subscribe to records from a Decentralized Web Node (DWN).
|
|
234
172
|
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
173
|
+
* Returns a {@link LiveQuery} that atomically provides an initial snapshot of
|
|
174
|
+
* matching records alongside a real-time stream of deduplicated, semantically-
|
|
175
|
+
* typed change events (`create`, `update`, `delete`).
|
|
237
176
|
*/
|
|
238
|
-
export type RecordsSubscribeRequest = {
|
|
177
|
+
export type RecordsSubscribeRequest = Omit<DwnMessageParams[DwnInterface.RecordsSubscribe], 'signer'> & {
|
|
239
178
|
/** Optional DID specifying the remote target DWN tenant to subscribe from. */
|
|
240
179
|
from?: string;
|
|
241
|
-
|
|
242
|
-
/** Records must be scoped to a specific protocol */
|
|
243
|
-
protocol?: string;
|
|
244
|
-
|
|
245
|
-
/** The parameters for the subscription operation, detailing the criteria for the subscription filter */
|
|
246
|
-
message: Omit<DwnMessageParams[DwnInterface.RecordsSubscribe], 'signer'>;
|
|
247
|
-
|
|
248
|
-
/** The handler to process the subscription events */
|
|
249
|
-
subscriptionHandler: RecordsSubscriptionHandler;
|
|
250
|
-
|
|
251
|
-
/** When true, indicates encryption is active (decryption happens on subsequent reads). */
|
|
252
|
-
encryption?: boolean;
|
|
253
180
|
};
|
|
254
181
|
|
|
255
|
-
/** Encapsulates the response from a DWN
|
|
182
|
+
/** Encapsulates the response from a DWN RecordsSubscribeRequest. */
|
|
256
183
|
export type RecordsSubscribeResponse = DwnResponseStatus & {
|
|
257
|
-
/**
|
|
258
|
-
|
|
259
|
-
*
|
|
260
|
-
* */
|
|
261
|
-
subscription?: DwnMessageSubscription;
|
|
184
|
+
/** The live query instance, or `undefined` if the request failed. */
|
|
185
|
+
liveQuery?: LiveQuery;
|
|
262
186
|
};
|
|
263
187
|
|
|
264
188
|
/**
|
|
@@ -267,18 +191,11 @@ export type RecordsSubscribeResponse = DwnResponseStatus & {
|
|
|
267
191
|
* This request type allows specifying the data for the new or updated record, along with any
|
|
268
192
|
* additional message parameters required for the write operation, and an optional flag to indicate
|
|
269
193
|
* whether the record should be immediately stored.
|
|
270
|
-
*
|
|
271
|
-
* @param data -
|
|
272
|
-
* @param message - , excluding the signer.
|
|
273
|
-
* @param store -
|
|
274
194
|
*/
|
|
275
|
-
export type RecordsWriteRequest = {
|
|
195
|
+
export type RecordsWriteRequest = Omit<Partial<DwnMessageParams[DwnInterface.RecordsWrite]>, 'signer' | 'data'> & {
|
|
276
196
|
/** The data payload for the record, which can be of any type. */
|
|
277
197
|
data: unknown;
|
|
278
198
|
|
|
279
|
-
/** Optional additional parameters for the record write operation. */
|
|
280
|
-
message?: Omit<Partial<DwnMessageParams[DwnInterface.RecordsWrite]>, 'signer'>;
|
|
281
|
-
|
|
282
199
|
/**
|
|
283
200
|
* Optional flag indicating whether the record should be immediately stored. If true, the record
|
|
284
201
|
* is persisted in the DWN as part of the write operation. If false, the record is created,
|
|
@@ -307,7 +224,7 @@ export type RecordsWriteResponse = DwnResponseStatus & {
|
|
|
307
224
|
* The `Record` instance representing the record that was successfully written to the
|
|
308
225
|
* DWN as a result of the write operation.
|
|
309
226
|
*/
|
|
310
|
-
record
|
|
227
|
+
record: Record;
|
|
311
228
|
};
|
|
312
229
|
|
|
313
230
|
/**
|
|
@@ -336,30 +253,6 @@ export class DwnApi {
|
|
|
336
253
|
this.permissionsApi = new AgentPermissionsApi({ agent: this.agent });
|
|
337
254
|
}
|
|
338
255
|
|
|
339
|
-
/**
|
|
340
|
-
* Returns a {@link TypedDwnApi} scoped to the given typed protocol.
|
|
341
|
-
*
|
|
342
|
-
* The returned API provides path autocompletion, typed data payloads,
|
|
343
|
-
* and automatically injects the protocol URI and protocolPath into every
|
|
344
|
-
* DWN operation.
|
|
345
|
-
*
|
|
346
|
-
* @param protocol - A typed protocol created via `defineProtocol()`.
|
|
347
|
-
* @returns A `TypedDwnApi` instance bound to the given protocol.
|
|
348
|
-
*
|
|
349
|
-
* @example
|
|
350
|
-
* ```ts
|
|
351
|
-
* const social = dwn.using(SocialGraphProtocol);
|
|
352
|
-
* const { record } = await social.write('friend', {
|
|
353
|
-
* data: { did: 'did:example:alice' },
|
|
354
|
-
* });
|
|
355
|
-
* ```
|
|
356
|
-
*/
|
|
357
|
-
public using<D extends ProtocolDefinition, M extends SchemaMap>(
|
|
358
|
-
protocol: TypedProtocol<D, M>,
|
|
359
|
-
): TypedDwnApi<D, M> {
|
|
360
|
-
return new TypedDwnApi<D, M>(this, protocol);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
256
|
/**
|
|
364
257
|
* API to interact with Grants
|
|
365
258
|
*
|
|
@@ -485,20 +378,21 @@ export class DwnApi {
|
|
|
485
378
|
* Configure method, used to setup a new protocol (or update) with the passed definitions
|
|
486
379
|
*/
|
|
487
380
|
configure: async (request: ProtocolsConfigureRequest): Promise<ProtocolsConfigureResponse> => {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
381
|
+
const { encryption, ...messageParams } = request;
|
|
382
|
+
|
|
383
|
+
const agentRequest: ProcessDwnRequest<DwnInterface.ProtocolsConfigure> = {
|
|
384
|
+
author : this.connectedDid,
|
|
385
|
+
messageParams,
|
|
386
|
+
messageType : DwnInterface.ProtocolsConfigure,
|
|
387
|
+
target : this.connectedDid,
|
|
388
|
+
encryption,
|
|
495
389
|
};
|
|
496
390
|
|
|
497
391
|
if (this.delegateDid) {
|
|
498
392
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
499
393
|
connectedDid : this.connectedDid,
|
|
500
394
|
delegateDid : this.delegateDid,
|
|
501
|
-
protocol :
|
|
395
|
+
protocol : messageParams.definition.protocol,
|
|
502
396
|
delegate : true,
|
|
503
397
|
cached : true,
|
|
504
398
|
messageType : agentRequest.messageType
|
|
@@ -528,11 +422,13 @@ export class DwnApi {
|
|
|
528
422
|
* Query the available protocols
|
|
529
423
|
*/
|
|
530
424
|
query: async (request: ProtocolsQueryRequest): Promise<ProtocolsQueryResponse> => {
|
|
425
|
+
const { from, ...messageParams } = request;
|
|
426
|
+
|
|
531
427
|
const agentRequest: ProcessDwnRequest<DwnInterface.ProtocolsQuery> = {
|
|
532
|
-
author
|
|
533
|
-
messageParams
|
|
534
|
-
messageType
|
|
535
|
-
target
|
|
428
|
+
author : this.connectedDid,
|
|
429
|
+
messageParams,
|
|
430
|
+
messageType : DwnInterface.ProtocolsQuery,
|
|
431
|
+
target : from || this.connectedDid,
|
|
536
432
|
};
|
|
537
433
|
|
|
538
434
|
if (this.delegateDid) {
|
|
@@ -543,7 +439,7 @@ export class DwnApi {
|
|
|
543
439
|
const { grant: { id: permissionGrantId } } = await this.permissionsApi.getPermissionForRequest({
|
|
544
440
|
connectedDid : this.connectedDid,
|
|
545
441
|
delegateDid : this.delegateDid,
|
|
546
|
-
protocol :
|
|
442
|
+
protocol : messageParams.filter.protocol,
|
|
547
443
|
cached : true,
|
|
548
444
|
messageType : agentRequest.messageType
|
|
549
445
|
});
|
|
@@ -561,7 +457,7 @@ export class DwnApi {
|
|
|
561
457
|
|
|
562
458
|
let agentResponse: DwnResponse<DwnInterface.ProtocolsQuery>;
|
|
563
459
|
|
|
564
|
-
if (
|
|
460
|
+
if (from) {
|
|
565
461
|
agentResponse = await this.agent.sendDwnRequest(agentRequest);
|
|
566
462
|
} else {
|
|
567
463
|
agentResponse = await this.agent.processDwnRequest(agentRequest);
|
|
@@ -581,11 +477,9 @@ export class DwnApi {
|
|
|
581
477
|
}
|
|
582
478
|
|
|
583
479
|
/**
|
|
584
|
-
* API to interact with DWN records (e.g., `dwn.records.
|
|
480
|
+
* API to interact with DWN records (e.g., `dwn.records.write()`).
|
|
585
481
|
*/
|
|
586
482
|
get records(): {
|
|
587
|
-
create: (request: RecordsCreateRequest) => Promise<RecordsCreateResponse>;
|
|
588
|
-
createFrom: (request: RecordsCreateFromRequest) => Promise<RecordsWriteResponse>;
|
|
589
483
|
delete: (request: RecordsDeleteRequest) => Promise<DwnResponseStatus>;
|
|
590
484
|
query: (request: RecordsQueryRequest) => Promise<RecordsQueryResponse>;
|
|
591
485
|
read: (request: RecordsReadRequest) => Promise<RecordsReadResponse>;
|
|
@@ -594,77 +488,33 @@ export class DwnApi {
|
|
|
594
488
|
} {
|
|
595
489
|
|
|
596
490
|
return {
|
|
597
|
-
/**
|
|
598
|
-
* Alias for the `write` method
|
|
599
|
-
*/
|
|
600
|
-
create: async (request: RecordsCreateRequest): Promise<RecordsCreateResponse> => {
|
|
601
|
-
return this.records.write(request);
|
|
602
|
-
},
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Write a record based on an existing one (useful for updating an existing record)
|
|
606
|
-
*/
|
|
607
|
-
createFrom: async (request: RecordsCreateFromRequest): Promise<RecordsWriteResponse> => {
|
|
608
|
-
const { author: inheritedAuthor, ...inheritedProperties } = request.record.toJSON();
|
|
609
|
-
|
|
610
|
-
// If `data` is being updated then `dataCid` and `dataSize` must not be present.
|
|
611
|
-
if (request.data !== undefined) {
|
|
612
|
-
delete inheritedProperties.dataCid;
|
|
613
|
-
delete inheritedProperties.dataSize;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// If `published` is set to false, ensure that `datePublished` is undefined. Otherwise, DWN SDK's schema validation
|
|
617
|
-
// will throw an error if `published` is false but `datePublished` is set.
|
|
618
|
-
if (request.message?.published === false && inheritedProperties.datePublished !== undefined) {
|
|
619
|
-
delete inheritedProperties.datePublished;
|
|
620
|
-
delete inheritedProperties.published;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// If the request changes the `author` or message `descriptor` then the deterministic `recordId` will change.
|
|
624
|
-
// As a result, we will discard the `recordId` if either of these changes occur.
|
|
625
|
-
if (!isEmptyObject(request.message) || (request.author && request.author !== inheritedAuthor)) {
|
|
626
|
-
delete inheritedProperties.recordId;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Auto-detect encryption from the source record if not explicitly set.
|
|
630
|
-
const shouldEncrypt = request.encryption
|
|
631
|
-
?? (request.record.encryption !== undefined);
|
|
632
|
-
|
|
633
|
-
return this.records.write({
|
|
634
|
-
data : request.data,
|
|
635
|
-
message : {
|
|
636
|
-
...inheritedProperties,
|
|
637
|
-
...request.message,
|
|
638
|
-
},
|
|
639
|
-
encryption: shouldEncrypt || undefined,
|
|
640
|
-
});
|
|
641
|
-
},
|
|
642
|
-
|
|
643
491
|
/**
|
|
644
492
|
* Delete a record
|
|
645
493
|
*/
|
|
646
494
|
delete: async (request: RecordsDeleteRequest): Promise<DwnResponseStatus> => {
|
|
495
|
+
const { from, protocol, ...messageParams } = request;
|
|
496
|
+
|
|
647
497
|
const agentRequest: ProcessDwnRequest<DwnInterface.RecordsDelete> = {
|
|
648
498
|
/**
|
|
649
499
|
* The `author` is the DID that will sign the message and must be the DID the Web5 app is
|
|
650
500
|
* connected with and is authorized to access the signing private key of.
|
|
651
501
|
*/
|
|
652
|
-
author
|
|
653
|
-
messageParams
|
|
654
|
-
messageType
|
|
502
|
+
author : this.connectedDid,
|
|
503
|
+
messageParams,
|
|
504
|
+
messageType : DwnInterface.RecordsDelete,
|
|
655
505
|
/**
|
|
656
506
|
* The `target` is the DID of the DWN tenant under which the delete will be executed.
|
|
657
507
|
* If `from` is provided, the delete operation will be executed on a remote DWN.
|
|
658
508
|
* Otherwise, the record will be deleted on the local DWN.
|
|
659
509
|
*/
|
|
660
|
-
target
|
|
510
|
+
target : from || this.connectedDid,
|
|
661
511
|
};
|
|
662
512
|
|
|
663
513
|
if (this.delegateDid) {
|
|
664
514
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
665
515
|
connectedDid : this.connectedDid,
|
|
666
516
|
delegateDid : this.delegateDid,
|
|
667
|
-
protocol
|
|
517
|
+
protocol,
|
|
668
518
|
delegate : true,
|
|
669
519
|
cached : true,
|
|
670
520
|
messageType : agentRequest.messageType
|
|
@@ -679,7 +529,7 @@ export class DwnApi {
|
|
|
679
529
|
|
|
680
530
|
let agentResponse: DwnResponse<DwnInterface.RecordsDelete>;
|
|
681
531
|
|
|
682
|
-
if (
|
|
532
|
+
if (from) {
|
|
683
533
|
agentResponse = await this.agent.sendDwnRequest(agentRequest);
|
|
684
534
|
} else {
|
|
685
535
|
agentResponse = await this.agent.processDwnRequest(agentRequest);
|
|
@@ -689,39 +539,41 @@ export class DwnApi {
|
|
|
689
539
|
|
|
690
540
|
return { status };
|
|
691
541
|
},
|
|
542
|
+
|
|
692
543
|
/**
|
|
693
544
|
* Query a single or multiple records based on the given filter
|
|
694
545
|
*/
|
|
695
546
|
query: async (request: RecordsQueryRequest): Promise<RecordsQueryResponse> => {
|
|
547
|
+
const { from, encryption, ...messageParams } = request;
|
|
548
|
+
|
|
696
549
|
const agentRequest: ProcessDwnRequest<DwnInterface.RecordsQuery> = {
|
|
697
550
|
/**
|
|
698
551
|
* The `author` is the DID that will sign the message and must be the DID the Web5 app is
|
|
699
552
|
* connected with and is authorized to access the signing private key of.
|
|
700
553
|
*/
|
|
701
|
-
author
|
|
702
|
-
messageParams
|
|
703
|
-
messageType
|
|
554
|
+
author : this.connectedDid,
|
|
555
|
+
messageParams,
|
|
556
|
+
messageType : DwnInterface.RecordsQuery,
|
|
704
557
|
/**
|
|
705
558
|
* The `target` is the DID of the DWN tenant under which the query will be executed.
|
|
706
559
|
* If `from` is provided, the query operation will be executed on a remote DWN.
|
|
707
560
|
* Otherwise, the local DWN will be queried.
|
|
708
561
|
*/
|
|
709
|
-
target
|
|
710
|
-
encryption
|
|
562
|
+
target : from || this.connectedDid,
|
|
563
|
+
encryption,
|
|
711
564
|
};
|
|
712
565
|
|
|
713
566
|
if (this.delegateDid) {
|
|
714
567
|
// if we don't find a delegated grant, we will attempt to query signing as the delegated DID
|
|
715
568
|
// This is to allow the API caller to query public records without needing to impersonate the delegate.
|
|
716
569
|
//
|
|
717
|
-
// NOTE:
|
|
718
|
-
//
|
|
719
|
-
// TODO: https://github.com/enboxorg/enbox/issues/898
|
|
570
|
+
// NOTE: For anonymous/public queries without explicit permissions, callers can use `DwnReaderApi` via `Web5.anonymous()`.
|
|
571
|
+
// See: https://github.com/enboxorg/enbox/issues/898
|
|
720
572
|
try {
|
|
721
573
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
722
574
|
connectedDid : this.connectedDid,
|
|
723
575
|
delegateDid : this.delegateDid,
|
|
724
|
-
protocol :
|
|
576
|
+
protocol : messageParams.filter?.protocol,
|
|
725
577
|
delegate : true,
|
|
726
578
|
cached : true,
|
|
727
579
|
messageType : agentRequest.messageType
|
|
@@ -738,10 +590,9 @@ export class DwnApi {
|
|
|
738
590
|
}
|
|
739
591
|
}
|
|
740
592
|
|
|
741
|
-
|
|
742
593
|
let agentResponse: DwnResponse<DwnInterface.RecordsQuery>;
|
|
743
594
|
|
|
744
|
-
if (
|
|
595
|
+
if (from) {
|
|
745
596
|
agentResponse = await this.agent.sendDwnRequest(agentRequest);
|
|
746
597
|
} else {
|
|
747
598
|
agentResponse = await this.agent.processDwnRequest(agentRequest);
|
|
@@ -751,7 +602,6 @@ export class DwnApi {
|
|
|
751
602
|
const { entries = [], status, cursor } = reply;
|
|
752
603
|
|
|
753
604
|
const records = entries.map((entry) => {
|
|
754
|
-
|
|
755
605
|
const recordOptions = {
|
|
756
606
|
/**
|
|
757
607
|
* Extract the `author` DID from the record entry since records may be signed by the
|
|
@@ -770,7 +620,7 @@ export class DwnApi {
|
|
|
770
620
|
* to determine which DWN to send subsequent read requests to in the event the data
|
|
771
621
|
* payload exceeds the threshold for being returned with queries.
|
|
772
622
|
*/
|
|
773
|
-
remoteOrigin :
|
|
623
|
+
remoteOrigin : from,
|
|
774
624
|
delegateDid : this.delegateDid,
|
|
775
625
|
protocolRole : agentRequest.messageParams.protocolRole,
|
|
776
626
|
...entry as DwnMessage[DwnInterface.RecordsWrite]
|
|
@@ -786,35 +636,37 @@ export class DwnApi {
|
|
|
786
636
|
* Read a single record based on the given filter
|
|
787
637
|
*/
|
|
788
638
|
read: async (request: RecordsReadRequest): Promise<RecordsReadResponse> => {
|
|
639
|
+
const { from, protocol, encryption, ...messageParams } = request;
|
|
640
|
+
|
|
789
641
|
const agentRequest: ProcessDwnRequest<DwnInterface.RecordsRead> = {
|
|
790
642
|
/**
|
|
791
643
|
* The `author` is the DID that will sign the message and must be the DID the Web5 app is
|
|
792
644
|
* connected with and is authorized to access the signing private key of.
|
|
793
645
|
*/
|
|
794
|
-
author
|
|
795
|
-
messageParams
|
|
796
|
-
messageType
|
|
646
|
+
author : this.connectedDid,
|
|
647
|
+
messageParams,
|
|
648
|
+
messageType : DwnInterface.RecordsRead,
|
|
797
649
|
/**
|
|
798
650
|
* The `target` is the DID of the DWN tenant under which the read will be executed.
|
|
799
651
|
* If `from` is provided, the read operation will be executed on a remote DWN.
|
|
800
652
|
* Otherwise, the read will occur on the local DWN.
|
|
801
653
|
*/
|
|
802
|
-
target
|
|
803
|
-
encryption
|
|
654
|
+
target : from || this.connectedDid,
|
|
655
|
+
encryption,
|
|
804
656
|
};
|
|
657
|
+
|
|
805
658
|
if (this.delegateDid) {
|
|
806
659
|
// if we don't find a delegated grant, we will attempt to read signing as the delegated DID
|
|
807
660
|
// This is to allow the API caller to read public records without needing to impersonate the delegate.
|
|
808
661
|
//
|
|
809
|
-
// NOTE:
|
|
810
|
-
//
|
|
811
|
-
// TODO: https://github.com/enboxorg/enbox/issues/898
|
|
662
|
+
// NOTE: For anonymous/public reads without explicit permissions, callers can use `DwnReaderApi` via `Web5.anonymous()`.
|
|
663
|
+
// See: https://github.com/enboxorg/enbox/issues/898
|
|
812
664
|
|
|
813
665
|
try {
|
|
814
666
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
815
667
|
connectedDid : this.connectedDid,
|
|
816
668
|
delegateDid : this.delegateDid,
|
|
817
|
-
protocol
|
|
669
|
+
protocol,
|
|
818
670
|
delegate : true,
|
|
819
671
|
cached : true,
|
|
820
672
|
messageType : agentRequest.messageType
|
|
@@ -833,7 +685,7 @@ export class DwnApi {
|
|
|
833
685
|
|
|
834
686
|
let agentResponse: DwnResponse<DwnInterface.RecordsRead>;
|
|
835
687
|
|
|
836
|
-
if (
|
|
688
|
+
if (from) {
|
|
837
689
|
agentResponse = await this.agent.sendDwnRequest(agentRequest);
|
|
838
690
|
} else {
|
|
839
691
|
agentResponse = await this.agent.processDwnRequest(agentRequest);
|
|
@@ -861,7 +713,7 @@ export class DwnApi {
|
|
|
861
713
|
* to determine which DWN to send subsequent read requests to in the event the data
|
|
862
714
|
* payload must be read again (e.g., if the data stream is consumed).
|
|
863
715
|
*/
|
|
864
|
-
remoteOrigin :
|
|
716
|
+
remoteOrigin : from,
|
|
865
717
|
delegateDid : this.delegateDid,
|
|
866
718
|
data : entry.data,
|
|
867
719
|
initialWrite : entry.initialWrite,
|
|
@@ -875,52 +727,61 @@ export class DwnApi {
|
|
|
875
727
|
},
|
|
876
728
|
|
|
877
729
|
/**
|
|
878
|
-
*
|
|
730
|
+
* Subscribe to records matching the given filter.
|
|
879
731
|
*
|
|
880
|
-
*
|
|
881
|
-
*
|
|
732
|
+
* Returns a {@link LiveQuery} that atomically provides an initial snapshot
|
|
733
|
+
* of matching records and a real-time stream of deduplicated, semantically-
|
|
734
|
+
* typed change events (`create`, `update`, `delete`).
|
|
882
735
|
*/
|
|
883
736
|
subscribe: async (request: RecordsSubscribeRequest): Promise<RecordsSubscribeResponse> => {
|
|
884
|
-
const
|
|
885
|
-
/**
|
|
886
|
-
* The `author` is the DID that will sign the message and must be the DID the Web5 app is
|
|
887
|
-
* connected with and is authorized to access the signing private key of.
|
|
888
|
-
*/
|
|
889
|
-
author : this.connectedDid,
|
|
890
|
-
messageParams : request.message,
|
|
891
|
-
messageType : DwnInterface.RecordsSubscribe,
|
|
892
|
-
/**
|
|
893
|
-
* The `target` is the DID of the DWN tenant under which the subscribe operation will be executed.
|
|
894
|
-
* If `from` is provided, the subscribe operation will be executed on a remote DWN.
|
|
895
|
-
* Otherwise, the local DWN will execute the subscribe operation.
|
|
896
|
-
*/
|
|
897
|
-
target : request.from || this.connectedDid,
|
|
737
|
+
const { from, ...messageParams } = request;
|
|
898
738
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
739
|
+
// Build a DWN-level subscription handler that wraps raw RecordEvents
|
|
740
|
+
// into Record objects and feeds them into the LiveQuery.
|
|
741
|
+
let liveQuery: LiveQuery | undefined;
|
|
742
|
+
|
|
743
|
+
const remoteOrigin = from;
|
|
744
|
+
const protocolRole = messageParams.protocolRole;
|
|
745
|
+
|
|
746
|
+
type RecordEvent = {
|
|
747
|
+
message: DwnMessage[DwnInterface.RecordsWrite];
|
|
748
|
+
initialWrite?: DwnMessage[DwnInterface.RecordsWrite];
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
const subscriptionHandler = async (event: RecordEvent): Promise<void> => {
|
|
752
|
+
const { message, initialWrite } = event;
|
|
753
|
+
const record = new Record(this.agent, {
|
|
754
|
+
...message,
|
|
755
|
+
author : getRecordAuthor(message),
|
|
756
|
+
connectedDid : this.connectedDid,
|
|
757
|
+
remoteOrigin,
|
|
758
|
+
initialWrite,
|
|
759
|
+
protocolRole,
|
|
760
|
+
delegateDid : this.delegateDid,
|
|
761
|
+
}, this.permissionsApi);
|
|
762
|
+
|
|
763
|
+
liveQuery?.handleEvent(record);
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
const agentRequest: ProcessDwnRequest<DwnInterface.RecordsSubscribe> = {
|
|
767
|
+
author : this.connectedDid,
|
|
768
|
+
messageParams,
|
|
769
|
+
messageType : DwnInterface.RecordsSubscribe,
|
|
770
|
+
target : from || this.connectedDid,
|
|
771
|
+
subscriptionHandler,
|
|
910
772
|
};
|
|
911
773
|
|
|
912
774
|
if (this.delegateDid) {
|
|
913
775
|
// if we don't find a delegated grant, we will attempt to subscribe signing as the delegated DID
|
|
914
776
|
// This is to allow the API caller to subscribe to public records without needing to impersonate the delegate.
|
|
915
777
|
//
|
|
916
|
-
// NOTE:
|
|
917
|
-
//
|
|
918
|
-
// TODO: https://github.com/enboxorg/enbox/issues/898
|
|
778
|
+
// NOTE: For anonymous/public subscriptions without explicit permissions, callers can use `DwnReaderApi` via `Web5.anonymous()`.
|
|
779
|
+
// See: https://github.com/enboxorg/enbox/issues/898
|
|
919
780
|
try {
|
|
920
781
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
921
782
|
connectedDid : this.connectedDid,
|
|
922
783
|
delegateDid : this.delegateDid,
|
|
923
|
-
protocol :
|
|
784
|
+
protocol : messageParams.filter?.protocol,
|
|
924
785
|
delegate : true,
|
|
925
786
|
cached : true,
|
|
926
787
|
messageType : agentRequest.messageType
|
|
@@ -939,16 +800,30 @@ export class DwnApi {
|
|
|
939
800
|
|
|
940
801
|
let agentResponse: DwnResponse<DwnInterface.RecordsSubscribe>;
|
|
941
802
|
|
|
942
|
-
if (
|
|
803
|
+
if (from) {
|
|
943
804
|
agentResponse = await this.agent.sendDwnRequest(agentRequest);
|
|
944
805
|
} else {
|
|
945
806
|
agentResponse = await this.agent.processDwnRequest(agentRequest);
|
|
946
807
|
}
|
|
947
808
|
|
|
948
809
|
const reply = agentResponse.reply;
|
|
949
|
-
const { status, subscription } = reply;
|
|
810
|
+
const { status, subscription, entries = [], cursor } = reply;
|
|
811
|
+
|
|
812
|
+
if (subscription) {
|
|
813
|
+
liveQuery = new LiveQuery({
|
|
814
|
+
agent : this.agent,
|
|
815
|
+
connectedDid : this.connectedDid,
|
|
816
|
+
delegateDid : this.delegateDid,
|
|
817
|
+
protocolRole,
|
|
818
|
+
remoteOrigin,
|
|
819
|
+
permissionsApi : this.permissionsApi,
|
|
820
|
+
initialEntries : entries,
|
|
821
|
+
cursor,
|
|
822
|
+
subscription,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
950
825
|
|
|
951
|
-
return { status,
|
|
826
|
+
return { status, liveQuery };
|
|
952
827
|
},
|
|
953
828
|
|
|
954
829
|
/**
|
|
@@ -961,19 +836,19 @@ export class DwnApi {
|
|
|
961
836
|
* requires fetching from the DWN datastore.
|
|
962
837
|
*/
|
|
963
838
|
write: async (request: RecordsWriteRequest): Promise<RecordsWriteResponse> => {
|
|
964
|
-
const {
|
|
839
|
+
const { data, store, encryption, ...restParams } = request;
|
|
840
|
+
const { dataBlob, dataFormat } = dataToBlob(data, restParams.dataFormat);
|
|
841
|
+
|
|
842
|
+
const messageParams = { ...restParams, dataFormat };
|
|
965
843
|
|
|
966
844
|
const dwnRequestParams: ProcessDwnRequest<DwnInterface.RecordsWrite> = {
|
|
967
|
-
store
|
|
968
|
-
messageType
|
|
969
|
-
messageParams
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
target : this.connectedDid,
|
|
975
|
-
dataStream : dataBlob,
|
|
976
|
-
encryption : request.encryption,
|
|
845
|
+
store,
|
|
846
|
+
messageType : DwnInterface.RecordsWrite,
|
|
847
|
+
messageParams,
|
|
848
|
+
author : this.connectedDid,
|
|
849
|
+
target : this.connectedDid,
|
|
850
|
+
dataStream : dataBlob,
|
|
851
|
+
encryption,
|
|
977
852
|
};
|
|
978
853
|
|
|
979
854
|
// if impersonation is enabled, fetch the delegated grant to use with the write operation
|
|
@@ -981,7 +856,7 @@ export class DwnApi {
|
|
|
981
856
|
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
|
|
982
857
|
connectedDid : this.connectedDid,
|
|
983
858
|
delegateDid : this.delegateDid,
|
|
984
|
-
protocol :
|
|
859
|
+
protocol : messageParams.protocol,
|
|
985
860
|
delegate : true,
|
|
986
861
|
cached : true,
|
|
987
862
|
messageType : dwnRequestParams.messageType
|