Skip to content

Commit a7169b3

Browse files
authored
feat: support nip-111 (#168)
* feat: support nip-111 * test: update schemas
1 parent 67ad1eb commit a7169b3

File tree

9 files changed

+53
-16
lines changed

9 files changed

+53
-16
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ NIPs with a relay-specific implementation are listed here.
5959
- [x] NIP-26: Delegated Event Signing
6060
- [x] NIP-28: Public Chat
6161
- [x] NIP-33: Parameterized Replaceable Events
62+
- [x] NIP-111: Relay Information Document Extensions
6263

6364
## Requirements
6465

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
26,
1717
28,
1818
33,
19-
40
19+
40,
20+
111
2021
],
2122
"main": "src/index.ts",
2223
"scripts": {

src/handlers/request-handlers/root-request-handler.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@ import { NextFunction, Request, Response } from 'express'
22
import { path } from 'ramda'
33

44
import { createSettings } from '../../factories/settings-factory'
5+
import { FeeSchedule } from '../../@types/settings'
56
import packageJson from '../../../package.json'
67

78
export const rootRequestHandler = (request: Request, response: Response, next: NextFunction) => {
89
const settings = createSettings()
910

1011
if (request.header('accept') === 'application/nostr+json') {
1112
const {
12-
info: { name, description, pubkey, contact },
13+
info: { name, description, pubkey, contact, relay_url },
1314
} = settings
1415

16+
const paymentsUrl = new URL(relay_url)
17+
paymentsUrl.protocol = paymentsUrl.protocol === 'wss:' ? 'https:' : 'http:'
18+
paymentsUrl.pathname = '/invoices'
19+
1520
const relayInformationDocument = {
1621
name,
1722
description,
@@ -20,6 +25,33 @@ export const rootRequestHandler = (request: Request, response: Response, next: N
2025
supported_nips: packageJson.supportedNips,
2126
software: packageJson.repository.url,
2227
version: packageJson.version,
28+
limitation: {
29+
max_message_length: settings.network.maxPayloadSize,
30+
max_subscriptions: settings.limits.client.subscription.maxSubscriptions,
31+
max_filters: settings.limits.client.subscription.maxFilters,
32+
max_limit: 5000,
33+
max_subid_length: 256,
34+
min_prefix: 4,
35+
max_event_tags: 2500,
36+
max_content_length: 102400,
37+
min_pow_difficulty: settings.limits.event.eventId.minLeadingZeroBits,
38+
auth_required: false,
39+
payment_required: settings.payments.enabled,
40+
},
41+
payments_url: paymentsUrl.toString(),
42+
fees: Object
43+
.getOwnPropertyNames(settings.payments.feeSchedules)
44+
.reduce((prev, feeName) => {
45+
const feeSchedules = settings.payments.feeSchedules[feeName] as FeeSchedule[]
46+
47+
return {
48+
...prev,
49+
[feeName]: feeSchedules.reduce((fees, fee) => (fee.enabled)
50+
? [...fees, { amount: fee.amount, unit: 'msats' }]
51+
: fees, []),
52+
}
53+
54+
}, {} as Record<string, { amount: number, unit: string }>),
2355
}
2456

2557
response

src/schemas/base-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Schema from 'joi'
22

3-
export const prefixSchema = Schema.string().case('lower').hex().min(1).max(64).label('prefix')
3+
export const prefixSchema = Schema.string().case('lower').hex().min(4).max(64).label('prefix')
44

55
export const idSchema = Schema.string().case('lower').hex().length(64).label('id')
66

src/schemas/event-schema.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ export const eventSchema = Schema.object({
3131
pubkey: pubkeySchema.required(),
3232
created_at: createdAtSchema.required(),
3333
kind: kindSchema.required(),
34-
tags: Schema.array().items(tagSchema).required(),
34+
tags: Schema.array().items(tagSchema).max(2500).required(),
3535
content: Schema.string()
3636
.allow('')
37+
.max(100 * 1024) // 100 kB
3738
.required(),
3839
sig: signatureSchema.required(),
3940
}).unknown(false)

src/schemas/filter-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ export const filterSchema = Schema.object({
88
kinds: Schema.array().items(kindSchema).max(20),
99
since: createdAtSchema,
1010
until: createdAtSchema,
11-
limit: Schema.number().min(0).multiple(1).max(10000),
11+
limit: Schema.number().min(0).multiple(1).max(5000),
1212
}).pattern(/^#[a-z]$/, Schema.array().items(Schema.string().max(1024)).max(256))

src/schemas/message-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const eventMessageSchema = Schema.array().ordered(
1212
.label('EVENT message')
1313

1414
export const reqMessageSchema = Schema.array()
15-
.ordered(Schema.string().valid('REQ').required(), Schema.string().required().label('subscriptionId'))
15+
.ordered(Schema.string().valid('REQ').required(), Schema.string().max(256).required().label('subscriptionId'))
1616
.items(filterSchema.required().label('filter')).max(12)
1717
.label('REQ message')
1818

test/unit/schemas/filter-schema.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ describe('NIP-01', () => {
1010
describe('validate filter schema', () => {
1111
beforeEach(() => {
1212
filter = {
13-
ids: ['aa', 'bb', 'cc'],
14-
authors: ['aa', 'bb', 'cc'],
13+
ids: ['aaaa', 'bbbb', 'cccc'],
14+
authors: ['aaaa', 'bbbb', 'cccc'],
1515
kinds: [0, 1, 2, 3],
1616
since: 1000,
1717
until: 1000,
@@ -32,7 +32,7 @@ describe('NIP-01', () => {
3232
const cases = {
3333
ids: [
3434
{ message: 'must be an array', transform: assocPath(['ids'], null) },
35-
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['ids'], range(0, 1001).map(() => 'f')) },
35+
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['ids'], range(0, 1001).map(() => 'ffff')) },
3636
],
3737
prefixOrId: [
3838
{ message: 'length must be less than or equal to 64 characters long', transform: assocPath(['ids', 0], 'f'.repeat(65)) },
@@ -41,7 +41,7 @@ describe('NIP-01', () => {
4141
],
4242
authors: [
4343
{ message: 'must be an array', transform: assocPath(['authors'], null) },
44-
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['authors'], range(0, 1001).map(() => 'f')) },
44+
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['authors'], range(0, 1001).map(() => 'ffff')) },
4545
],
4646
prefixOrAuthor: [
4747
{ message: 'length must be less than or equal to 64 characters long', transform: assocPath(['authors', 0], 'f'.repeat(65)) },
@@ -73,7 +73,7 @@ describe('NIP-01', () => {
7373
{ message: 'must be a number', transform: assocPath(['limit'], null) },
7474
{ message: 'must be greater than or equal to 0', transform: assocPath(['limit'], -1) },
7575
{ message: 'must be a multiple of 1', transform: assocPath(['limit'], Math.PI) },
76-
{ message: 'must be less than or equal to 10000', transform: assocPath(['limit'], 10001) },
76+
{ message: 'must be less than or equal to 5000', transform: assocPath(['limit'], 5001) },
7777
],
7878
'#e': [
7979
{ message: 'must be an array', transform: assocPath(['#e'], null) },

test/unit/schemas/message-schema.spec.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ describe('NIP-01', () => {
2525

2626
const result = validateSchema(messageSchema)(message)
2727

28+
console.log(result)
29+
2830
expect(result).not.to.have.property('error')
2931
expect(result).to.have.deep.property('value', message)
3032
})
@@ -56,8 +58,8 @@ describe('NIP-01', () => {
5658
'REQ',
5759
'id',
5860
{
59-
ids: ['aa', 'bb', 'cc'],
60-
authors: ['aa', 'bb', 'cc'],
61+
ids: ['aaaa', 'bbbb', 'cccc'],
62+
authors: ['aaaa', 'bbbb', 'cccc'],
6163
kinds: [0, 1, 2, 3],
6264
since: 1000,
6365
until: 1000,
@@ -67,8 +69,8 @@ describe('NIP-01', () => {
6769
'#r': ['00', '11', '22'],
6870
},
6971
{
70-
ids: ['aa', 'bb', 'cc'],
71-
authors: ['aa', 'bb', 'cc'],
72+
ids: ['aaaa', 'bbbb', 'cccc'],
73+
authors: ['aaaa', 'bbbb', 'cccc'],
7274
kinds: [0, 1, 2, 3],
7375
since: 1000,
7476
until: 1000,
@@ -82,7 +84,7 @@ describe('NIP-01', () => {
8284

8385
it('returns same message if valid', () => {
8486
const result = validateSchema(messageSchema)(message)
85-
87+
console.log('result', result)
8688
expect(result).not.to.have.property('error')
8789
expect(result).to.have.deep.property('value', message)
8890
})

0 commit comments

Comments
 (0)