diff --git a/package-lock.json b/package-lock.json index a3a7b72d7..41bc9df0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tbd54566975/dwn-sdk-js", - "version": "0.4.7", + "version": "0.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tbd54566975/dwn-sdk-js", - "version": "0.4.7", + "version": "0.5.0", "license": "Apache-2.0", "dependencies": { "@ipld/dag-cbor": "9.0.3", diff --git a/package.json b/package.json index a1b2e2bf8..41d2fdf4c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tbd54566975/dwn-sdk-js", - "version": "0.4.7", + "version": "0.5.0", "description": "A reference implementation of https://identity.foundation/decentralized-web-node/spec/", "repository": { "type": "git", diff --git a/src/handlers/records-read.ts b/src/handlers/records-read.ts index 2c3553eb6..2e8540553 100644 --- a/src/handlers/records-read.ts +++ b/src/handlers/records-read.ts @@ -65,16 +65,20 @@ export class RecordsReadHandler implements MethodHandler { const matchedMessage = existingMessages[0]; + // if the matched message is a RecordsDelete, we mark the record as not-found and return both the RecordsDelete and the initial RecordsWrite + // TODO: https://github.com/TBD54566975/dwn-sdk-js/issues/819: + // Consider performing authorization checks like when records exists before returning RecordsDelete and initial RecordsWrite of a deleted record if (matchedMessage.descriptor.method === DwnMethodName.Delete) { const recordsDeleteMessage = matchedMessage as RecordsDeleteMessage; const initialWrite = await RecordsWrite.fetchInitialRecordsWriteMessage(this.messageStore, tenant, recordsDeleteMessage.descriptor.recordId); return { - status : { code: 404, detail: 'Not Found' }, - delete : recordsDeleteMessage, + status : { code: 404, detail: 'Not Found' }, + recordsDelete : recordsDeleteMessage, initialWrite }; } + // else the matched message is a RecordsWrite const matchedRecordsWrite = matchedMessage as RecordsQueryReplyEntry; try { @@ -98,27 +102,24 @@ export class RecordsReadHandler implements MethodHandler { data = result.dataStream; } - const record = { - ...matchedRecordsWrite, + const recordsReadReply: RecordsReadReply = { + status : { code: 200, detail: 'OK' }, + recordsWrite : matchedRecordsWrite, data }; - // attach initial write if returned RecordsWrite is not initial write - if (!await RecordsWrite.isInitialWrite(record)) { + // attach initial write if latest RecordsWrite is not initial write + if (!await RecordsWrite.isInitialWrite(matchedRecordsWrite)) { const initialWriteQueryResult = await this.messageStore.query( tenant, - [{ recordId: record.recordId, isLatestBaseState: false, method: DwnMethodName.Write }] + [{ recordId: matchedRecordsWrite.recordId, isLatestBaseState: false, method: DwnMethodName.Write }] ); const initialWrite = initialWriteQueryResult.messages[0] as RecordsQueryReplyEntry; - delete initialWrite.encodedData; // defensive measure but technically optional because we do this when an update RecordsWrite takes place - record.initialWrite = initialWrite; + delete initialWrite.encodedData; // just defensive because technically should already be deleted when a later RecordsWrite is written + recordsReadReply.initialWrite = initialWrite; } - const messageReply: RecordsReadReply = { - status: { code: 200, detail: 'OK' }, - record - }; - return messageReply; + return recordsReadReply; }; /** diff --git a/src/types/records-types.ts b/src/types/records-types.ts index 8dd1b1b26..14ffb3071 100644 --- a/src/types/records-types.ts +++ b/src/types/records-types.ts @@ -202,21 +202,29 @@ export type RecordsReadMessage = { descriptor: RecordsReadDescriptor; }; +/** + * The reply to a RecordsRead message. + */ export type RecordsReadReply = GenericMessageReply & { + /** + * The latest RecordsWrite message of the record if record exists (not deleted). + */ + recordsWrite?: RecordsWriteMessage; + /** * The RecordsDelete if the record is deleted. */ - delete?: RecordsDeleteMessage; + recordsDelete?: RecordsDeleteMessage; /** * The initial write of the record if the returned RecordsWrite message itself is not the initial write or if a RecordsDelete is returned. */ initialWrite?: RecordsWriteMessage; - record?: RecordsWriteMessage & { - initialWrite?: RecordsWriteMessage; - data: Readable; - }; + /** + * The data stream associated with the record if the records exists (not deleted). + */ + data?: Readable; }; export type RecordsReadDescriptor = { diff --git a/tests/features/author-delegated-grant.spec.ts b/tests/features/author-delegated-grant.spec.ts index f93076158..60fc9117b 100644 --- a/tests/features/author-delegated-grant.spec.ts +++ b/tests/features/author-delegated-grant.spec.ts @@ -505,7 +505,7 @@ export function testAuthorDelegatedGrant(): void { }); const deviceXRecordsReadReply = await dwn.processMessage(bob.did, recordsReadByDeviceX.message); expect(deviceXRecordsReadReply.status.code).to.equal(200); - expect(deviceXRecordsReadReply.record?.recordId).to.equal(chatRecord.message.recordId); + expect(deviceXRecordsReadReply.recordsWrite?.recordId).to.equal(chatRecord.message.recordId); // Verify that Carol cannot query as Alice by invoking the delegated grant granted to Device X const recordsQueryByCarol = await RecordsQuery.create({ diff --git a/tests/features/owner-signature.spec.ts b/tests/features/owner-signature.spec.ts index eed9cad07..1d3978e41 100644 --- a/tests/features/owner-signature.spec.ts +++ b/tests/features/owner-signature.spec.ts @@ -78,26 +78,26 @@ export function testOwnerSignature(): void { const readReply = await dwn.processMessage(bob.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; - expect(readReply.record?.descriptor).to.exist; + expect(readReply.recordsWrite).to.exist; + expect(readReply.recordsWrite?.descriptor).to.exist; // Alice augments Bob's message as an external owner - const { data, ...messageFetched } = readReply.record!; // remove data from message - const ownerSignedMessage = await RecordsWrite.parse(messageFetched); + const { recordsWrite } = readReply; // remove data from message + const ownerSignedMessage = await RecordsWrite.parse(recordsWrite!); await ownerSignedMessage.signAsOwner(Jws.createSigner(alice)); // Test that Alice can successfully retain/write Bob's message to her DWN - const aliceDataStream = readReply.record!.data; + const aliceDataStream = readReply.data!; const aliceWriteReply = await dwn.processMessage(alice.did, ownerSignedMessage.message, { dataStream: aliceDataStream }); expect(aliceWriteReply.status.code).to.equal(202); // Test that Bob's message can be read from Alice's DWN const readReply2 = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply2.status.code).to.equal(200); - expect(readReply2.record).to.exist; - expect(readReply2.record?.descriptor).to.exist; + expect(readReply2.recordsWrite).to.exist; + expect(readReply2.recordsWrite?.descriptor).to.exist; - const dataFetched = await DataStream.toBytes(readReply2.record!.data!); + const dataFetched = await DataStream.toBytes(readReply2.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); @@ -144,10 +144,10 @@ export function testOwnerSignature(): void { }); const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; - expect(readReply.record?.descriptor).to.exist; + expect(readReply.recordsWrite).to.exist; + expect(readReply.recordsWrite?.descriptor).to.exist; - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, bobRecordsWrite.dataBytes!)).to.be.true; }); diff --git a/tests/features/permissions.spec.ts b/tests/features/permissions.spec.ts index e7a458099..694c8ffb9 100644 --- a/tests/features/permissions.spec.ts +++ b/tests/features/permissions.spec.ts @@ -345,7 +345,7 @@ export function testPermissions(): void { // 9. Verify that any third-party can fetch the revocation status of the permission grant const revocationReadReply2 = await dwn.processMessage(alice.did, revocationRead.message); expect(revocationReadReply2.status.code).to.equal(200); - expect(revocationReadReply2.record?.recordId).to.equal(revokeWrite.recordsWrite.message.recordId); + expect(revocationReadReply2.recordsWrite?.recordId).to.equal(revokeWrite.recordsWrite.message.recordId); }); it('should fail if a RecordsPermissionScope in a Request or Grant record is created without a protocol', async () => { diff --git a/tests/features/protocol-update-action.spec.ts b/tests/features/protocol-update-action.spec.ts index 9ac08d935..2559a40e3 100644 --- a/tests/features/protocol-update-action.spec.ts +++ b/tests/features/protocol-update-action.spec.ts @@ -165,8 +165,8 @@ export function testProtocolUpdateAction(): void { }); const recordsReadReply = await dwn.processMessage(alice.did, recordsRead.message); expect(recordsReadReply.status.code).to.equal(200); - expect(recordsReadReply.record?.data).to.exist; - const dataFromReply = await DataStream.toBytes(recordsReadReply.record!.data); + expect(recordsReadReply.data).to.exist; + const dataFromReply = await DataStream.toBytes(recordsReadReply.data!); expect(dataFromReply).to.eql(bobFooNewBytes); // 5. Carol creates a `foo` by invoking the user role. @@ -350,8 +350,8 @@ export function testProtocolUpdateAction(): void { }); const bobBarReadReply = await dwn.processMessage(alice.did, bobBarRead.message); expect(bobBarReadReply.status.code).to.equal(200); - expect(bobBarReadReply.record?.data).to.exist; - const dataFromBobBarRead = await DataStream.toBytes(bobBarReadReply.record!.data); + expect(bobBarReadReply.data).to.exist; + const dataFromBobBarRead = await DataStream.toBytes(bobBarReadReply.data!); expect(dataFromBobBarRead).to.eql(bobBarNewBytes); // 7. Verify that Bob cannot update Carol's `bar`. @@ -423,8 +423,8 @@ export function testProtocolUpdateAction(): void { }); const bobBazReadReply = await dwn.processMessage(alice.did, bobBazRead.message); expect(bobBazReadReply.status.code).to.equal(200); - expect(bobBazReadReply.record?.data).to.exist; - const dataFromBobBazRead = await DataStream.toBytes(bobBazReadReply.record!.data); + expect(bobBazReadReply.data).to.exist; + const dataFromBobBazRead = await DataStream.toBytes(bobBazReadReply.data!); expect(dataFromBobBazRead).to.eql(bobBazNewBytes); // 11. Verify that Bob cannot update Carol's `baz` @@ -534,8 +534,8 @@ export function testProtocolUpdateAction(): void { }); const bobFooReadReply = await dwn.processMessage(alice.did, bobBarRead.message); expect(bobFooReadReply.status.code).to.equal(200); - expect(bobFooReadReply.record?.data).to.exist; - const dataFromBobFooRead = await DataStream.toBytes(bobFooReadReply.record!.data); + expect(bobFooReadReply.data).to.exist; + const dataFromBobFooRead = await DataStream.toBytes(bobFooReadReply.data!); expect(dataFromBobFooRead).to.eql(bobFooNewBytes); // 5. Verify that Bob cannot update Carol's `foo`. diff --git a/tests/features/records-tags.spec.ts b/tests/features/records-tags.spec.ts index e6a8ea717..05d5bcaa3 100644 --- a/tests/features/records-tags.spec.ts +++ b/tests/features/records-tags.spec.ts @@ -2079,8 +2079,9 @@ export function testRecordsTags(): void { const tagsRecord1ReadReply = await dwn.processMessage(alice.did, tagsRecord1Read.message); expect(tagsRecord1ReadReply.status.code).to.equal(200); - expect(tagsRecord1ReadReply.record).to.not.be.undefined; - expect(tagsRecord1ReadReply.record!.descriptor.tags).to.deep.equal({ stringTag, numberTag, booleanTag, stringArrayTag, numberArrayTag }); + expect(tagsRecord1ReadReply.recordsWrite).to.not.be.undefined; + expect(tagsRecord1ReadReply.recordsWrite!.descriptor.tags) + .to.deep.equal({ stringTag, numberTag, booleanTag, stringArrayTag, numberArrayTag }); }); it('should overwrite tags when updating a Record', async () => { @@ -2113,8 +2114,8 @@ export function testRecordsTags(): void { const tagsRecord1ReadReply = await dwn.processMessage(alice.did, tagsRecord1Read.message); expect(tagsRecord1ReadReply.status.code).to.equal(200); - expect(tagsRecord1ReadReply.record).to.not.be.undefined; - expect(tagsRecord1ReadReply.record!.descriptor.tags).to.deep.equal({ + expect(tagsRecord1ReadReply.recordsWrite).to.not.be.undefined; + expect(tagsRecord1ReadReply.recordsWrite!.descriptor.tags).to.deep.equal({ stringTag : 'string-value', numberTag : 54566975, booleanTag : false, @@ -2148,8 +2149,8 @@ export function testRecordsTags(): void { const updatedRecordReadReply = await dwn.processMessage(alice.did, tagsRecord1Read.message); expect(updatedRecordReadReply.status.code).to.equal(200); - expect(updatedRecordReadReply.record).to.not.be.undefined; - expect(updatedRecordReadReply.record!.descriptor.tags).to.deep.equal({ newTag: 'new-value' }); + expect(updatedRecordReadReply.recordsWrite).to.exist; + expect(updatedRecordReadReply.recordsWrite!.descriptor.tags).to.deep.equal({ newTag: 'new-value' }); // Sanity: Query for the old tag value should return no results const tagsQueryMatchReply2 = await dwn.processMessage(alice.did, tagsQueryMatch.message); diff --git a/tests/features/resumable-tasks.spec.ts b/tests/features/resumable-tasks.spec.ts index ea74e35fc..b47419fda 100644 --- a/tests/features/resumable-tasks.spec.ts +++ b/tests/features/resumable-tasks.spec.ts @@ -138,7 +138,7 @@ export function testResumableTasks(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; + expect(readReply.recordsWrite).to.exist; // 3. Restart the DWN to trigger the resumable task to be resumed. await dwn.close(); @@ -147,7 +147,7 @@ export function testResumableTasks(): void { // 4. Verify that the record is deleted. const readReply2 = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply2.status.code).to.equal(404); - expect(readReply2.record).to.be.undefined; + expect(readReply2.recordsWrite).to.be.undefined; }); it('should only resume tasks that are timed-out up to the batch size when DWN starts', async () => { diff --git a/tests/handlers/records-delete.spec.ts b/tests/handlers/records-delete.spec.ts index 306ab7bd2..33692d323 100644 --- a/tests/handlers/records-delete.spec.ts +++ b/tests/handlers/records-delete.spec.ts @@ -168,7 +168,7 @@ export function testRecordsDeleteHandler(): void { const aliceRead1Reply = await dwn.processMessage(alice.did, aliceRead1.message); expect(aliceRead1Reply.status.code).to.equal(200); - const aliceDataFetched = await DataStream.toBytes(aliceRead1Reply.record!.data!); + const aliceDataFetched = await DataStream.toBytes(aliceRead1Reply.data!); expect(ArrayUtility.byteArraysEqual(aliceDataFetched, data)).to.be.true; // alice deletes the other record @@ -194,7 +194,7 @@ export function testRecordsDeleteHandler(): void { const bobRead1Reply = await dwn.processMessage(bob.did, bobRead1.message); expect(bobRead1Reply.status.code).to.equal(200); - const bobDataFetched = await DataStream.toBytes(bobRead1Reply.record!.data!); + const bobDataFetched = await DataStream.toBytes(bobRead1Reply.data!); expect(ArrayUtility.byteArraysEqual(bobDataFetched, data)).to.be.true; }); diff --git a/tests/handlers/records-read.spec.ts b/tests/handlers/records-read.spec.ts index 092be215a..0230ce60e 100644 --- a/tests/handlers/records-read.spec.ts +++ b/tests/handlers/records-read.spec.ts @@ -98,11 +98,11 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; - expect(readReply.record?.authorization).to.deep.equal(message.authorization); - expect(readReply.record?.descriptor).to.deep.equal(message.descriptor); + expect(readReply.recordsWrite).to.exist; + expect(readReply.recordsWrite?.authorization).to.deep.equal(message.authorization); + expect(readReply.recordsWrite?.descriptor).to.deep.equal(message.descriptor); - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); @@ -147,7 +147,7 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); @@ -172,7 +172,7 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); @@ -198,10 +198,10 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; - expect(readReply.record?.descriptor).to.exist; + expect(readReply.recordsWrite).to.exist; + expect(readReply.recordsWrite?.descriptor).to.exist; - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; }); @@ -253,10 +253,10 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - expect(readReply.record).to.exist; - expect(readReply.record?.descriptor).to.exist; + expect(readReply.recordsWrite).to.exist; + expect(readReply.recordsWrite?.descriptor).to.exist; - const dataFetched = await DataStream.toBytes(readReply.record!.data!); + const dataFetched = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(dataFetched, dataBytes!)).to.be.true; // carol attempts to read Bob's record @@ -288,8 +288,8 @@ export function testRecordsReadHandler(): void { const reply = await dwn.processMessage(alice.did, messageData.message); expect(reply.status.code).to.equal(200); - expect(reply.record?.initialWrite).to.exist; - expect(reply.record?.initialWrite?.recordId).to.equal(write.message.recordId); + expect(reply.initialWrite).to.exist; + expect(reply.initialWrite?.recordId).to.equal(write.message.recordId); }); @@ -520,7 +520,7 @@ export function testRecordsReadHandler(): void { const fooPathReply = await dwn.processMessage(alice.did, fooPathRead.message); expect(fooPathReply.status.code).to.equal(200); - expect(fooPathReply.record!.recordId).to.equal(foo1Write.message.recordId); + expect(fooPathReply.recordsWrite!.recordId).to.equal(foo1Write.message.recordId); }); it('should throw if requested filter has more than a single result', async () => { @@ -768,7 +768,7 @@ export function testRecordsReadHandler(): void { const threadRead = await RecordsRead.create({ signer : Jws.createSigner(bob), filter : { - recordId: participantReadReply.record!.descriptor.parentId, + recordId: participantReadReply.recordsWrite!.descriptor.parentId, }, protocolRole: 'thread/participant' }); @@ -1436,11 +1436,11 @@ export function testRecordsReadHandler(): void { const recordsReadResponse = await dwn.processMessage(alice.did, recordRead.message); expect(recordsReadResponse.status.code).to.equal(200); - expect(recordsReadResponse.record).to.exist; - expect(recordsReadResponse.record!.data).to.exist; + expect(recordsReadResponse.recordsWrite).to.exist; + expect(recordsReadResponse.data!).to.exist; sinon.assert.notCalled(dataStoreGet); - const readData = await DataStream.toBytes(recordsReadResponse.record!.data); + const readData = await DataStream.toBytes(recordsReadResponse.data!); expect(readData).to.eql(dataBytes); }); @@ -1467,11 +1467,11 @@ export function testRecordsReadHandler(): void { const recordsReadResponse = await dwn.processMessage(alice.did, recordRead.message); expect(recordsReadResponse.status.code).to.equal(200); - expect(recordsReadResponse.record).to.exist; - expect(recordsReadResponse.record!.data).to.exist; + expect(recordsReadResponse.recordsWrite).to.exist; + expect(recordsReadResponse.data!).to.exist; sinon.assert.calledOnce(dataStoreGet); - const readData = await DataStream.toBytes(recordsReadResponse.record!.data); + const readData = await DataStream.toBytes(recordsReadResponse.data!); expect(readData).to.eql(dataBytes); }); }); @@ -1550,8 +1550,8 @@ export function testRecordsReadHandler(): void { // test able to derive correct key using `schemas` scheme from root key to decrypt the message const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - const recordsWriteMessage = readReply.record!; - const cipherStream = readReply.record!.data; + const recordsWriteMessage = readReply.recordsWrite!; + const cipherStream = readReply.data!; const plaintextDataStream = await Records.decrypt(recordsWriteMessage, schemaDerivedPrivateKey, cipherStream); const plaintextBytes = await DataStream.toBytes(plaintextDataStream); @@ -1561,7 +1561,7 @@ export function testRecordsReadHandler(): void { // test able to derive correct key using `dataFormat` scheme from root key to decrypt the message const readReply2 = await dwn.processMessage(alice.did, recordsRead.message); // send the same read message to get a new cipher stream expect(readReply2.status.code).to.equal(200); - const cipherStream2 = readReply2.record!.data; + const cipherStream2 = readReply2.data!; const plaintextDataStream2 = await Records.decrypt(recordsWriteMessage, rootPrivateKeyWithDataFormatsScheme, cipherStream2); const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2); @@ -1571,7 +1571,7 @@ export function testRecordsReadHandler(): void { // test unable to decrypt the message if dataFormat-derived key is derived without taking `schema` as input to derivation path const readReply3 = await dwn.processMessage(alice.did, recordsRead.message); // process the same read message to get a new cipher stream expect(readReply3.status.code).to.equal(200); - const cipherStream3 = readReply3.record!.data; + const cipherStream3 = readReply3.data!; const invalidDerivationPath = [KeyDerivationScheme.DataFormats, message.descriptor.dataFormat]; const inValidDescendantPrivateKey: DerivedPrivateJwk @@ -1639,8 +1639,8 @@ export function testRecordsReadHandler(): void { // test able to derive correct key using `dataFormat` scheme from root key to decrypt the message const readReply = await dwn.processMessage(alice.did, recordsRead.message); // send the same read message to get a new cipher stream expect(readReply.status.code).to.equal(200); - const cipherStream = readReply.record!.data; - const recordsWriteMessage = readReply.record!; + const cipherStream = readReply.data!; + const recordsWriteMessage = readReply.recordsWrite!; const plaintextDataStream = await Records.decrypt(recordsWriteMessage, rootPrivateKeyWithDataFormatsScheme, cipherStream); const plaintextBytes = await DataStream.toBytes(plaintextDataStream); @@ -1756,8 +1756,8 @@ export function testRecordsReadHandler(): void { const readReply = await dwn.processMessage(alice.did, recordsRead.message); expect(readReply.status.code).to.equal(200); - const fetchedRecordsWrite = readReply.record!; - const cipherStream = readReply.record!.data; + const fetchedRecordsWrite = readReply.recordsWrite!; + const cipherStream = readReply.data!; const derivationPathFromReadContext = Records.constructKeyDerivationPathUsingProtocolContextScheme(fetchedRecordsWrite.contextId); const protocolContextDerivedPrivateJwk = await HdKey.derivePrivateKey(bobRootPrivateKey, derivationPathFromReadContext); @@ -1799,8 +1799,8 @@ export function testRecordsReadHandler(): void { const readByBobReply = await dwn.processMessage(bob.did, recordsReadByBob.message); expect(readByBobReply.status.code).to.equal(200); - const fetchedRecordsWrite2 = readByBobReply.record!; - const cipherStream2 = readByBobReply.record!.data; + const fetchedRecordsWrite2 = readByBobReply.recordsWrite!; + const cipherStream2 = readByBobReply.data!; const plaintextDataStream2 = await Records.decrypt(fetchedRecordsWrite2, protocolContextDerivedPrivateJwk, cipherStream2); const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2); @@ -1897,8 +1897,8 @@ export function testRecordsReadHandler(): void { derivedPrivateKey : alice.keyPair.privateJwk }; - const fetchedRecordsWrite = readReply.record!; - const cipherStream = readReply.record!.data; + const fetchedRecordsWrite = readReply.recordsWrite!; + const cipherStream = readReply.data!; const plaintextDataStream = await Records.decrypt(fetchedRecordsWrite, rootPrivateKey, cipherStream); const plaintextBytes = await DataStream.toBytes(plaintextDataStream); @@ -1911,8 +1911,8 @@ export function testRecordsReadHandler(): void { const relativeDescendantDerivationPath = Records.constructKeyDerivationPath(KeyDerivationScheme.ProtocolPath, fetchedRecordsWrite); const derivedPrivateKey: DerivedPrivateJwk = await HdKey.derivePrivateKey(rootPrivateKey, relativeDescendantDerivationPath); - const fetchedRecordsWrite2 = readReply2.record!; - const cipherStream2 = readReply2.record!.data; + const fetchedRecordsWrite2 = readReply2.recordsWrite!; + const cipherStream2 = readReply2.data!; const plaintextDataStream2 = await Records.decrypt(fetchedRecordsWrite2, derivedPrivateKey, cipherStream2); const plaintextBytes2 = await DataStream.toBytes(plaintextDataStream2); expect(ArrayUtility.byteArraysEqual(plaintextBytes2, bobMessageBytes)).to.be.true; diff --git a/tests/handlers/records-write.spec.ts b/tests/handlers/records-write.spec.ts index 1d18daaf8..8fbd4b7e2 100644 --- a/tests/handlers/records-write.spec.ts +++ b/tests/handlers/records-write.spec.ts @@ -287,7 +287,7 @@ export function testRecordsWriteHandler(): void { }); const recordsReadReply = await dwn.processMessage(tenant, recordsRead.message); expect(recordsReadReply.status.code).to.equal(200); - expect(recordsReadReply.record?.descriptor.dataFormat).to.equal(newDataFormat); + expect(recordsReadReply.recordsWrite?.descriptor.dataFormat).to.equal(newDataFormat); }); it('should not allow changes to immutable properties', async () => { @@ -359,8 +359,8 @@ export function testRecordsWriteHandler(): void { const readMessageReply = await dwn.processMessage(tenant, readMessage.message); expect(readMessageReply.status.code).to.equal(200); - expect(readMessageReply.record).to.exist; - const data = await DataStream.toBytes(readMessageReply.record!.data); + expect(readMessageReply.recordsWrite).to.exist; + const data = await DataStream.toBytes(readMessageReply.data!); expect(data).to.eql(dataBytes); }); @@ -478,8 +478,8 @@ export function testRecordsWriteHandler(): void { const readMessageReply = await dwn.processMessage(tenant, readMessage.message); expect(readMessageReply.status.code).to.equal(200); - expect(readMessageReply.record).to.exist; - const data = await DataStream.toBytes(readMessageReply.record!.data); + expect(readMessageReply.recordsWrite).to.exist; + const data = await DataStream.toBytes(readMessageReply.data!); expect(data).to.eql(dataBytes); }); @@ -511,8 +511,8 @@ export function testRecordsWriteHandler(): void { const readMessageReply = await dwn.processMessage(tenant, readMessage.message); expect(readMessageReply.status.code).to.equal(200); - expect(readMessageReply.record).to.exist; - const data = await DataStream.toBytes(readMessageReply.record!.data); + expect(readMessageReply.recordsWrite).to.exist; + const data = await DataStream.toBytes(readMessageReply.data!); expect(data).to.eql(dataBytes); }); }); @@ -736,7 +736,7 @@ export function testRecordsWriteHandler(): void { const readReply = await dwn.processMessage(alice.did, read.message); expect(readReply.status.code).to.equal(200); - const readDataBytes = await DataStream.toBytes(readReply.record!.data!); + const readDataBytes = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(readDataBytes, write2.dataBytes!)).to.be.true; }); @@ -790,7 +790,7 @@ export function testRecordsWriteHandler(): void { const readReply = await dwn.processMessage(alice.did, read.message); expect(readReply.status.code).to.equal(200); - const readDataBytes = await DataStream.toBytes(readReply.record!.data!); + const readDataBytes = await DataStream.toBytes(readReply.data!); expect(ArrayUtility.byteArraysEqual(readDataBytes, write2.dataBytes!)).to.be.true; }); @@ -2505,7 +2505,7 @@ export function testRecordsWriteHandler(): void { }); const recordsReadReply = await dwn.processMessage(alice.did, recordsRead.message); expect(recordsReadReply.status.code).to.equal(200); - expect(recordsReadReply.record?.descriptor.dataFormat).to.equal(protocolDefinition.types.image.dataFormats[1]); + expect(recordsReadReply.recordsWrite?.descriptor.dataFormat).to.equal(protocolDefinition.types.image.dataFormats[1]); }); it('#690 - should allow any data format for a record if protocol definition does not explicitly specify the list of allowed data formats', async () => { @@ -2557,7 +2557,7 @@ export function testRecordsWriteHandler(): void { }); const recordsReadReply = await dwn.processMessage(alice.did, recordsRead.message); expect(recordsReadReply.status.code).to.equal(200); - expect(recordsReadReply.record?.descriptor.dataFormat).to.equal(newDataFormat); + expect(recordsReadReply.recordsWrite?.descriptor.dataFormat).to.equal(newDataFormat); }); it('should fail authorization if record schema is not allowed at the hierarchical level attempted for the RecordsWrite', async () => { diff --git a/tests/scenarios/deleted-record.spec.ts b/tests/scenarios/deleted-record.spec.ts index 159b43354..69c25c405 100644 --- a/tests/scenarios/deleted-record.spec.ts +++ b/tests/scenarios/deleted-record.spec.ts @@ -108,8 +108,8 @@ export function testDeletedRecordScenarios(): void { // Expected outcome: Alice should get a 404 error with the reply containing the deleted record and the initial write of the record. expect(readReply.status.code).to.equal(404); - expect(readReply.delete).to.exist; - expect(readReply.delete).to.deep.equal(recordsDelete.message); + expect(readReply.recordsDelete).to.exist; + expect(readReply.recordsDelete).to.deep.equal(recordsDelete.message); expect(readReply.initialWrite).to.exist; expect(readReply.initialWrite).to.deep.equal(recordsWriteMessage); }); diff --git a/tests/scenarios/end-to-end-tests.spec.ts b/tests/scenarios/end-to-end-tests.spec.ts index d4caa2c84..ac9d0b5f4 100644 --- a/tests/scenarios/end-to-end-tests.spec.ts +++ b/tests/scenarios/end-to-end-tests.spec.ts @@ -201,7 +201,7 @@ export function testEndToEndScenarios(): void { }); const threadReadReply = await dwn.processMessage(alice.did, threadRead.message) as RecordsReadReply; expect(threadReadReply.status.code).to.equal(200); - expect(threadReadReply.record).to.exist; + expect(threadReadReply.recordsWrite).to.exist; // Test Bob can invoke his 'participant' role to read the chat message // TODO: #555 - We currently lack role-authorized RecordsQuery for a realistic scenario (https://github.com/TBD54566975/dwn-sdk-js/issues/555) @@ -215,7 +215,7 @@ export function testEndToEndScenarios(): void { }); const chatReadReply = await dwn.processMessage(alice.did, chatRead.message) as RecordsReadReply; expect(chatReadReply.status.code).to.equal(200); - expect(chatReadReply.record).to.exist; + expect(chatReadReply.recordsWrite).to.exist; // 7. Bob is able to decrypt all thread content // Bob decrypts the participant message to obtain the context-derived private key @@ -224,12 +224,12 @@ export function testEndToEndScenarios(): void { derivationScheme : KeyDerivationScheme.ProtocolPath, derivedPrivateKey : bob.keyPair.privateJwk }; - const participantRecordFetched = participantReadReply.record!; - const encryptedContextDerivedPrivateKeyBytes = await DataStream.toBytes(participantRecordFetched.data); // to create streams for testing - const derivationPathFromProtocolPath = Records.constructKeyDerivationPathUsingProtocolPathScheme(participantRecordFetched.descriptor); + const participantRecordWriteFetched = participantReadReply.recordsWrite!; + const encryptedContextDerivedPrivateKeyBytes = await DataStream.toBytes(participantReadReply.data!); // to create streams for testing + const derivationPathFromProtocolPath = Records.constructKeyDerivationPathUsingProtocolPathScheme(participantRecordWriteFetched.descriptor); const bobProtocolPathDerivedPrivateKey = await HdKey.derivePrivateKey(bobRootKey, derivationPathFromProtocolPath); const decryptedContextDerivedKeyStream = await Records.decrypt( - participantRecordFetched, + participantRecordWriteFetched, bobProtocolPathDerivedPrivateKey, DataStream.fromBytes(encryptedContextDerivedPrivateKeyBytes) ); @@ -238,7 +238,7 @@ export function testEndToEndScenarios(): void { // Arguably unrelated to the scenario, but let's sanity check that Bob's root key can also decrypt the encrypted context-derived private key const decryptedContextDerivedKeyStream2 = await Records.decrypt( - participantRecordFetched, + participantRecordWriteFetched, bobRootKey, DataStream.fromBytes(encryptedContextDerivedPrivateKeyBytes) ); @@ -247,16 +247,16 @@ export function testEndToEndScenarios(): void { // Verify that Bob can now decrypt Alice's chat thread record using the decrypted context-derived key const decryptedChatThread = await Records.decrypt( - threadReadReply.record!, + threadReadReply.recordsWrite!, decryptedContextDerivedPrivateKey, - threadReadReply.record!.data + threadReadReply.data! ); expect(await DataStream.toBytes(decryptedChatThread)).to.deep.equal(threadBytes); // Verify that Bob can now decrypt Alice's chat message using the decrypted context-derived key - const encryptedChatMessageBytes = await DataStream.toBytes(chatReadReply.record!.data); // to create streams for testing + const encryptedChatMessageBytes = await DataStream.toBytes(chatReadReply.data!); // to create streams for testing const decryptedChatMessage = await Records.decrypt( - chatReadReply.record!, + chatReadReply.recordsWrite!, decryptedContextDerivedPrivateKey, DataStream.fromBytes(encryptedChatMessageBytes) ); @@ -264,7 +264,7 @@ export function testEndToEndScenarios(): void { // Arguably unrelated to the scenario, but let's also sanity check that Alice's root key can also decrypt the encrypted chat message const decryptedChatMessageStream2 = await Records.decrypt( - chatReadReply.record!, + chatReadReply.recordsWrite!, aliceRootKey, DataStream.fromBytes(encryptedChatMessageBytes) ); diff --git a/tests/scenarios/nested-roles.spec.ts b/tests/scenarios/nested-roles.spec.ts index a40ce4b6a..62e59975c 100644 --- a/tests/scenarios/nested-roles.spec.ts +++ b/tests/scenarios/nested-roles.spec.ts @@ -129,7 +129,7 @@ export function testNestedRoleScenarios(): void { }); const bobCommunityReadReply = await dwn.processMessage(alice.did, bobCommunityRead.message); expect(bobCommunityReadReply.status.code).to.equal(200); - expect(bobCommunityReadReply.record?.recordId).to.equal(communityRecord.message.recordId); + expect(bobCommunityReadReply.recordsWrite?.recordId).to.equal(communityRecord.message.recordId); // 4b. Bob can create gated-channels 1 & 2 in the community const channel1Record = await TestDataGenerator.generateRecordsWrite({ @@ -225,7 +225,7 @@ export function testNestedRoleScenarios(): void { }); const carolReadReply = await dwn.processMessage(alice.did, carolRead.message); expect(carolReadReply.status.code).to.equal(200); - expect(carolReadReply.record?.recordId).to.equal(channel1Record.message.recordId); + expect(carolReadReply.recordsWrite?.recordId).to.equal(channel1Record.message.recordId); // 7. Carol CANNOT add anyone as a participant in the gated-channel 2 since she is not a participant in the channel const participantCarolRecord = await TestDataGenerator.generateRecordsWrite({