Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion json-schemas/definitions.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"did": {
"type": "string",
"pattern": "^did:([a-z0-9]+):((?:(?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))*:)*((?:[a-zA-Z0-9._-]|(?:%[0-9a-fA-F]{2}))+))((;[a-zA-Z0-9_.:%-]+=[a-zA-Z0-9_.:%-]*)*)(\/[^#?]*)?([?][^#]*)?(#.*)?$"
},
"date-time": {
"type": "string",
"pattern": "^\\d{4}-[0-1]\\d-[0-3]\\dT(?:[0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.\\d{6}Z$"
}
}
}
}
2 changes: 1 addition & 1 deletion json-schemas/hooks/hooks-write.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"type": "string"
},
"dateCreated": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"schema": {
"type": "string"
Expand Down
6 changes: 3 additions & 3 deletions json-schemas/records/records-query.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"type": "string"
},
"dateCreated": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"filter": {
"type": "object",
Expand Down Expand Up @@ -71,10 +71,10 @@
"additionalProperties": false,
"properties": {
"from": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"to": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions json-schemas/records/records-write.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@
"type": "number"
},
"dateCreated": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"dateModified": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"published": {
"type": "boolean"
},
"datePublished": {
"type": "string"
"$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time"
},
"dataFormat": {
"type": "string"
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tbd54566975/dwn-sdk-js",
"version": "0.0.30",
"version": "0.0.31",
"description": "A reference implementation of https://identity.foundation/decentralized-web-node/spec/",
"type": "module",
"types": "./dist/esm/src/index.d.ts",
Expand Down Expand Up @@ -60,7 +60,7 @@
"@types/readable-stream": "2.3.15",
"@types/secp256k1": "4.0.3",
"abstract-level": "1.0.3",
"ajv": "8.11.0",
"ajv": "8.12.0",
"blockstore-core": "3.0.0",
"cross-fetch": "3.1.5",
"date-fns": "2.28.0",
Expand Down Expand Up @@ -143,4 +143,4 @@
"url": "https://github.com/TBD54566975/dwn-sdk-js/issues"
},
"homepage": "https://github.com/TBD54566975/dwn-sdk-js#readme"
}
}
29 changes: 17 additions & 12 deletions tests/interfaces/records/handlers/records-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ import { Message } from '../../../../src/core/message.js';
import { MessageStoreLevel } from '../../../../src/store/message-store-level.js';
import { RecordsQueryHandler } from '../../../../src/interfaces/records/handlers/records-query.js';
import { StorageController } from '../../../../src/store/storage-controller.js';
import { Temporal } from '@js-temporal/polyfill';
import { TestDataGenerator } from '../../../utils/test-data-generator.js';
import { TestStubGenerator } from '../../../utils/test-stub-generator.js';
import { toTemporalInstant } from '@js-temporal/polyfill';

import { constructRecordsWriteIndexes } from '../../../../src/interfaces/records/handlers/records-write.js';
import { DataStream, DidResolver, Dwn, HdKey, KeyDerivationScheme, Records } from '../../../../src/index.js';
import { DateSort, RecordsQuery } from '../../../../src/interfaces/records/messages/records-query.js';

chai.use(chaiAsPromised);

function createDateString(d: Date): string {
return toTemporalInstant.call(d).toString({ smallestUnit: 'microseconds' });
}

describe('RecordsQueryHandler.handle()', () => {
describe('functional tests', () => {
let didResolver: DidResolver;
Expand Down Expand Up @@ -183,11 +187,12 @@ describe('RecordsQueryHandler.handle()', () => {
expect(reply3.entries?.length).to.equal(0);
});


it('should be able to range query by `dateCreated`', async () => {
// scenario: 3 records authored by alice, created on first of 2021, 2022, and 2023 respectively, only the first 2 records share the same schema
const firstDayOf2021 = Temporal.PlainDateTime.from({ year: 2021, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2022 = Temporal.PlainDateTime.from({ year: 2022, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2023 = Temporal.PlainDateTime.from({ year: 2023, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2021 = createDateString(new Date(2021, 1, 1));
const firstDayOf2022 = createDateString(new Date(2022, 1, 1));
const firstDayOf2023 = createDateString(new Date(2023, 1, 1));
const alice = await DidKeyResolver.generate();
const write1 = await TestDataGenerator.generateRecordsWrite({ requester: alice, dateCreated: firstDayOf2021, dateModified: firstDayOf2021 });
const write2 = await TestDataGenerator.generateRecordsWrite({ requester: alice, dateCreated: firstDayOf2022, dateModified: firstDayOf2022 });
Expand All @@ -202,7 +207,7 @@ describe('RecordsQueryHandler.handle()', () => {
expect(writeReply3.status.code).to.equal(202);

// testing `from` range
const lastDayOf2021 = Temporal.PlainDateTime.from({ year: 2021, month: 12, day: 31 }).toString({ smallestUnit: 'microseconds' });
const lastDayOf2021 = createDateString(new Date(2021, 12, 31));
const recordsQuery1 = await TestDataGenerator.generateRecordsQuery({
requester : alice,
filter : { dateCreated: { from: lastDayOf2021 } },
Expand All @@ -214,7 +219,7 @@ describe('RecordsQueryHandler.handle()', () => {
expect(reply1.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write3.dataBytes!));

// testing `to` range
const lastDayOf2022 = Temporal.PlainDateTime.from({ year: 2022, month: 12, day: 31 }).toString({ smallestUnit: 'microseconds' });
const lastDayOf2022 = createDateString(new Date(2022, 12, 31));
const recordsQuery2 = await TestDataGenerator.generateRecordsQuery({
requester : alice,
filter : { dateCreated: { to: lastDayOf2022 } },
Expand All @@ -226,7 +231,7 @@ describe('RecordsQueryHandler.handle()', () => {
expect(reply2.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write2.dataBytes!));

// testing `from` and `to` range
const lastDayOf2023 = Temporal.PlainDateTime.from({ year: 2023, month: 12, day: 31 }).toString({ smallestUnit: 'microseconds' });
const lastDayOf2023 = createDateString(new Date(2023, 12, 31));
const recordsQuery3 = await TestDataGenerator.generateRecordsQuery({
requester : alice,
filter : { dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } },
Expand All @@ -249,9 +254,9 @@ describe('RecordsQueryHandler.handle()', () => {

it('should be able use range and exact match queries at the same time', async () => {
// scenario: 3 records authored by alice, created on first of 2021, 2022, and 2023 respectively, only the first 2 records share the same schema
const firstDayOf2021 = Temporal.PlainDateTime.from({ year: 2021, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2022 = Temporal.PlainDateTime.from({ year: 2022, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2023 = Temporal.PlainDateTime.from({ year: 2023, month: 1, day: 1 }).toString({ smallestUnit: 'microseconds' });
const firstDayOf2021 = createDateString(new Date(2021, 1, 1));
const firstDayOf2022 = createDateString(new Date(2022, 1, 1));
const firstDayOf2023 = createDateString(new Date(2023, 1, 1));
const alice = await DidKeyResolver.generate();
const schema = '2021And2022Schema';
const write1 = await TestDataGenerator.generateRecordsWrite({
Expand All @@ -273,8 +278,8 @@ describe('RecordsQueryHandler.handle()', () => {
expect(writeReply3.status.code).to.equal(202);

// testing range criterion with another exact match
const lastDayOf2021 = Temporal.PlainDateTime.from({ year: 2021, month: 12, day: 31 }).toString({ smallestUnit: 'microseconds' });
const lastDayOf2023 = Temporal.PlainDateTime.from({ year: 2023, month: 12, day: 31 }).toString({ smallestUnit: 'microseconds' });
const lastDayOf2021 = createDateString(new Date(2021, 12, 31));
const lastDayOf2023 = createDateString(new Date(2023, 12, 31));
const recordsQuery5 = await TestDataGenerator.generateRecordsQuery({
requester : alice,
filter : {
Expand Down
2 changes: 1 addition & 1 deletion tests/interfaces/records/handlers/records-write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ describe('RecordsWriteHandler.handle()', () => {

it('should return 400 if `dateCreated` and `dateModified` are not the same in an initial write', async () => {
const { requester, message, dataStream } = await TestDataGenerator.generateRecordsWrite({
dateCreated : '2023-01-10T10:20:30.405060',
dateCreated : '2023-01-10T10:20:30.405060Z',
dateModified : getCurrentTimeInHighPrecision() // this always generate a different timestamp
});
const tenant = requester.did;
Expand Down
2 changes: 1 addition & 1 deletion tests/interfaces/records/messages/records-write.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('RecordsWrite', () => {
recipient : alice.did,
data : TestDataGenerator.randomBytes(10),
dataFormat : 'application/json',
dateCreated : '2022-10-14T10:20:30.405060',
dateCreated : '2022-10-14T10:20:30.405060Z',
recordId : await TestDataGenerator.randomCborSha256Cid(),
authorizationSignatureInput : Jws.createSignatureInput(alice)
};
Expand Down
29 changes: 29 additions & 0 deletions tests/validation/json-schemas/definitions.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Ajv from 'ajv';
import definitions from '../../../json-schemas/definitions.json' assert { type: 'json' };

import { expect } from 'chai';

describe('date-time schema', async () => {

const ajv = new Ajv.default();
const validateDateTime = ajv.compile(definitions.definitions['date-time']);

it('should accept ISO 8601 date-time strings accepted by DWN', () => {
expect(validateDateTime('2022-04-29T10:30:00.123456Z')).to.be.true;
});

it('should reject ISO 8601 date-time strings not accepted by DWN', () => {
const unacceptableDateTimeStrings = [
'2023-04-27T13:30:00.123456',
'2023-04-27T13:30:00.123456z',
'2023-04-27T13:30:00.1234Z',
'2023-04-27T13:30:00Z',
'2023-04-27T13:30:00.000000+00:00',
'2023-04-27 13:30:00.000000Z'
];

for (const dateTime of unacceptableDateTimeStrings) {
expect(validateDateTime(dateTime)).to.be.false;
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('ProtocolsConfigure schema definition', () => {
descriptor: {
interface : 'Protocols',
method : 'Configure',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
protocol : 'anyProtocolUri',
definition : protocolDefinition
},
Expand Down
18 changes: 9 additions & 9 deletions tests/validation/json-schemas/records/records-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' }
},
authorization: {
Expand All @@ -26,7 +26,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' }
}
};
Expand All @@ -41,7 +41,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' }
},
authorization: {
Expand All @@ -64,7 +64,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' },
unknownProperty : 'unknownProperty' // unknown property
},
Expand All @@ -90,7 +90,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' },
dateSort : dateSortValue
},
Expand All @@ -111,7 +111,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { schema: 'anySchema' },
dateSort : 'unacceptable', // bad value
},
Expand All @@ -135,7 +135,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { }
},
authorization: {
Expand All @@ -157,7 +157,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { dateCreated: { } } // empty `dateCreated` criteria
},
authorization: {
Expand All @@ -179,7 +179,7 @@ describe('RecordsQuery schema validation', () => {
descriptor: {
interface : 'Records',
method : 'Query',
dateCreated : '123',
dateCreated : '2022-10-14T10:20:30.405060Z',
filter : { dateCreated: { unexpectedProperty: 'anyValue' } } // unexpected property in `dateCreated` criteria
},
authorization: {
Expand Down
Loading