@enbox/api 0.1.1 → 0.2.1
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 +505 -138
- 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 +56 -114
- 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 +3 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/live-query.js +5 -4
- package/dist/esm/live-query.js.map +1 -1
- 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 +13 -92
- 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 +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/live-query.d.ts +13 -1
- package/dist/types/live-query.d.ts.map +1 -1
- 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} +70 -73
- 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 +91 -232
- package/src/dwn-reader-api.ts +255 -0
- package/src/index.ts +3 -2
- package/src/live-query.ts +20 -4
- 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/typed-dwn-api.js +0 -182
- package/dist/esm/typed-dwn-api.js.map +0 -1
- package/dist/types/typed-dwn-api.d.ts.map +0 -1
- package/src/typed-dwn-api.ts +0 -370
package/src/record.ts
CHANGED
|
@@ -60,8 +60,8 @@ export type RecordModel = ImmutableRecordProperties & OptionalRecordProperties &
|
|
|
60
60
|
/** The unique identifier of the record. */
|
|
61
61
|
recordId?: string;
|
|
62
62
|
|
|
63
|
-
/** The timestamp
|
|
64
|
-
|
|
63
|
+
/** The message timestamp (time of creation, most recent update, or deletion). */
|
|
64
|
+
timestamp?: string;
|
|
65
65
|
|
|
66
66
|
/** The protocol role under which this record is written. */
|
|
67
67
|
protocolRole?: RecordOptions['protocolRole'];
|
|
@@ -152,8 +152,8 @@ export type RecordUpdateParams = {
|
|
|
152
152
|
/** The size of the data in bytes. */
|
|
153
153
|
dataSize?: DwnMessageDescriptor[DwnInterface.RecordsWrite]['dataSize'];
|
|
154
154
|
|
|
155
|
-
/** The timestamp
|
|
156
|
-
|
|
155
|
+
/** The timestamp of the update message. */
|
|
156
|
+
timestamp?: DwnMessageDescriptor[DwnInterface.RecordsWrite]['messageTimestamp'];
|
|
157
157
|
|
|
158
158
|
/** The timestamp indicating when the record was published. */
|
|
159
159
|
datePublished?: DwnMessageDescriptor[DwnInterface.RecordsWrite]['datePublished'];
|
|
@@ -196,13 +196,33 @@ export type RecordDeleteParams = {
|
|
|
196
196
|
/** Whether or not to prune any children this record may have. */
|
|
197
197
|
prune?: DwnMessageDescriptor[DwnInterface.RecordsDelete]['prune'];
|
|
198
198
|
|
|
199
|
-
/** The timestamp
|
|
200
|
-
|
|
199
|
+
/** The timestamp of the delete message. */
|
|
200
|
+
timestamp?: DwnMessageDescriptor[DwnInterface.RecordsDelete]['messageTimestamp'];
|
|
201
201
|
|
|
202
202
|
/** The protocol role under which this record will be deleted. */
|
|
203
203
|
protocolRole?: string;
|
|
204
204
|
};
|
|
205
205
|
|
|
206
|
+
/**
|
|
207
|
+
* The result of a {@link Record.update} operation.
|
|
208
|
+
*
|
|
209
|
+
* @beta
|
|
210
|
+
*/
|
|
211
|
+
export type RecordUpdateResult = DwnResponseStatus & {
|
|
212
|
+
/** The updated Record instance reflecting the new state. */
|
|
213
|
+
record: Record;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* The result of a {@link Record.delete} operation.
|
|
218
|
+
*
|
|
219
|
+
* @beta
|
|
220
|
+
*/
|
|
221
|
+
export type RecordDeleteResult = DwnResponseStatus & {
|
|
222
|
+
/** The deleted Record instance reflecting the deleted state. */
|
|
223
|
+
record: Record;
|
|
224
|
+
};
|
|
225
|
+
|
|
206
226
|
/**
|
|
207
227
|
* The `Record` class encapsulates a single record's data and metadata, providing a more
|
|
208
228
|
* developer-friendly interface for working with Decentralized Web Node (DWN) records.
|
|
@@ -210,12 +230,9 @@ export type RecordDeleteParams = {
|
|
|
210
230
|
* Methods are provided to read, update, and manage the record's lifecycle, including writing to
|
|
211
231
|
* remote DWNs.
|
|
212
232
|
*
|
|
213
|
-
* Note: The `messageTimestamp`
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* intended to simplify the developer experience of working with
|
|
217
|
-
* logical records (and not individual DWN messages) the
|
|
218
|
-
* `messageTimestamp` is mapped to `dateModified`.
|
|
233
|
+
* Note: The DWN SDK's `messageTimestamp` is exposed as `timestamp` on
|
|
234
|
+
* the Record class. It represents the time of the most recent
|
|
235
|
+
* message (create, update, or delete) for this logical record.
|
|
219
236
|
*
|
|
220
237
|
* @beta
|
|
221
238
|
*/
|
|
@@ -270,9 +287,14 @@ export class Record implements RecordModel {
|
|
|
270
287
|
/** Role under which the record is written. */
|
|
271
288
|
private _protocolRole?: RecordOptions['protocolRole'];
|
|
272
289
|
|
|
290
|
+
/** Cached reconstructed raw message, invalidated when record state changes. */
|
|
291
|
+
private _rawMessageCache?: DwnMessage[DwnInterface.RecordsWrite] | DwnMessage[DwnInterface.RecordsDelete];
|
|
292
|
+
/** Dirty flag indicating the cached raw message needs to be rebuilt. */
|
|
293
|
+
private _rawMessageDirty: boolean = true;
|
|
294
|
+
|
|
273
295
|
/** The `RecordsWriteMessage` descriptor unless the record is in a deleted state */
|
|
274
296
|
private get _recordsWriteDescriptor(): DwnMessageDescriptor[DwnInterface.RecordsWrite] | undefined {
|
|
275
|
-
if (
|
|
297
|
+
if (!this.isRecordsDeleteDescriptor(this._descriptor)) {
|
|
276
298
|
return this._descriptor as DwnMessageDescriptor[DwnInterface.RecordsWrite];
|
|
277
299
|
}
|
|
278
300
|
|
|
@@ -338,8 +360,8 @@ export class Record implements RecordModel {
|
|
|
338
360
|
/** DID that is the original creator of the Record. */
|
|
339
361
|
get creator(): string { return this._creator; }
|
|
340
362
|
|
|
341
|
-
/** Record's
|
|
342
|
-
get
|
|
363
|
+
/** Record's message timestamp (time of creation, most recent update, or deletion). */
|
|
364
|
+
get timestamp(): string { return this._descriptor.messageTimestamp; }
|
|
343
365
|
|
|
344
366
|
/** Record's encryption */
|
|
345
367
|
get encryption(): DwnMessage[DwnInterface.RecordsWrite]['encryption'] { return this._encryption; }
|
|
@@ -354,15 +376,20 @@ export class Record implements RecordModel {
|
|
|
354
376
|
get protocolRole(): string | undefined { return this._protocolRole; }
|
|
355
377
|
|
|
356
378
|
/** Record's deleted state (true/false) */
|
|
357
|
-
get deleted(): boolean { return
|
|
379
|
+
get deleted(): boolean { return this.isRecordsDeleteDescriptor(this._descriptor); }
|
|
358
380
|
|
|
359
381
|
/** Record's initial write if the record has been updated */
|
|
360
382
|
get initialWrite(): RecordOptions['initialWrite'] { return this._initialWrite; }
|
|
361
383
|
|
|
362
384
|
/**
|
|
363
385
|
* Returns a copy of the raw `RecordsWriteMessage` that was used to create the current `Record` instance.
|
|
386
|
+
* The result is cached and only rebuilt when the record's state changes (via `update()` or `delete()`).
|
|
364
387
|
*/
|
|
365
388
|
get rawMessage(): DwnMessage[DwnInterface.RecordsWrite] | DwnMessage[DwnInterface.RecordsDelete] {
|
|
389
|
+
if (!this._rawMessageDirty && this._rawMessageCache) {
|
|
390
|
+
return this._rawMessageCache;
|
|
391
|
+
}
|
|
392
|
+
|
|
366
393
|
const messageType = this._descriptor.interface + this._descriptor.method;
|
|
367
394
|
let message: DwnMessage[DwnInterface.RecordsWrite] | DwnMessage[DwnInterface.RecordsDelete];
|
|
368
395
|
if (messageType === DwnInterface.RecordsWrite) {
|
|
@@ -382,6 +409,9 @@ export class Record implements RecordModel {
|
|
|
382
409
|
}
|
|
383
410
|
|
|
384
411
|
removeUndefinedProperties(message);
|
|
412
|
+
|
|
413
|
+
this._rawMessageCache = message;
|
|
414
|
+
this._rawMessageDirty = false;
|
|
385
415
|
return message;
|
|
386
416
|
}
|
|
387
417
|
|
|
@@ -661,7 +691,7 @@ export class Record implements RecordModel {
|
|
|
661
691
|
messageType : DwnInterface.RecordsWrite,
|
|
662
692
|
author : this._connectedDid,
|
|
663
693
|
target : target,
|
|
664
|
-
dataStream : await this.data.blob(),
|
|
694
|
+
dataStream : this._encodedData ?? await this.data.blob(),
|
|
665
695
|
rawMessage : { ...this.rawMessage }
|
|
666
696
|
};
|
|
667
697
|
}
|
|
@@ -677,26 +707,26 @@ export class Record implements RecordModel {
|
|
|
677
707
|
*/
|
|
678
708
|
toJSON(): RecordModel {
|
|
679
709
|
return {
|
|
680
|
-
attestation
|
|
681
|
-
author
|
|
682
|
-
authorization
|
|
683
|
-
contextId
|
|
684
|
-
dataCid
|
|
685
|
-
dataFormat
|
|
686
|
-
dataSize
|
|
687
|
-
dateCreated
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
710
|
+
attestation : this.attestation,
|
|
711
|
+
author : this.author,
|
|
712
|
+
authorization : this.authorization,
|
|
713
|
+
contextId : this.contextId,
|
|
714
|
+
dataCid : this.dataCid,
|
|
715
|
+
dataFormat : this.dataFormat,
|
|
716
|
+
dataSize : this.dataSize,
|
|
717
|
+
dateCreated : this.dateCreated,
|
|
718
|
+
datePublished : this.datePublished,
|
|
719
|
+
encryption : this.encryption,
|
|
720
|
+
parentId : this.parentId,
|
|
721
|
+
protocol : this.protocol,
|
|
722
|
+
protocolPath : this.protocolPath,
|
|
723
|
+
protocolRole : this.protocolRole,
|
|
724
|
+
published : this.published,
|
|
725
|
+
recipient : this.recipient,
|
|
726
|
+
recordId : this.id,
|
|
727
|
+
schema : this.schema,
|
|
728
|
+
tags : this.tags,
|
|
729
|
+
timestamp : this.timestamp,
|
|
700
730
|
};
|
|
701
731
|
}
|
|
702
732
|
|
|
@@ -720,7 +750,7 @@ export class Record implements RecordModel {
|
|
|
720
750
|
|
|
721
751
|
str += ` Deleted: ${this.deleted}\n`;
|
|
722
752
|
str += ` Created: ${this.dateCreated}\n`;
|
|
723
|
-
str += `
|
|
753
|
+
str += ` Timestamp: ${this.timestamp}\n`;
|
|
724
754
|
str += `}`;
|
|
725
755
|
return str;
|
|
726
756
|
}
|
|
@@ -743,7 +773,7 @@ export class Record implements RecordModel {
|
|
|
743
773
|
*
|
|
744
774
|
* @beta
|
|
745
775
|
*/
|
|
746
|
-
async update({
|
|
776
|
+
async update({ timestamp, data, encryption, protocolRole, store = true, ...params }: RecordUpdateParams): Promise<RecordUpdateResult> {
|
|
747
777
|
|
|
748
778
|
if (this.deleted) {
|
|
749
779
|
throw new Error('Record: Cannot revive a deleted record.');
|
|
@@ -763,7 +793,7 @@ export class Record implements RecordModel {
|
|
|
763
793
|
...params,
|
|
764
794
|
parentContextId,
|
|
765
795
|
protocolRole : protocolRole ?? this._protocolRole, // Use the current protocolRole if not provided.
|
|
766
|
-
messageTimestamp :
|
|
796
|
+
messageTimestamp : timestamp, // Map Record class `timestamp` property to DWN SDK `messageTimestamp`
|
|
767
797
|
recordId : this._recordId
|
|
768
798
|
};
|
|
769
799
|
|
|
@@ -785,7 +815,7 @@ export class Record implements RecordModel {
|
|
|
785
815
|
}
|
|
786
816
|
|
|
787
817
|
// Throw an error if an attempt is made to modify immutable properties.
|
|
788
|
-
// Note: `data` and `
|
|
818
|
+
// Note: `data` and `timestamp` have already been handled.
|
|
789
819
|
const mutableDescriptorProperties = new Set(['data', 'dataCid', 'dataFormat', 'dataSize', 'datePublished', 'messageTimestamp', 'published', 'tags']);
|
|
790
820
|
Record.verifyPermittedMutation(Object.keys(params), mutableDescriptorProperties);
|
|
791
821
|
|
|
@@ -820,41 +850,38 @@ export class Record implements RecordModel {
|
|
|
820
850
|
|
|
821
851
|
const agentResponse = await this._agent.processDwnRequest(requestOptions);
|
|
822
852
|
|
|
823
|
-
const { message, reply: { status } } = agentResponse;
|
|
824
|
-
const responseMessage = message;
|
|
825
|
-
|
|
826
|
-
if (200 <= status.code && status.code <= 299) {
|
|
827
|
-
// copy the original raw message to the initial write before we update the values.
|
|
828
|
-
if (!this._initialWrite) {
|
|
829
|
-
// If there is no initial write, we need to create one from the current record state.
|
|
830
|
-
// We checked in the beginning of the function that the rawMessage is a RecordsWrite message.
|
|
831
|
-
this._initialWrite = { ...this.rawMessage as DwnMessage[DwnInterface.RecordsWrite] };
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// Only update the local Record instance mutable properties if the record was successfully (over)written.
|
|
835
|
-
this._authorization = responseMessage.authorization;
|
|
836
|
-
this._encryption = responseMessage.encryption;
|
|
837
|
-
this._protocolRole = updateMessage.protocolRole;
|
|
838
|
-
mutableDescriptorProperties.forEach(property => {
|
|
839
|
-
this._descriptor[property] = responseMessage.descriptor[property];
|
|
840
|
-
});
|
|
853
|
+
const { message: responseMessage, reply: { status } } = agentResponse;
|
|
841
854
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
}
|
|
855
|
+
if (!(200 <= status.code && status.code <= 299)) {
|
|
856
|
+
// Return a shallow copy of this record on failure — no state change.
|
|
857
|
+
return { status, record: this };
|
|
846
858
|
}
|
|
847
859
|
|
|
848
|
-
|
|
860
|
+
// Determine the initial write for the new Record instance.
|
|
861
|
+
const initialWrite = this._initialWrite ?? { ...this.rawMessage as DwnMessage[DwnInterface.RecordsWrite] };
|
|
862
|
+
|
|
863
|
+
// Construct a new Record instance reflecting the updated state.
|
|
864
|
+
const updatedRecord = new Record(this._agent, {
|
|
865
|
+
author : this._author,
|
|
866
|
+
connectedDid : this._connectedDid,
|
|
867
|
+
delegateDid : this._delegateDid,
|
|
868
|
+
remoteOrigin : this._remoteOrigin,
|
|
869
|
+
protocolRole : protocolRole ?? this._protocolRole,
|
|
870
|
+
initialWrite,
|
|
871
|
+
encodedData : data !== undefined ? dataBlob : this._encodedData,
|
|
872
|
+
...responseMessage as DwnMessage[DwnInterface.RecordsWrite],
|
|
873
|
+
}, this._permissionsApi);
|
|
874
|
+
|
|
875
|
+
return { status, record: updatedRecord };
|
|
849
876
|
}
|
|
850
877
|
|
|
851
878
|
/**
|
|
852
879
|
* Delete the current record on the DWN.
|
|
853
880
|
* @param params - Parameters to delete the record.
|
|
854
|
-
* @returns the status
|
|
881
|
+
* @returns the status and a new Record instance reflecting the deleted state
|
|
855
882
|
*/
|
|
856
|
-
async delete(deleteParams?: RecordDeleteParams): Promise<
|
|
857
|
-
const { store = true, signAsOwner,
|
|
883
|
+
async delete(deleteParams?: RecordDeleteParams): Promise<RecordDeleteResult> {
|
|
884
|
+
const { store = true, signAsOwner, timestamp, prune = false } = deleteParams || {};
|
|
858
885
|
|
|
859
886
|
const signAsOwnerValue = signAsOwner && this._delegateDid === undefined;
|
|
860
887
|
const signAsOwnerDelegate = signAsOwner && this._delegateDid !== undefined;
|
|
@@ -893,7 +920,7 @@ export class Record implements RecordModel {
|
|
|
893
920
|
deleteOptions.messageParams = {
|
|
894
921
|
prune : prune,
|
|
895
922
|
recordId : this._recordId,
|
|
896
|
-
messageTimestamp :
|
|
923
|
+
messageTimestamp : timestamp,
|
|
897
924
|
protocolRole : deleteParams?.protocolRole ?? this._protocolRole // if no protocolRole is provided, use the current protocolRole
|
|
898
925
|
};
|
|
899
926
|
}
|
|
@@ -920,22 +947,23 @@ export class Record implements RecordModel {
|
|
|
920
947
|
const { message, reply: { status } } = agentResponse;
|
|
921
948
|
|
|
922
949
|
if (status.code !== 202) {
|
|
923
|
-
// If the delete was not successful, return
|
|
924
|
-
return { status };
|
|
950
|
+
// If the delete was not successful, return this record unchanged.
|
|
951
|
+
return { status, record: this };
|
|
925
952
|
}
|
|
926
953
|
|
|
927
|
-
//
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
954
|
+
// Construct a new Record instance reflecting the deleted state.
|
|
955
|
+
const initialWrite = this._initialWrite;
|
|
956
|
+
const deletedRecord = new Record(this._agent, {
|
|
957
|
+
author : getRecordAuthor(message),
|
|
958
|
+
connectedDid : this._connectedDid,
|
|
959
|
+
delegateDid : this._delegateDid,
|
|
960
|
+
remoteOrigin : this._remoteOrigin,
|
|
961
|
+
protocolRole : deleteParams?.protocolRole ?? this._protocolRole,
|
|
962
|
+
initialWrite,
|
|
963
|
+
...message as DwnMessage[DwnInterface.RecordsDelete],
|
|
964
|
+
}, this._permissionsApi);
|
|
965
|
+
|
|
966
|
+
return { status, record: deletedRecord };
|
|
939
967
|
}
|
|
940
968
|
|
|
941
969
|
/**
|
|
@@ -1051,7 +1079,10 @@ export class Record implements RecordModel {
|
|
|
1051
1079
|
if (200 <= status.code && status.code <= 299) {
|
|
1052
1080
|
// If we are signing as the owner, make sure to update the current record state's
|
|
1053
1081
|
// authorization, because now it will have the owner's signature on it.
|
|
1054
|
-
if (signAsOwner) {
|
|
1082
|
+
if (signAsOwner) {
|
|
1083
|
+
this._authorization = responseMessage.authorization;
|
|
1084
|
+
this._rawMessageDirty = true;
|
|
1085
|
+
}
|
|
1055
1086
|
}
|
|
1056
1087
|
|
|
1057
1088
|
return { status };
|
|
@@ -1088,9 +1119,8 @@ export class Record implements RecordModel {
|
|
|
1088
1119
|
// When reading the data as a delegate, if we don't find a grant we will attempt to read it with the delegate DID as the author.
|
|
1089
1120
|
// This allows users to read publicly available data without needing explicit grants.
|
|
1090
1121
|
//
|
|
1091
|
-
// NOTE:
|
|
1092
|
-
//
|
|
1093
|
-
// TODO: https://github.com/enboxorg/enbox/issues/898
|
|
1122
|
+
// NOTE: For anonymous/public record data access, callers can use `ReadOnlyRecord` via `Web5.anonymous()`.
|
|
1123
|
+
// See: https://github.com/enboxorg/enbox/issues/898
|
|
1094
1124
|
try {
|
|
1095
1125
|
const { message: delegatedGrant } = await this._permissionsApi.getPermissionForRequest({
|
|
1096
1126
|
connectedDid : this._connectedDid,
|