From 4bad010dd58cc53081df651e760fc1c863052566 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 12:44:16 +0000 Subject: [PATCH 1/5] Update dependency @tryghost/validator to v3 --- package.json | 2 +- yarn.lock | 35 +++++++++++++++-------------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 93b3af9d..b95c6f99 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@sinclair/typebox": "0.34.49", "@tryghost/errors": "3.2.0", "@tryghost/referrer-parser": "0.1.16", - "@tryghost/validator": "2.1.0", + "@tryghost/validator": "3.1.0", "fastify": "5.8.5", "fastify-plugin": "5.1.0", "pino": "10.3.1", diff --git a/yarn.lock b/yarn.lock index c1fee1be..84ed7d37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1558,11 +1558,6 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.1.tgz#35adc6222e3662fa2222ce123b961476a746b9ea" integrity sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ== -"@tryghost/errors@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-3.1.0.tgz#d02112b290f5358c2e73f148084d3bad4cf72c17" - integrity sha512-vavmjjIAxngGuKK+D6vzYM+Bi36Td1cVEPtj25OFfHJj3xwoZL1Hji/wJylzqIRIFoCGvvHw+Ztnqjl9yLLAVw== - "@tryghost/errors@3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-3.2.0.tgz#d6dcc78fcdebd6c6767653e0fd859b93791194e7" @@ -1573,21 +1568,21 @@ resolved "https://registry.yarnpkg.com/@tryghost/referrer-parser/-/referrer-parser-0.1.16.tgz#47c26876d8b76f4e3f2b89968aed20380146e581" integrity sha512-lCs+puTmZW8UIJ3rI00GP70ndi/fntPKZ2ai2T5oKOfZg/X5QKLX6Pj6uLPvA2XTKp+4+jfAzuBUf3TiEMDZSA== -"@tryghost/tpl@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/tpl/-/tpl-2.1.0.tgz#48882a23bf929508d5a3faf2f27194ea520d6d75" - integrity sha512-NIzGwyHcFUnJRmaDkd5wx6X+lXfqXqUbsICKO4KcPFtwmqLVButlbidNZsXLdoblyI2J5jS6JIGY22TB+mtiBw== +"@tryghost/tpl@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@tryghost/tpl/-/tpl-2.2.0.tgz#8178f529f36c6e9eb7a015e5a0a7eb5e11b8a33b" + integrity sha512-6OFCFHNzJxbZ0HXiLIAKJz5OkT6cdZId19m6UZ2+xN8oBg14iZwhoHoBWCzKNDrFN53t3N5JHM3oa/WtoB+BKw== -"@tryghost/validator@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/validator/-/validator-2.1.0.tgz#11cf6bc9690e5c45273e150e5df17bfbe7619b8f" - integrity sha512-HdM5ucxn91WG4pkLOIojPRFKWW1wF4IS9lhyxv95gA32AMWnGBpA5B1cQ9/Jv30Xn3ZBz6L7nxmoKtmdsRus7A== +"@tryghost/validator@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@tryghost/validator/-/validator-3.1.0.tgz#53462554ae385384e9ed2ebbb7a8f64113d3aa0a" + integrity sha512-/C0uetcZA5In8jKnXJ31fVRbVkmxqBE+FBjz9w6Uj0/jG/7xbDzrpmwo1QHboc+5HfKFzvIvaLNTnjskBi28eQ== dependencies: - "@tryghost/errors" "3.1.0" - "@tryghost/tpl" "2.1.0" + "@tryghost/errors" "3.2.0" + "@tryghost/tpl" "2.2.0" lodash "4.18.1" moment-timezone "^0.5.23" - validator "7.2.0" + validator "13.15.35" "@tybys/wasm-util@^0.10.1": version "0.10.1" @@ -4886,10 +4881,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validator@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-7.2.0.tgz#a63dcbaba51d4350bf8df20988e0d5a54d711791" - integrity sha512-c8NGTUYeBEcUIGeMppmNVKHE7wwfm3mYbNZxV+c5mlv9fDHI7Ad3p07qfNrn/CvpdkK2k61fOLRO2sTEhgQXmg== +validator@13.15.35: + version "13.15.35" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.35.tgz#81cf455c51f15b69d8d340be5914f3fab00dbf7f" + integrity sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw== vite@8.0.10, "vite@^6.0.0 || ^7.0.0 || ^8.0.0": version "8.0.10" From 9b17834c54c6f20bccf3d4387ff23fb43622f236 Mon Sep 17 00:00:00 2001 From: Chris Raible Date: Wed, 29 Apr 2026 23:00:43 +0000 Subject: [PATCH 2/5] Updated UUID fixtures for validator v3 --- test/unit/plugins/logging.test.ts | 2 +- .../schemas/v1/page-hit-processed.test.ts | 10 ++++----- test/unit/schemas/v1/page-hit-raw.test.ts | 6 ++--- test/unit/schemas/v1/page-hit-request.test.ts | 22 +++++++++---------- .../page-hit-transformations.test.ts | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/test/unit/plugins/logging.test.ts b/test/unit/plugins/logging.test.ts index 24f381b8..d7812137 100644 --- a/test/unit/plugins/logging.test.ts +++ b/test/unit/plugins/logging.test.ts @@ -156,7 +156,7 @@ describe('Logging Plugin', () => { describe('x-site-uuid header', () => { it('should include siteUuid in IncomingRequest log when x-site-uuid header is provided', async () => { - const siteUuid = '12345678-1234-1234-1234-123456789012'; + const siteUuid = '12345678-1234-4234-9234-123456789012'; await app.inject({ method: 'GET', diff --git a/test/unit/schemas/v1/page-hit-processed.test.ts b/test/unit/schemas/v1/page-hit-processed.test.ts index f2c6c7cf..f8054eab 100644 --- a/test/unit/schemas/v1/page-hit-processed.test.ts +++ b/test/unit/schemas/v1/page-hit-processed.test.ts @@ -31,7 +31,7 @@ const validPageHitRaw: PageHitRaw = { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', member_uuid: 'undefined', @@ -70,11 +70,11 @@ describe('PageHitProcessedSchema v1', () => { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', session_id: 'abc123def456', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', member_uuid: 'undefined', member_status: 'free', post_uuid: 'undefined', @@ -372,7 +372,7 @@ describe('PageHitProcessedSchema v1', () => { describe('generateUserSignature', () => { it('should generate consistent signature for same inputs', async () => { - const siteUuid = '12345678-1234-1234-1234-123456789012'; + const siteUuid = '12345678-1234-4234-9234-123456789012'; const ipAddress = '192.168.1.1'; const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'; @@ -384,7 +384,7 @@ describe('PageHitProcessedSchema v1', () => { }); it('should generate different signatures for different inputs', async () => { - const siteUuid = '12345678-1234-1234-1234-123456789012'; + const siteUuid = '12345678-1234-4234-9234-123456789012'; const ipAddress1 = '192.168.1.1'; const ipAddress2 = '192.168.1.2'; const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'; diff --git a/test/unit/schemas/v1/page-hit-raw.test.ts b/test/unit/schemas/v1/page-hit-raw.test.ts index 6b3a4d6f..11d94604 100644 --- a/test/unit/schemas/v1/page-hit-raw.test.ts +++ b/test/unit/schemas/v1/page-hit-raw.test.ts @@ -7,7 +7,7 @@ describe('PageHitRawSchema v1', () => { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', member_uuid: 'undefined', @@ -119,7 +119,7 @@ describe('PageHitRawSchema v1', () => { ...validPageHitRaw, payload: { ...validPageHitRaw.payload, - member_uuid: '12345678-1234-1234-1234-123456789012' + member_uuid: '12345678-1234-4234-9234-123456789012' } }; expect(Value.Check(PageHitRawSchema, validData)).toBe(true); @@ -152,7 +152,7 @@ describe('PageHitRawSchema v1', () => { ...validPageHitRaw, payload: { ...validPageHitRaw.payload, - post_uuid: '12345678-1234-1234-1234-123456789012' + post_uuid: '12345678-1234-4234-9234-123456789012' } }; expect(Value.Check(PageHitRawSchema, validData)).toBe(true); diff --git a/test/unit/schemas/v1/page-hit-request.test.ts b/test/unit/schemas/v1/page-hit-request.test.ts index f7b73c91..d3ffd85a 100644 --- a/test/unit/schemas/v1/page-hit-request.test.ts +++ b/test/unit/schemas/v1/page-hit-request.test.ts @@ -120,7 +120,7 @@ describe('PageHitRequestSchema v1', () => { describe('HeadersSchema', () => { it('should validate valid headers', () => { const validHeaders = { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012', + 'x-site-uuid': '12345678-1234-4234-9234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' }; @@ -130,7 +130,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with optional referer', () => { const validHeaders = { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012', + 'x-site-uuid': '12345678-1234-4234-9234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0', referer: 'https://example.com' @@ -151,7 +151,7 @@ describe('PageHitRequestSchema v1', () => { it('should reject invalid content-type', () => { const invalidHeaders = { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012', + 'x-site-uuid': '12345678-1234-4234-9234-123456789012', 'content-type': 'text/plain', 'user-agent': 'Mozilla/5.0' }; @@ -161,7 +161,7 @@ describe('PageHitRequestSchema v1', () => { it('should reject missing required headers', () => { const invalidHeaders = { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012' + 'x-site-uuid': '12345678-1234-4234-9234-123456789012' // Missing content-type and user-agent }; @@ -177,7 +177,7 @@ describe('PageHitRequestSchema v1', () => { referrer: 'https://google.com', pathname: '/blog/post', href: 'https://example.com/blog/post', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -216,7 +216,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with UUID post_uuid', () => { const payloadWithUUIDPost = { ...validPayload, - post_uuid: '12345678-1234-1234-1234-123456789012' + post_uuid: '12345678-1234-4234-9234-123456789012' }; expect(Value.Check(PageHitRequestPayloadSchema, payloadWithUUIDPost)).toBe(true); @@ -225,7 +225,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with UUID member_uuid', () => { const payloadWithUUIDMember = { ...validPayload, - member_uuid: '12345678-1234-1234-1234-123456789012' + member_uuid: '12345678-1234-4234-9234-123456789012' }; expect(Value.Check(PageHitRequestPayloadSchema, payloadWithUUIDMember)).toBe(true); @@ -443,7 +443,7 @@ describe('PageHitRequestSchema v1', () => { location: 'homepage', pathname: '/blog', href: 'https://example.com/blog', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -492,7 +492,7 @@ describe('PageHitRequestSchema v1', () => { name: 'analytics_events' }, headers: { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012', + 'x-site-uuid': '12345678-1234-4234-9234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0' }, @@ -507,7 +507,7 @@ describe('PageHitRequestSchema v1', () => { location: 'homepage', pathname: '/blog', href: 'https://example.com/blog', - site_uuid: '12345678-1234-1234-1234-123456789012', + site_uuid: '12345678-1234-4234-9234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -556,4 +556,4 @@ describe('PageHitRequestSchema v1', () => { expect(Value.Check(PageHitRequestSchema, invalidRequest)).toBe(false); }); }); -}); \ No newline at end of file +}); diff --git a/test/unit/transformations/page-hit-transformations.test.ts b/test/unit/transformations/page-hit-transformations.test.ts index 7b3b3845..b704a48b 100644 --- a/test/unit/transformations/page-hit-transformations.test.ts +++ b/test/unit/transformations/page-hit-transformations.test.ts @@ -8,7 +8,7 @@ describe('pageHitRawPayloadFromRequest', () => { ip: '192.168.1.1', serverReceivedAt, headers: { - 'x-site-uuid': '12345678-1234-1234-1234-123456789012', + 'x-site-uuid': '12345678-1234-4234-9234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' }, @@ -45,7 +45,7 @@ describe('pageHitRawPayloadFromRequest', () => { expect(result.timestamp).toBe(serverTime.toISOString()); expect(result.action).toBe('page_hit'); expect(result.version).toBe('1'); - expect(result.site_uuid).toBe('12345678-1234-1234-1234-123456789012'); + expect(result.site_uuid).toBe('12345678-1234-4234-9234-123456789012'); expect(result.payload).toEqual({ event_id: 'test-event-id', member_uuid: 'member-uuid-123', From eb30a4e6957144ca6190d8c2de0b2381741a1466 Mon Sep 17 00:00:00 2001 From: Chris Raible Date: Mon, 4 May 2026 13:24:36 -0700 Subject: [PATCH 3/5] Revert "Updated UUID fixtures for validator v3" This reverts commit 9b17834c54c6f20bccf3d4387ff23fb43622f236. --- test/unit/plugins/logging.test.ts | 2 +- .../schemas/v1/page-hit-processed.test.ts | 10 ++++----- test/unit/schemas/v1/page-hit-raw.test.ts | 6 ++--- test/unit/schemas/v1/page-hit-request.test.ts | 22 +++++++++---------- .../page-hit-transformations.test.ts | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/test/unit/plugins/logging.test.ts b/test/unit/plugins/logging.test.ts index d7812137..24f381b8 100644 --- a/test/unit/plugins/logging.test.ts +++ b/test/unit/plugins/logging.test.ts @@ -156,7 +156,7 @@ describe('Logging Plugin', () => { describe('x-site-uuid header', () => { it('should include siteUuid in IncomingRequest log when x-site-uuid header is provided', async () => { - const siteUuid = '12345678-1234-4234-9234-123456789012'; + const siteUuid = '12345678-1234-1234-1234-123456789012'; await app.inject({ method: 'GET', diff --git a/test/unit/schemas/v1/page-hit-processed.test.ts b/test/unit/schemas/v1/page-hit-processed.test.ts index f8054eab..f2c6c7cf 100644 --- a/test/unit/schemas/v1/page-hit-processed.test.ts +++ b/test/unit/schemas/v1/page-hit-processed.test.ts @@ -31,7 +31,7 @@ const validPageHitRaw: PageHitRaw = { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', member_uuid: 'undefined', @@ -70,11 +70,11 @@ describe('PageHitProcessedSchema v1', () => { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', session_id: 'abc123def456', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', member_uuid: 'undefined', member_status: 'free', post_uuid: 'undefined', @@ -372,7 +372,7 @@ describe('PageHitProcessedSchema v1', () => { describe('generateUserSignature', () => { it('should generate consistent signature for same inputs', async () => { - const siteUuid = '12345678-1234-4234-9234-123456789012'; + const siteUuid = '12345678-1234-1234-1234-123456789012'; const ipAddress = '192.168.1.1'; const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'; @@ -384,7 +384,7 @@ describe('PageHitProcessedSchema v1', () => { }); it('should generate different signatures for different inputs', async () => { - const siteUuid = '12345678-1234-4234-9234-123456789012'; + const siteUuid = '12345678-1234-1234-1234-123456789012'; const ipAddress1 = '192.168.1.1'; const ipAddress2 = '192.168.1.2'; const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'; diff --git a/test/unit/schemas/v1/page-hit-raw.test.ts b/test/unit/schemas/v1/page-hit-raw.test.ts index 11d94604..6b3a4d6f 100644 --- a/test/unit/schemas/v1/page-hit-raw.test.ts +++ b/test/unit/schemas/v1/page-hit-raw.test.ts @@ -7,7 +7,7 @@ describe('PageHitRawSchema v1', () => { timestamp: '2024-01-01T00:00:00.000Z', action: 'page_hit', version: '1', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', payload: { event_id: '550e8400-e29b-41d4-a716-446655440000', member_uuid: 'undefined', @@ -119,7 +119,7 @@ describe('PageHitRawSchema v1', () => { ...validPageHitRaw, payload: { ...validPageHitRaw.payload, - member_uuid: '12345678-1234-4234-9234-123456789012' + member_uuid: '12345678-1234-1234-1234-123456789012' } }; expect(Value.Check(PageHitRawSchema, validData)).toBe(true); @@ -152,7 +152,7 @@ describe('PageHitRawSchema v1', () => { ...validPageHitRaw, payload: { ...validPageHitRaw.payload, - post_uuid: '12345678-1234-4234-9234-123456789012' + post_uuid: '12345678-1234-1234-1234-123456789012' } }; expect(Value.Check(PageHitRawSchema, validData)).toBe(true); diff --git a/test/unit/schemas/v1/page-hit-request.test.ts b/test/unit/schemas/v1/page-hit-request.test.ts index d3ffd85a..f7b73c91 100644 --- a/test/unit/schemas/v1/page-hit-request.test.ts +++ b/test/unit/schemas/v1/page-hit-request.test.ts @@ -120,7 +120,7 @@ describe('PageHitRequestSchema v1', () => { describe('HeadersSchema', () => { it('should validate valid headers', () => { const validHeaders = { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012', + 'x-site-uuid': '12345678-1234-1234-1234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' }; @@ -130,7 +130,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with optional referer', () => { const validHeaders = { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012', + 'x-site-uuid': '12345678-1234-1234-1234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0', referer: 'https://example.com' @@ -151,7 +151,7 @@ describe('PageHitRequestSchema v1', () => { it('should reject invalid content-type', () => { const invalidHeaders = { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012', + 'x-site-uuid': '12345678-1234-1234-1234-123456789012', 'content-type': 'text/plain', 'user-agent': 'Mozilla/5.0' }; @@ -161,7 +161,7 @@ describe('PageHitRequestSchema v1', () => { it('should reject missing required headers', () => { const invalidHeaders = { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012' + 'x-site-uuid': '12345678-1234-1234-1234-123456789012' // Missing content-type and user-agent }; @@ -177,7 +177,7 @@ describe('PageHitRequestSchema v1', () => { referrer: 'https://google.com', pathname: '/blog/post', href: 'https://example.com/blog/post', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -216,7 +216,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with UUID post_uuid', () => { const payloadWithUUIDPost = { ...validPayload, - post_uuid: '12345678-1234-4234-9234-123456789012' + post_uuid: '12345678-1234-1234-1234-123456789012' }; expect(Value.Check(PageHitRequestPayloadSchema, payloadWithUUIDPost)).toBe(true); @@ -225,7 +225,7 @@ describe('PageHitRequestSchema v1', () => { it('should validate with UUID member_uuid', () => { const payloadWithUUIDMember = { ...validPayload, - member_uuid: '12345678-1234-4234-9234-123456789012' + member_uuid: '12345678-1234-1234-1234-123456789012' }; expect(Value.Check(PageHitRequestPayloadSchema, payloadWithUUIDMember)).toBe(true); @@ -443,7 +443,7 @@ describe('PageHitRequestSchema v1', () => { location: 'homepage', pathname: '/blog', href: 'https://example.com/blog', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -492,7 +492,7 @@ describe('PageHitRequestSchema v1', () => { name: 'analytics_events' }, headers: { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012', + 'x-site-uuid': '12345678-1234-1234-1234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0' }, @@ -507,7 +507,7 @@ describe('PageHitRequestSchema v1', () => { location: 'homepage', pathname: '/blog', href: 'https://example.com/blog', - site_uuid: '12345678-1234-4234-9234-123456789012', + site_uuid: '12345678-1234-1234-1234-123456789012', post_uuid: 'undefined', post_type: 'post', member_uuid: 'undefined', @@ -556,4 +556,4 @@ describe('PageHitRequestSchema v1', () => { expect(Value.Check(PageHitRequestSchema, invalidRequest)).toBe(false); }); }); -}); +}); \ No newline at end of file diff --git a/test/unit/transformations/page-hit-transformations.test.ts b/test/unit/transformations/page-hit-transformations.test.ts index b704a48b..7b3b3845 100644 --- a/test/unit/transformations/page-hit-transformations.test.ts +++ b/test/unit/transformations/page-hit-transformations.test.ts @@ -8,7 +8,7 @@ describe('pageHitRawPayloadFromRequest', () => { ip: '192.168.1.1', serverReceivedAt, headers: { - 'x-site-uuid': '12345678-1234-4234-9234-123456789012', + 'x-site-uuid': '12345678-1234-1234-1234-123456789012', 'content-type': 'application/json', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' }, @@ -45,7 +45,7 @@ describe('pageHitRawPayloadFromRequest', () => { expect(result.timestamp).toBe(serverTime.toISOString()); expect(result.action).toBe('page_hit'); expect(result.version).toBe('1'); - expect(result.site_uuid).toBe('12345678-1234-4234-9234-123456789012'); + expect(result.site_uuid).toBe('12345678-1234-1234-1234-123456789012'); expect(result.payload).toEqual({ event_id: 'test-event-id', member_uuid: 'member-uuid-123', From 85d0abb381521611750e58697a1284513dad0168 Mon Sep 17 00:00:00 2001 From: Chris Raible Date: Mon, 4 May 2026 13:55:16 -0700 Subject: [PATCH 4/5] Allowed loose UUID validation --- src/schemas/format-registry.ts | 8 +++++--- src/types/tryghost-validator.d.ts | 4 ++-- test/unit/schemas/v1/page-hit-raw.test.ts | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/schemas/format-registry.ts b/src/schemas/format-registry.ts index 5365811c..c602245e 100644 --- a/src/schemas/format-registry.ts +++ b/src/schemas/format-registry.ts @@ -1,15 +1,17 @@ import {FormatRegistry} from '@sinclair/typebox'; import validator from '@tryghost/validator'; +const UUID_SHAPE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + /** * Registers all format validators used by schemas. * This should be called once at application startup to ensure * format validators are available before any schema usage. */ export function registerFormatValidators(): void { - // UUID format validator using @tryghost/validator FormatRegistry.Set('uuid', (value) => { - return validator.isUUID(value); + // We only require UUID-shaped values here; they do not need to be fully RFC compliant. + return validator.isUUID(value, 'loose') || UUID_SHAPE_PATTERN.test(value); }); // URI format validator using @tryghost/validator @@ -23,4 +25,4 @@ export function registerFormatValidators(): void { const date = new Date(value); return !isNaN(date.getTime()) && date.toISOString() === value; }); -} \ No newline at end of file +} diff --git a/src/types/tryghost-validator.d.ts b/src/types/tryghost-validator.d.ts index e029c082..cc1a6853 100644 --- a/src/types/tryghost-validator.d.ts +++ b/src/types/tryghost-validator.d.ts @@ -5,7 +5,7 @@ declare module '@tryghost/validator' { isURL(str: string): boolean; isEmail(str: string): boolean; isIn(str: string, values: string[]): boolean; - isUUID(str: string, version?: number): boolean; + isUUID(str: string, version?: number | 'loose' | 'all' | 'nil' | 'max'): boolean; isBoolean(str: string): boolean; isInt(str: string, options?: {min?: number; max?: number}): boolean; isLowercase(str: string): boolean; @@ -20,4 +20,4 @@ declare module '@tryghost/validator' { const validator: Validator; export default validator; -} \ No newline at end of file +} diff --git a/test/unit/schemas/v1/page-hit-raw.test.ts b/test/unit/schemas/v1/page-hit-raw.test.ts index 6b3a4d6f..8f6c305a 100644 --- a/test/unit/schemas/v1/page-hit-raw.test.ts +++ b/test/unit/schemas/v1/page-hit-raw.test.ts @@ -104,6 +104,14 @@ describe('PageHitRawSchema v1', () => { expect(Value.Check(PageHitRawSchema, validData)).toBe(true); }); + it('should validate UUID-shaped values without requiring RFC version and variant bits', () => { + const validData = { + ...validPageHitRaw, + site_uuid: '12345678-1234-1234-1234-123456789012' + }; + expect(Value.Check(PageHitRawSchema, validData)).toBe(true); + }); + it('should reject invalid UUID format', () => { const invalidData = { ...validPageHitRaw, From 28519069ba81071661d063e10b6c99f56abc423b Mon Sep 17 00:00:00 2001 From: Chris Raible Date: Mon, 4 May 2026 14:02:46 -0700 Subject: [PATCH 5/5] Removed UUID regex fallback --- src/schemas/format-registry.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/schemas/format-registry.ts b/src/schemas/format-registry.ts index c602245e..563668d6 100644 --- a/src/schemas/format-registry.ts +++ b/src/schemas/format-registry.ts @@ -1,8 +1,6 @@ import {FormatRegistry} from '@sinclair/typebox'; import validator from '@tryghost/validator'; -const UUID_SHAPE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; - /** * Registers all format validators used by schemas. * This should be called once at application startup to ensure @@ -11,7 +9,7 @@ const UUID_SHAPE_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0- export function registerFormatValidators(): void { FormatRegistry.Set('uuid', (value) => { // We only require UUID-shaped values here; they do not need to be fully RFC compliant. - return validator.isUUID(value, 'loose') || UUID_SHAPE_PATTERN.test(value); + return validator.isUUID(value, 'loose'); }); // URI format validator using @tryghost/validator