From 0eac661682dc9517c2506546f6b3247a2d235e8b Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 25 Apr 2023 17:52:07 -0400 Subject: [PATCH 01/11] Specify format: 'date-time' for date properties --- build/compile-validators.js | 5 +++- json-schemas/hooks/hooks-write.json | 3 +- json-schemas/records/records-query.json | 9 ++++-- json-schemas/records/records-write.json | 9 ++++-- package-lock.json | 39 ++++++++++++++++++++----- package.json | 3 +- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/build/compile-validators.js b/build/compile-validators.js index d01b7b800..e9afc66b1 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -14,6 +14,8 @@ import path from 'node:path'; import url from 'node:url'; import Ajv from 'ajv'; +import addFormats from "ajv-formats" + import mkdirp from 'mkdirp'; import standaloneCode from 'ajv/dist/standalone/index.js'; @@ -59,7 +61,8 @@ const schemas = { PublicJwk }; -const ajv = new Ajv({ code: { source: true, esm: true } }); +const ajv = new Ajv({ code: { source: true, esm: true }, allowDate: 'string' }); +addFormats(ajv); for (const schemaName in schemas) { ajv.addSchema(schemas[schemaName], schemaName); diff --git a/json-schemas/hooks/hooks-write.json b/json-schemas/hooks/hooks-write.json index 092657ef4..8a4bf96ae 100644 --- a/json-schemas/hooks/hooks-write.json +++ b/json-schemas/hooks/hooks-write.json @@ -35,7 +35,8 @@ "type": "string" }, "dateCreated": { - "type": "string" + "type": "string", + "format": "date-time" }, "schema": { "type": "string" diff --git a/json-schemas/records/records-query.json b/json-schemas/records/records-query.json index 0c1c1d212..72b9fa835 100644 --- a/json-schemas/records/records-query.json +++ b/json-schemas/records/records-query.json @@ -34,7 +34,8 @@ "type": "string" }, "dateCreated": { - "type": "string" + "type": "string", + "format": "date-time" }, "filter": { "type": "object", @@ -71,10 +72,12 @@ "additionalProperties": false, "properties": { "from": { - "type": "string" + "type": "string", + "format": "date-time" }, "to": { - "type": "string" + "type": "string", + "format": "date-time" } } } diff --git a/json-schemas/records/records-write.json b/json-schemas/records/records-write.json index 4e57b459a..e8bc890e3 100644 --- a/json-schemas/records/records-write.json +++ b/json-schemas/records/records-write.json @@ -121,16 +121,19 @@ "type": "number" }, "dateCreated": { - "type": "string" + "type": "string", + "format": "date-time" }, "dateModified": { - "type": "string" + "type": "string", + "format": "date-time" }, "published": { "type": "boolean" }, "datePublished": { - "type": "string" + "type": "string", + "format": "date-time" }, "dataFormat": { "type": "string" diff --git a/package-lock.json b/package-lock.json index 2599925bd..21dd6915d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,8 @@ "@types/readable-stream": "2.3.15", "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", - "ajv": "8.11.0", + "ajv": "8.12.0", + "ajv-formats": "^2.1.1", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", @@ -1243,9 +1244,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1257,6 +1258,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -8803,9 +8820,9 @@ "requires": {} }, "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -8813,6 +8830,14 @@ "uri-js": "^4.2.2" } }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + } + }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", diff --git a/package.json b/package.json index 11f05b8c6..a53025e72 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,8 @@ "@types/readable-stream": "2.3.15", "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", - "ajv": "8.11.0", + "ajv": "8.12.0", + "ajv-formats": "^2.1.1", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", From a5b7b490187f7f0863f344d93c07b0d6478951a1 Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 25 Apr 2023 18:06:45 -0400 Subject: [PATCH 02/11] Remove JTD-specific option --- build/compile-validators.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/compile-validators.js b/build/compile-validators.js index e9afc66b1..f0bca06e7 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -61,7 +61,7 @@ const schemas = { PublicJwk }; -const ajv = new Ajv({ code: { source: true, esm: true }, allowDate: 'string' }); +const ajv = new Ajv({ code: { source: true, esm: true } }); addFormats(ajv); for (const schemaName in schemas) { From dfd65cb019452b3445dab8ab0c2af26245172ec1 Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 25 Apr 2023 18:25:16 -0400 Subject: [PATCH 03/11] Update ajv-formats to 3.0.0-rc.0 to get date-time fixes --- build/compile-validators.js | 2 +- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build/compile-validators.js b/build/compile-validators.js index f0bca06e7..6e35be06b 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -8,13 +8,13 @@ * - to reduce the browser bundle size - Ajv is not included in the bundle * - to reduce the start-up time - the validation and compilation of schemas will happen during build time. */ +import addFormats from 'ajv-formats'; import fs from 'node:fs'; import path from 'node:path'; import url from 'node:url'; import Ajv from 'ajv'; -import addFormats from "ajv-formats" import mkdirp from 'mkdirp'; import standaloneCode from 'ajv/dist/standalone/index.js'; diff --git a/package-lock.json b/package-lock.json index 21dd6915d..8222b3e93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", "ajv": "8.12.0", - "ajv-formats": "^2.1.1", + "ajv-formats": "^3.0.0-rc.0", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", @@ -1259,9 +1259,9 @@ } }, "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "version": "3.0.0-rc.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.0-rc.0.tgz", + "integrity": "sha512-eyqaGv4OE7RMgW2GNujqwJZWFjOT4z0tQZTVnYiWtSDh9TFwD8CIsJ6ta065IblpZXcV3wFuy8y2gKFb1d0uPw==", "dependencies": { "ajv": "^8.0.0" }, @@ -8831,9 +8831,9 @@ } }, "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "version": "3.0.0-rc.0", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.0-rc.0.tgz", + "integrity": "sha512-eyqaGv4OE7RMgW2GNujqwJZWFjOT4z0tQZTVnYiWtSDh9TFwD8CIsJ6ta065IblpZXcV3wFuy8y2gKFb1d0uPw==", "requires": { "ajv": "^8.0.0" } diff --git a/package.json b/package.json index a53025e72..07b63147f 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", "ajv": "8.12.0", - "ajv-formats": "^2.1.1", + "ajv-formats": "^3.0.0-rc.0", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", From 3391b4679aa4fb89e4893c0fd66aa0f1ee1632ec Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Tue, 25 Apr 2023 23:39:57 -0400 Subject: [PATCH 04/11] Don't include ajv-formats and inline the date-time format regex --- build/compile-validators.js | 3 +-- package-lock.json | 39 +++++++------------------------------ package.json | 3 +-- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/build/compile-validators.js b/build/compile-validators.js index 6e35be06b..811d06f08 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -8,7 +8,6 @@ * - to reduce the browser bundle size - Ajv is not included in the bundle * - to reduce the start-up time - the validation and compilation of schemas will happen during build time. */ -import addFormats from 'ajv-formats'; import fs from 'node:fs'; import path from 'node:path'; @@ -62,7 +61,7 @@ const schemas = { }; const ajv = new Ajv({ code: { source: true, esm: true } }); -addFormats(ajv); +ajv.addFormat('date-time', /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i); for (const schemaName in schemas) { ajv.addSchema(schemas[schemaName], schemaName); diff --git a/package-lock.json b/package-lock.json index 8222b3e93..2599925bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,8 +21,7 @@ "@types/readable-stream": "2.3.15", "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", - "ajv": "8.12.0", - "ajv-formats": "^3.0.0-rc.0", + "ajv": "8.11.0", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", @@ -1244,9 +1243,9 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1258,22 +1257,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.0-rc.0.tgz", - "integrity": "sha512-eyqaGv4OE7RMgW2GNujqwJZWFjOT4z0tQZTVnYiWtSDh9TFwD8CIsJ6ta065IblpZXcV3wFuy8y2gKFb1d0uPw==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -8820,9 +8803,9 @@ "requires": {} }, "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -8830,14 +8813,6 @@ "uri-js": "^4.2.2" } }, - "ajv-formats": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.0-rc.0.tgz", - "integrity": "sha512-eyqaGv4OE7RMgW2GNujqwJZWFjOT4z0tQZTVnYiWtSDh9TFwD8CIsJ6ta065IblpZXcV3wFuy8y2gKFb1d0uPw==", - "requires": { - "ajv": "^8.0.0" - } - }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", diff --git a/package.json b/package.json index 07b63147f..11f05b8c6 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,7 @@ "@types/readable-stream": "2.3.15", "@types/secp256k1": "4.0.3", "abstract-level": "1.0.3", - "ajv": "8.12.0", - "ajv-formats": "^3.0.0-rc.0", + "ajv": "8.11.0", "blockstore-core": "3.0.0", "cross-fetch": "3.1.5", "date-fns": "2.28.0", From 59cc6ba9163eb617ccebf362898a22efe112865e Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Wed, 26 Apr 2023 00:05:50 -0400 Subject: [PATCH 05/11] Update tests to make dateCreated validate --- json-schemas/records/records-write.json | 2 +- .../records/handlers/records-write.spec.ts | 2 +- .../records/messages/records-write.spec.ts | 2 +- .../protocols/protocols-configure.spec.ts | 2 +- .../records/records-query.spec.ts | 18 ++--- .../records/records-write.spec.ts | 68 +++++++++---------- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/json-schemas/records/records-write.json b/json-schemas/records/records-write.json index e8bc890e3..bd7f3f3bb 100644 --- a/json-schemas/records/records-write.json +++ b/json-schemas/records/records-write.json @@ -132,7 +132,7 @@ "type": "boolean" }, "datePublished": { - "type": "string", + "type": "string", "format": "date-time" }, "dataFormat": { diff --git a/tests/interfaces/records/handlers/records-write.spec.ts b/tests/interfaces/records/handlers/records-write.spec.ts index bbb6642aa..4c3035960 100644 --- a/tests/interfaces/records/handlers/records-write.spec.ts +++ b/tests/interfaces/records/handlers/records-write.spec.ts @@ -426,7 +426,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; diff --git a/tests/interfaces/records/messages/records-write.spec.ts b/tests/interfaces/records/messages/records-write.spec.ts index 44c0f7b55..8971bd0a6 100644 --- a/tests/interfaces/records/messages/records-write.spec.ts +++ b/tests/interfaces/records/messages/records-write.spec.ts @@ -24,7 +24,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) }; diff --git a/tests/validation/json-schemas/protocols/protocols-configure.spec.ts b/tests/validation/json-schemas/protocols/protocols-configure.spec.ts index 610f37d81..60b221d64 100644 --- a/tests/validation/json-schemas/protocols/protocols-configure.spec.ts +++ b/tests/validation/json-schemas/protocols/protocols-configure.spec.ts @@ -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 }, diff --git a/tests/validation/json-schemas/records/records-query.spec.ts b/tests/validation/json-schemas/records/records-query.spec.ts index 3b5e06724..729b8d120 100644 --- a/tests/validation/json-schemas/records/records-query.spec.ts +++ b/tests/validation/json-schemas/records/records-query.spec.ts @@ -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: { @@ -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' } } }; @@ -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: { @@ -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 }, @@ -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 }, @@ -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 }, @@ -135,7 +135,7 @@ describe('RecordsQuery schema validation', () => { descriptor: { interface : 'Records', method : 'Query', - dateCreated : '123', + dateCreated : '2022-10-14T10:20:30.405060Z', filter : { } }, authorization: { @@ -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: { @@ -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: { diff --git a/tests/validation/json-schemas/records/records-write.spec.ts b/tests/validation/json-schemas/records/records-write.spec.ts index 10cc85de4..a812e31f7 100644 --- a/tests/validation/json-schemas/records/records-write.spec.ts +++ b/tests/validation/json-schemas/records/records-write.spec.ts @@ -11,8 +11,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456', + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z', }, authorization: { payload : 'anyPayload', @@ -33,8 +33,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -59,8 +59,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' } }; @@ -78,8 +78,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -105,8 +105,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456', + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z', unknownProperty : 'unknownProperty' // unknown property }, authorization: { @@ -136,8 +136,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -164,8 +164,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -190,8 +190,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -215,8 +215,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -242,8 +242,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -271,8 +271,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -300,8 +300,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -330,8 +330,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456' + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z' }, authorization: { payload : 'anyPayload', @@ -356,10 +356,10 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateModified : '2022-12-19T10:20:30.123456', + dateModified : '2022-12-19T10:20:30.123456Z', published : false, - dateCreated : '2022-12-19T10:20:30.123456', - datePublished : '2022-12-19T10:20:30.123456' // must not be present when not published + dateCreated : '2022-12-19T10:20:30.123456Z', + datePublished : '2022-12-19T10:20:30.123456Z' // must not be present when not published }, authorization: { payload : 'anyPayload', @@ -384,8 +384,8 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456', + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z', published : true //datePublished must be present }, authorization: { @@ -411,9 +411,9 @@ describe('RecordsWrite schema definition', () => { dataCid : 'anyCid', dataFormat : 'application/json', dataSize : 123, - dateCreated : '2022-12-19T10:20:30.123456', - dateModified : '2022-12-19T10:20:30.123456', - datePublished : '2022-12-19T10:20:30.123456' //published must be present + dateCreated : '2022-12-19T10:20:30.123456Z', + dateModified : '2022-12-19T10:20:30.123456Z', + datePublished : '2022-12-19T10:20:30.123456Z' //published must be present }, authorization: { payload : 'anyPayload', From 2189fd37775f34c03e722a8304bbdb35a8a3de4c Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Wed, 26 Apr 2023 01:08:11 -0400 Subject: [PATCH 06/11] Inline the date strings --- build/compile-validators.js | 1 - .../records/handlers/records-query.spec.ts | 23 +++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/build/compile-validators.js b/build/compile-validators.js index 811d06f08..f055f7b90 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -14,7 +14,6 @@ import path from 'node:path'; import url from 'node:url'; import Ajv from 'ajv'; - import mkdirp from 'mkdirp'; import standaloneCode from 'ajv/dist/standalone/index.js'; diff --git a/tests/interfaces/records/handlers/records-query.spec.ts b/tests/interfaces/records/handlers/records-query.spec.ts index 61a306915..18c2aaebf 100644 --- a/tests/interfaces/records/handlers/records-query.spec.ts +++ b/tests/interfaces/records/handlers/records-query.spec.ts @@ -20,7 +20,6 @@ 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'; @@ -186,9 +185,9 @@ describe('RecordsQueryHandler.handle()', () => { 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 = '2021-01-01T00:00:00.000000Z'; + const firstDayOf2022 = '2022-01-01T00:00:00.000000Z'; + const firstDayOf2023 = '2023-01-01T00:00:00.000000Z'; 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 }); @@ -203,7 +202,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 = '2021-12-31T00:00:00.000000Z'; const recordsQuery1 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2021 } }, @@ -215,7 +214,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 = '2022-12-31T00:00:00.000000Z'; const recordsQuery2 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { to: lastDayOf2022 } }, @@ -227,7 +226,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 = '2023-12-31T00:00:00.000000Z'; const recordsQuery3 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } }, @@ -250,9 +249,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 = '2021-01-01T00:00:00.000000Z'; + const firstDayOf2022 = '2022-01-01T00:00:00.000000Z'; + const firstDayOf2023 = '2023-01-01T00:00:00.000000Z'; const alice = await DidKeyResolver.generate(); const schema = '2021And2022Schema'; const write1 = await TestDataGenerator.generateRecordsWrite({ @@ -274,8 +273,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 = '2021-12-31T00:00:00.000000Z'; + const lastDayOf2023 = '2023-12-31T00:00:00.000000Z'; const recordsQuery5 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { From f425557984b1c257b60f53c2c11f0f3506ac4aeb Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Wed, 26 Apr 2023 13:26:32 -0400 Subject: [PATCH 07/11] Use toTemporalInstant instead of hardcoding the datetime strings --- .../records/handlers/records-query.spec.ts | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/interfaces/records/handlers/records-query.spec.ts b/tests/interfaces/records/handlers/records-query.spec.ts index 18c2aaebf..39fd653cd 100644 --- a/tests/interfaces/records/handlers/records-query.spec.ts +++ b/tests/interfaces/records/handlers/records-query.spec.ts @@ -22,11 +22,19 @@ import { RecordsQueryHandler } from '../../../../src/interfaces/records/handlers import { StorageController } from '../../../../src/store/storage-controller.js'; 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'; +declare global { + interface Date { + toTemporalInstant: typeof toTemporalInstant; + } +} +Date.prototype.toTemporalInstant = toTemporalInstant; + chai.use(chaiAsPromised); describe('RecordsQueryHandler.handle()', () => { @@ -183,11 +191,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 = '2021-01-01T00:00:00.000000Z'; - const firstDayOf2022 = '2022-01-01T00:00:00.000000Z'; - const firstDayOf2023 = '2023-01-01T00:00:00.000000Z'; + const firstDayOf2021 = new Date(2021, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const firstDayOf2022 = new Date(2022, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const firstDayOf2023 = new Date(2023, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); 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 }); @@ -202,7 +211,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(writeReply3.status.code).to.equal(202); // testing `from` range - const lastDayOf2021 = '2021-12-31T00:00:00.000000Z'; + const lastDayOf2021 = new Date(2021, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); const recordsQuery1 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2021 } }, @@ -214,7 +223,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(reply1.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write3.dataBytes!)); // testing `to` range - const lastDayOf2022 = '2022-12-31T00:00:00.000000Z'; + const lastDayOf2022 = new Date(2022, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); const recordsQuery2 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { to: lastDayOf2022 } }, @@ -226,7 +235,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(reply2.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write2.dataBytes!)); // testing `from` and `to` range - const lastDayOf2023 = '2023-12-31T00:00:00.000000Z'; + const lastDayOf2023 = new Date(2023, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); const recordsQuery3 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } }, @@ -249,9 +258,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 = '2021-01-01T00:00:00.000000Z'; - const firstDayOf2022 = '2022-01-01T00:00:00.000000Z'; - const firstDayOf2023 = '2023-01-01T00:00:00.000000Z'; + const firstDayOf2021 = new Date(2021, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const firstDayOf2022 = new Date(2022, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const firstDayOf2023 = new Date(2023, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); const alice = await DidKeyResolver.generate(); const schema = '2021And2022Schema'; const write1 = await TestDataGenerator.generateRecordsWrite({ @@ -273,8 +282,8 @@ describe('RecordsQueryHandler.handle()', () => { expect(writeReply3.status.code).to.equal(202); // testing range criterion with another exact match - const lastDayOf2021 = '2021-12-31T00:00:00.000000Z'; - const lastDayOf2023 = '2023-12-31T00:00:00.000000Z'; + const lastDayOf2021 = new Date(2021, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const lastDayOf2023 = new Date(2023, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); const recordsQuery5 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { From 9c1ef77f063e033217a5f8998bf1a2d226cf34fc Mon Sep 17 00:00:00 2001 From: Duncan Mak Date: Wed, 26 Apr 2023 14:28:46 -0400 Subject: [PATCH 08/11] Introduce createDateString helper function instead of modifying Date.prototype --- .../records/handlers/records-query.spec.ts | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/tests/interfaces/records/handlers/records-query.spec.ts b/tests/interfaces/records/handlers/records-query.spec.ts index 39fd653cd..bb106a9f5 100644 --- a/tests/interfaces/records/handlers/records-query.spec.ts +++ b/tests/interfaces/records/handlers/records-query.spec.ts @@ -28,15 +28,12 @@ import { constructRecordsWriteIndexes } from '../../../../src/interfaces/records import { DataStream, DidResolver, Dwn, HdKey, KeyDerivationScheme, Records } from '../../../../src/index.js'; import { DateSort, RecordsQuery } from '../../../../src/interfaces/records/messages/records-query.js'; -declare global { - interface Date { - toTemporalInstant: typeof toTemporalInstant; - } -} -Date.prototype.toTemporalInstant = toTemporalInstant; - chai.use(chaiAsPromised); +function createDateString(d: Date): string { + return toTemporalInstant.call(d).toString({ smallestUnit: 'microseconds' }); +} + describe('RecordsQueryHandler.handle()', () => { describe('functional tests', () => { let didResolver: DidResolver; @@ -194,9 +191,9 @@ describe('RecordsQueryHandler.handle()', () => { 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 = new Date(2021, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); - const firstDayOf2022 = new Date(2022, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); - const firstDayOf2023 = new Date(2023, 1, 1).toTemporalInstant().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 }); @@ -211,7 +208,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(writeReply3.status.code).to.equal(202); // testing `from` range - const lastDayOf2021 = new Date(2021, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const lastDayOf2021 = createDateString(new Date(2021, 12, 31)); const recordsQuery1 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2021 } }, @@ -223,7 +220,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(reply1.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write3.dataBytes!)); // testing `to` range - const lastDayOf2022 = new Date(2022, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const lastDayOf2022 = createDateString(new Date(2022, 12, 31)); const recordsQuery2 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { to: lastDayOf2022 } }, @@ -235,7 +232,7 @@ describe('RecordsQueryHandler.handle()', () => { expect(reply2.entries![1].encodedData).to.equal(Encoder.bytesToBase64Url(write2.dataBytes!)); // testing `from` and `to` range - const lastDayOf2023 = new Date(2023, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); + const lastDayOf2023 = createDateString(new Date(2023, 12, 31)); const recordsQuery3 = await TestDataGenerator.generateRecordsQuery({ requester : alice, filter : { dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } }, @@ -258,9 +255,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 = new Date(2021, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); - const firstDayOf2022 = new Date(2022, 1, 1).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); - const firstDayOf2023 = new Date(2023, 1, 1).toTemporalInstant().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({ @@ -282,8 +279,8 @@ describe('RecordsQueryHandler.handle()', () => { expect(writeReply3.status.code).to.equal(202); // testing range criterion with another exact match - const lastDayOf2021 = new Date(2021, 12, 31).toTemporalInstant().toString({ smallestUnit: 'microseconds' }); - const lastDayOf2023 = new Date(2023, 12, 31).toTemporalInstant().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 : { From ff935e069945ba29e09fd1ce323b888a2c0f235d Mon Sep 17 00:00:00 2001 From: Henry Tsai Date: Thu, 27 Apr 2023 10:41:53 -0700 Subject: [PATCH 09/11] updated regex and moved it into definitions.json --- README.md | 2 +- build/compile-validators.js | 1 - json-schemas/definitions.json | 6 +++++- json-schemas/hooks/hooks-write.json | 3 +-- json-schemas/records/records-query.json | 9 +++------ json-schemas/records/records-write.json | 9 +++------ 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 330067b01..592f80e25 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ # Decentralized Web Node (DWN) SDK Code Coverage -![Statements](https://img.shields.io/badge/statements-93.99%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-93.5%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.72%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-93.99%25-brightgreen.svg?style=flat) +![Statements](https://img.shields.io/badge/statements-93.99%25-brightgreen.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-93.51%25-brightgreen.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-91.72%25-brightgreen.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-93.99%25-brightgreen.svg?style=flat) ## Introduction diff --git a/build/compile-validators.js b/build/compile-validators.js index f055f7b90..d01b7b800 100644 --- a/build/compile-validators.js +++ b/build/compile-validators.js @@ -60,7 +60,6 @@ const schemas = { }; const ajv = new Ajv({ code: { source: true, esm: true } }); -ajv.addFormat('date-time', /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i); for (const schemaName in schemas) { ajv.addSchema(schemas[schemaName], schemaName); diff --git a/json-schemas/definitions.json b/json-schemas/definitions.json index bbe5afe96..6c1622ba5 100644 --- a/json-schemas/definitions.json +++ b/json-schemas/definitions.json @@ -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": "^[0-9]{4}-[0-1]\\d-[0-3]\\dT([0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.[0-9]{6}Z$" } } -} +} \ No newline at end of file diff --git a/json-schemas/hooks/hooks-write.json b/json-schemas/hooks/hooks-write.json index 8a4bf96ae..808893be9 100644 --- a/json-schemas/hooks/hooks-write.json +++ b/json-schemas/hooks/hooks-write.json @@ -35,8 +35,7 @@ "type": "string" }, "dateCreated": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "schema": { "type": "string" diff --git a/json-schemas/records/records-query.json b/json-schemas/records/records-query.json index 72b9fa835..09c5b5813 100644 --- a/json-schemas/records/records-query.json +++ b/json-schemas/records/records-query.json @@ -34,8 +34,7 @@ "type": "string" }, "dateCreated": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "filter": { "type": "object", @@ -72,12 +71,10 @@ "additionalProperties": false, "properties": { "from": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "to": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" } } } diff --git a/json-schemas/records/records-write.json b/json-schemas/records/records-write.json index bd7f3f3bb..4ca745b72 100644 --- a/json-schemas/records/records-write.json +++ b/json-schemas/records/records-write.json @@ -121,19 +121,16 @@ "type": "number" }, "dateCreated": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "dateModified": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "published": { "type": "boolean" }, "datePublished": { - "type": "string", - "format": "date-time" + "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/definitions/date-time" }, "dataFormat": { "type": "string" From 26838018cd8c87031f8234cca13d0e639083b2fe Mon Sep 17 00:00:00 2001 From: Henry Tsai Date: Thu, 27 Apr 2023 12:54:11 -0700 Subject: [PATCH 10/11] added tests --- package-lock.json | 18 ++++++------ package.json | 6 ++-- .../json-schemas/definitions.spec.ts | 29 +++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 tests/validation/json-schemas/definitions.spec.ts diff --git a/package-lock.json b/package-lock.json index 2599925bd..a5a41ea53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tbd54566975/dwn-sdk-js", - "version": "0.0.30", + "version": "0.0.31", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tbd54566975/dwn-sdk-js", - "version": "0.0.30", + "version": "0.0.31", "license": "Apache-2.0", "dependencies": { "@ipld/dag-cbor": "9.0.0", @@ -21,7 +21,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", @@ -1243,9 +1243,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -8803,9 +8803,9 @@ "requires": {} }, "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", diff --git a/package.json b/package.json index 11f05b8c6..307c3a7ba 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", @@ -143,4 +143,4 @@ "url": "https://github.com/TBD54566975/dwn-sdk-js/issues" }, "homepage": "https://github.com/TBD54566975/dwn-sdk-js#readme" -} +} \ No newline at end of file diff --git a/tests/validation/json-schemas/definitions.spec.ts b/tests/validation/json-schemas/definitions.spec.ts new file mode 100644 index 000000000..6b92c0841 --- /dev/null +++ b/tests/validation/json-schemas/definitions.spec.ts @@ -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; + } + }); +}); From ce9ec7c34893276b5e12eae8b8b8bae8fe719f9c Mon Sep 17 00:00:00 2001 From: Henry Tsai Date: Thu, 27 Apr 2023 13:03:22 -0700 Subject: [PATCH 11/11] addressed review comments --- json-schemas/definitions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-schemas/definitions.json b/json-schemas/definitions.json index 6c1622ba5..cd08533ba 100644 --- a/json-schemas/definitions.json +++ b/json-schemas/definitions.json @@ -17,7 +17,7 @@ }, "date-time": { "type": "string", - "pattern": "^[0-9]{4}-[0-1]\\d-[0-3]\\dT([0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.[0-9]{6}Z$" + "pattern": "^\\d{4}-[0-1]\\d-[0-3]\\dT(?:[0-2]\\d:[0-5]\\d:[0-5]\\d|23:59:60)\\.\\d{6}Z$" } } } \ No newline at end of file