Skip to content

Commit 43a5078

Browse files
authored
differentiate between Record creator and author (#893)
Add a property to the `Record` class that denotes the record's `creator`. When the record is an initial write, the `creator` and `author` will return the same. Created this issue to add query/filter for creator: decentralized-identity/dwn-sdk-js#800
1 parent 2ec2d21 commit 43a5078

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

.changeset/brown-experts-lay.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@web5/api": patch
3+
---
4+
5+
differentiate between Record creator and author

packages/api/src/record.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,10 @@ export class Record implements RecordModel {
227227

228228
// Private variables for DWN `RecordsWrite` message properties.
229229

230-
/** The DID of the entity that authored the record. */
230+
/** The DID of the entity that most recently authored or deleted the record. */
231231
private _author: string;
232+
/** The DID of the entity that originally created the record. */
233+
private _creator: string;
232234
/** Attestation JWS signature. */
233235
private _attestation?: DwnMessage[DwnInterface.RecordsWrite]['attestation'];
234236
/** Authorization signature(s). */
@@ -314,6 +316,9 @@ export class Record implements RecordModel {
314316
/** DID that is the logical author of the Record. */
315317
get author(): string { return this._author; }
316318

319+
/** DID that is the original creator of the Record. */
320+
get creator(): string { return this._creator; }
321+
317322
/** Record's modified date */
318323
get dateModified() { return this._descriptor.messageTimestamp; }
319324

@@ -368,6 +373,8 @@ export class Record implements RecordModel {
368373
// Store the author DID that originally signed the message as a convenience for developers, so
369374
// that they don't have to decode the signer's DID from the JWS.
370375
this._author = options.author;
376+
// The creator is the author of the initial write, or the author of the record if there is no initial write.
377+
this._creator = options.initialWrite ? getRecordAuthor(options.initialWrite) : options.author;
371378

372379
// Store the `connectedDid`, and optionally the `delegateDid` and `permissionsApi` in order to be able
373380
// to perform operations on the record (update, delete, data) as a delegate of the connected DID.

packages/api/tests/record.spec.ts

+103
Original file line numberDiff line numberDiff line change
@@ -2403,6 +2403,51 @@ describe('Record', () => {
24032403
});
24042404

24052405
describe('update()', () => {
2406+
let notesProtocol: DwnProtocolDefinition;
2407+
2408+
beforeEach(async () => {
2409+
const protocolUri = `http://example.com/notes-${TestDataGenerator.randomString(15)}`;
2410+
2411+
notesProtocol = {
2412+
published : true,
2413+
protocol : protocolUri,
2414+
types : {
2415+
note: {
2416+
schema: 'http://example.com/note'
2417+
},
2418+
request: {
2419+
schema: 'http://example.com/request'
2420+
}
2421+
},
2422+
structure: {
2423+
request: {
2424+
$actions: [{
2425+
who : 'anyone',
2426+
can : ['create', 'update', 'delete']
2427+
},{
2428+
who : 'recipient',
2429+
of : 'request',
2430+
can : ['co-update']
2431+
}]
2432+
},
2433+
note: {
2434+
}
2435+
}
2436+
};
2437+
2438+
// alice and bob both configure the protocol
2439+
const { status: aliceConfigStatus, protocol: aliceNotesProtocol } = await dwnAlice.protocols.configure({ message: { definition: notesProtocol } });
2440+
expect(aliceConfigStatus.code).to.equal(202);
2441+
const { status: aliceNotesProtocolSend } = await aliceNotesProtocol.send(aliceDid.uri);
2442+
expect(aliceNotesProtocolSend.code).to.equal(202);
2443+
2444+
const { status: bobConfigStatus, protocol: bobNotesProtocol } = await dwnBob.protocols.configure({ message: { definition: notesProtocol } });
2445+
expect(bobConfigStatus.code).to.equal(202);
2446+
const { status: bobNotesProtocolSend } = await bobNotesProtocol!.send(bobDid.uri);
2447+
expect(bobNotesProtocolSend.code).to.equal(202);
2448+
2449+
});
2450+
24062451
it('updates a local record on the local DWN', async () => {
24072452
const { status, record } = await dwnAlice.records.write({
24082453
data : 'Hello, world!',
@@ -2906,6 +2951,64 @@ describe('Record', () => {
29062951
expect(record.dataFormat).to.equal('application/json');
29072952
expect(await record.data.json()).to.deep.equal({ subject: 'another subject', body: 'another body' });
29082953
});
2954+
2955+
it('differentiates between creator and author', async () => {
2956+
const { status, record } = await dwnAlice.records.write({
2957+
data : 'Hello, Bob!',
2958+
message : {
2959+
recipient : bobDid.uri,
2960+
protocol : notesProtocol.protocol,
2961+
protocolPath : 'request',
2962+
schema : notesProtocol.types.request.schema,
2963+
}
2964+
});
2965+
expect(status.code).to.equal(202, 'create');
2966+
expect(record).to.not.be.undefined;
2967+
const { status: sendStatus } = await record.send();
2968+
expect(sendStatus.code).to.equal(202, 'send');
2969+
2970+
// bob reads the record
2971+
const readResult = await dwnBob.records.read({
2972+
protocol : notesProtocol.protocol,
2973+
from : aliceDid.uri,
2974+
message : {
2975+
filter: {
2976+
recordId: record.id
2977+
}
2978+
}
2979+
});
2980+
expect(readResult.status.code).to.equal(200, 'bob reads record');
2981+
expect(readResult.record).to.not.be.undefined;
2982+
2983+
const bobRecord = readResult.record;
2984+
const { status: storeStatus } = await bobRecord!.store();
2985+
expect(storeStatus.code).to.equal(202, 'store');
2986+
const { status: updateStatus } = await bobRecord.update({ data: 'Hello, Alice!' });
2987+
expect(updateStatus.code).to.equal(202, 'update');
2988+
2989+
const updatedData = await bobRecord.send(aliceDid.uri);
2990+
expect(updatedData.status.code).to.equal(202, 'send update');
2991+
2992+
// alice reads the record
2993+
const readResultAlice = await dwnAlice.records.read({
2994+
from : aliceDid.uri,
2995+
protocol : notesProtocol.protocol,
2996+
message : {
2997+
filter: {
2998+
recordId: record.id
2999+
}
3000+
}
3001+
});
3002+
3003+
expect(readResultAlice.status.code).to.equal(200, 'alice reads record');
3004+
expect(readResultAlice.record).to.not.be.undefined;
3005+
expect(await readResultAlice.record!.data.text()).to.equal('Hello, Alice!');
3006+
3007+
// alice is the creator
3008+
expect(readResultAlice.record!.creator).to.equal(aliceDid.uri);
3009+
// bob is the author
3010+
expect(readResultAlice.record!.author).to.equal(bobDid.uri);
3011+
});
29093012
});
29103013

29113014
describe('delete()', () => {

0 commit comments

Comments
 (0)