From e802b3dbcef6bd71f53762c72654f9728df25015 Mon Sep 17 00:00:00 2001 From: Khushal Date: Mon, 20 Apr 2026 05:38:52 +0530 Subject: [PATCH 1/2] feat: support subject tags in text notes and add NIP-14 support coverage --- README.md | 1 + package.json | 1 + src/constants/base.ts | 2 ++ .../repositories/event-repository.spec.ts | 17 +++++++++++++++++ test/unit/schemas/event-schema.spec.ts | 19 +++++++++++++++++++ 5 files changed, 40 insertions(+) diff --git a/README.md b/README.md index 744e1a8f..33c15b08 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ NIPs with a relay-specific implementation are listed here. - [x] NIP-11: Relay information document - [x] NIP-12: Generic tag queries - [x] NIP-13: Proof of Work +- [x] NIP-14: Subject tag in text events - [x] NIP-15: End of Stored Events Notice - [x] NIP-16: Event Treatment - [x] NIP-20: Command Results diff --git a/package.json b/package.json index 09da8b33..48161f64 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ 9, 11, 12, + 14, 15, 16, 17, diff --git a/src/constants/base.ts b/src/constants/base.ts index 4c8c6cf6..f1daba11 100644 --- a/src/constants/base.ts +++ b/src/constants/base.ts @@ -46,6 +46,8 @@ export enum EventTags { Event = 'e', Pubkey = 'p', Relay = 'r', + // NIP-14: Subject for text notes + Subject = 'subject', // Multicast = 'm', Deduplication = 'd', Expiration = 'expiration', diff --git a/test/unit/repositories/event-repository.spec.ts b/test/unit/repositories/event-repository.spec.ts index 8996190a..0ca0c0a4 100644 --- a/test/unit/repositories/event-repository.spec.ts +++ b/test/unit/repositories/event-repository.spec.ts @@ -575,6 +575,23 @@ describe('EventRepository', () => { 'insert into "events" ("event_content", "event_created_at", "event_id", "event_kind", "event_pubkey", "event_signature", "event_tags", "expires_at", "remote_address") values (\'I\'\'ve set up mirroring between relays: https://i.imgur.com/HxCDipB.png\', 1648351380, X\'6b3cdd0302ded8068ad3f0269c74423ca4fee460f800f3d90103b63f14400407\', 1, X\'22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793\', X\'b37adfed0e6398546d623536f9ddc92b95b7dc71927e1123266332659253ecd0ffa91ddf2c0a82a8426c5b363139d28534d6cac893b8a810149557a3f6d36768\', \'[["p","8355095016fddbe31fcf1453b26f613553e9758cf2263e190eac8fd96a3d3de9","wss://nostr-pub.wellorder.net"],["e","7377fa81fc6c7ae7f7f4ef8938d4a603f7bf98183b35ab128235cc92d4bebf96","wss://nostr-relay.untethr.me"]]\', NULL, \'::1\') on conflict do nothing', ) }) + + it('preserves subject tag when serializing text note tags', () => { + const event: Event = { + id: '6b3cdd0302ded8068ad3f0269c74423ca4fee460f800f3d90103b63f14400407', + pubkey: '22e804d26ed16b68db5259e78449e96dab5d464c8f470bda3eb1a70467f2c793', + created_at: 1648351380, + kind: 1, + tags: [[EventTags.Subject, 'Weekly notes']], + content: 'hello', + sig: 'b37adfed0e6398546d623536f9ddc92b95b7dc71927e1123266332659253ecd0ffa91ddf2c0a82a8426c5b363139d28534d6cac893b8a810149557a3f6d36768', + [ContextMetadataKey]: { remoteAddress: { address: '::1' } as any }, + } + + const query = (repository as any).insert(event).toString() + + expect(query).to.include('[["subject","Weekly notes"]]') + }) }) describe('deleteByPubkeyAndIds', () => { diff --git a/test/unit/schemas/event-schema.spec.ts b/test/unit/schemas/event-schema.spec.ts index 9a44b0be..1587b154 100644 --- a/test/unit/schemas/event-schema.spec.ts +++ b/test/unit/schemas/event-schema.spec.ts @@ -108,3 +108,22 @@ describe('NIP-01', () => { } }) }) + +describe('NIP-14', () => { + it('accepts subject tag on text note events', () => { + const event: Event = { + id: 'fa4dd948576fe182f5d0e3120b9df42c83dffa1c884754d5e4d3b0a2f98a01c5', + pubkey: 'edfa27d49d2af37ee331e1225bb6ed1912c6d999281b36d8018ad99bc3573c29', + created_at: 1660306803, + kind: 1, + tags: [[EventTags.Subject, 'SoB weekly update']], + content: 'testing subject tag', + sig: '313a9b8cd68267a51da84e292c0937d1f3686c6757c4584f50fcedad2b13fad755e6226924f79880fb5aa9de95c04231a4823981513ac9e7092bad7488282a96', + } + + const result = validateSchema(eventSchema)(event) + + expect(result.error).to.be.undefined + expect(result.value).to.deep.equal(event) + }) +}) From b9c833dac49d6365eccaa3c2d93d9706e98c9654 Mon Sep 17 00:00:00 2001 From: Khushal Date: Wed, 22 Apr 2026 18:33:33 +0530 Subject: [PATCH 2/2] docs(changeset): add support for NIP-14 subject tags in text notes, with units tests to validate parsing and repository behavior --- .changeset/vast-rats-repeat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/vast-rats-repeat.md diff --git a/.changeset/vast-rats-repeat.md b/.changeset/vast-rats-repeat.md new file mode 100644 index 00000000..74a8cd8a --- /dev/null +++ b/.changeset/vast-rats-repeat.md @@ -0,0 +1,5 @@ +--- +"nostream": patch +--- + +add support for NIP-14 subject tags in text notes, with units tests to validate parsing and repository behavior