mirror of
https://github.com/Cameri/nostream.git
synced 2025-03-17 21:31:48 +01:00
feat: support nip-111 (#168)
* feat: support nip-111 * test: update schemas
This commit is contained in:
parent
67ad1eb1d1
commit
a7169b3569
@ -59,6 +59,7 @@ NIPs with a relay-specific implementation are listed here.
|
||||
- [x] NIP-26: Delegated Event Signing
|
||||
- [x] NIP-28: Public Chat
|
||||
- [x] NIP-33: Parameterized Replaceable Events
|
||||
- [x] NIP-111: Relay Information Document Extensions
|
||||
|
||||
## Requirements
|
||||
|
||||
|
@ -16,7 +16,8 @@
|
||||
26,
|
||||
28,
|
||||
33,
|
||||
40
|
||||
40,
|
||||
111
|
||||
],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
|
@ -2,6 +2,7 @@ import { NextFunction, Request, Response } from 'express'
|
||||
import { path } from 'ramda'
|
||||
|
||||
import { createSettings } from '../../factories/settings-factory'
|
||||
import { FeeSchedule } from '../../@types/settings'
|
||||
import packageJson from '../../../package.json'
|
||||
|
||||
export const rootRequestHandler = (request: Request, response: Response, next: NextFunction) => {
|
||||
@ -9,9 +10,13 @@ export const rootRequestHandler = (request: Request, response: Response, next: N
|
||||
|
||||
if (request.header('accept') === 'application/nostr+json') {
|
||||
const {
|
||||
info: { name, description, pubkey, contact },
|
||||
info: { name, description, pubkey, contact, relay_url },
|
||||
} = settings
|
||||
|
||||
const paymentsUrl = new URL(relay_url)
|
||||
paymentsUrl.protocol = paymentsUrl.protocol === 'wss:' ? 'https:' : 'http:'
|
||||
paymentsUrl.pathname = '/invoices'
|
||||
|
||||
const relayInformationDocument = {
|
||||
name,
|
||||
description,
|
||||
@ -20,6 +25,33 @@ export const rootRequestHandler = (request: Request, response: Response, next: N
|
||||
supported_nips: packageJson.supportedNips,
|
||||
software: packageJson.repository.url,
|
||||
version: packageJson.version,
|
||||
limitation: {
|
||||
max_message_length: settings.network.maxPayloadSize,
|
||||
max_subscriptions: settings.limits.client.subscription.maxSubscriptions,
|
||||
max_filters: settings.limits.client.subscription.maxFilters,
|
||||
max_limit: 5000,
|
||||
max_subid_length: 256,
|
||||
min_prefix: 4,
|
||||
max_event_tags: 2500,
|
||||
max_content_length: 102400,
|
||||
min_pow_difficulty: settings.limits.event.eventId.minLeadingZeroBits,
|
||||
auth_required: false,
|
||||
payment_required: settings.payments.enabled,
|
||||
},
|
||||
payments_url: paymentsUrl.toString(),
|
||||
fees: Object
|
||||
.getOwnPropertyNames(settings.payments.feeSchedules)
|
||||
.reduce((prev, feeName) => {
|
||||
const feeSchedules = settings.payments.feeSchedules[feeName] as FeeSchedule[]
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[feeName]: feeSchedules.reduce((fees, fee) => (fee.enabled)
|
||||
? [...fees, { amount: fee.amount, unit: 'msats' }]
|
||||
: fees, []),
|
||||
}
|
||||
|
||||
}, {} as Record<string, { amount: number, unit: string }>),
|
||||
}
|
||||
|
||||
response
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Schema from 'joi'
|
||||
|
||||
export const prefixSchema = Schema.string().case('lower').hex().min(1).max(64).label('prefix')
|
||||
export const prefixSchema = Schema.string().case('lower').hex().min(4).max(64).label('prefix')
|
||||
|
||||
export const idSchema = Schema.string().case('lower').hex().length(64).label('id')
|
||||
|
||||
|
@ -31,9 +31,10 @@ export const eventSchema = Schema.object({
|
||||
pubkey: pubkeySchema.required(),
|
||||
created_at: createdAtSchema.required(),
|
||||
kind: kindSchema.required(),
|
||||
tags: Schema.array().items(tagSchema).required(),
|
||||
tags: Schema.array().items(tagSchema).max(2500).required(),
|
||||
content: Schema.string()
|
||||
.allow('')
|
||||
.max(100 * 1024) // 100 kB
|
||||
.required(),
|
||||
sig: signatureSchema.required(),
|
||||
}).unknown(false)
|
||||
|
@ -8,5 +8,5 @@ export const filterSchema = Schema.object({
|
||||
kinds: Schema.array().items(kindSchema).max(20),
|
||||
since: createdAtSchema,
|
||||
until: createdAtSchema,
|
||||
limit: Schema.number().min(0).multiple(1).max(10000),
|
||||
limit: Schema.number().min(0).multiple(1).max(5000),
|
||||
}).pattern(/^#[a-z]$/, Schema.array().items(Schema.string().max(1024)).max(256))
|
||||
|
@ -12,7 +12,7 @@ export const eventMessageSchema = Schema.array().ordered(
|
||||
.label('EVENT message')
|
||||
|
||||
export const reqMessageSchema = Schema.array()
|
||||
.ordered(Schema.string().valid('REQ').required(), Schema.string().required().label('subscriptionId'))
|
||||
.ordered(Schema.string().valid('REQ').required(), Schema.string().max(256).required().label('subscriptionId'))
|
||||
.items(filterSchema.required().label('filter')).max(12)
|
||||
.label('REQ message')
|
||||
|
||||
|
@ -10,8 +10,8 @@ describe('NIP-01', () => {
|
||||
describe('validate filter schema', () => {
|
||||
beforeEach(() => {
|
||||
filter = {
|
||||
ids: ['aa', 'bb', 'cc'],
|
||||
authors: ['aa', 'bb', 'cc'],
|
||||
ids: ['aaaa', 'bbbb', 'cccc'],
|
||||
authors: ['aaaa', 'bbbb', 'cccc'],
|
||||
kinds: [0, 1, 2, 3],
|
||||
since: 1000,
|
||||
until: 1000,
|
||||
@ -32,7 +32,7 @@ describe('NIP-01', () => {
|
||||
const cases = {
|
||||
ids: [
|
||||
{ message: 'must be an array', transform: assocPath(['ids'], null) },
|
||||
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['ids'], range(0, 1001).map(() => 'f')) },
|
||||
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['ids'], range(0, 1001).map(() => 'ffff')) },
|
||||
],
|
||||
prefixOrId: [
|
||||
{ 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', () => {
|
||||
],
|
||||
authors: [
|
||||
{ message: 'must be an array', transform: assocPath(['authors'], null) },
|
||||
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['authors'], range(0, 1001).map(() => 'f')) },
|
||||
{ message: 'must contain less than or equal to 1000 items', transform: assocPath(['authors'], range(0, 1001).map(() => 'ffff')) },
|
||||
],
|
||||
prefixOrAuthor: [
|
||||
{ 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', () => {
|
||||
{ message: 'must be a number', transform: assocPath(['limit'], null) },
|
||||
{ message: 'must be greater than or equal to 0', transform: assocPath(['limit'], -1) },
|
||||
{ message: 'must be a multiple of 1', transform: assocPath(['limit'], Math.PI) },
|
||||
{ message: 'must be less than or equal to 10000', transform: assocPath(['limit'], 10001) },
|
||||
{ message: 'must be less than or equal to 5000', transform: assocPath(['limit'], 5001) },
|
||||
],
|
||||
'#e': [
|
||||
{ message: 'must be an array', transform: assocPath(['#e'], null) },
|
||||
|
@ -25,6 +25,8 @@ describe('NIP-01', () => {
|
||||
|
||||
const result = validateSchema(messageSchema)(message)
|
||||
|
||||
console.log(result)
|
||||
|
||||
expect(result).not.to.have.property('error')
|
||||
expect(result).to.have.deep.property('value', message)
|
||||
})
|
||||
@ -56,8 +58,8 @@ describe('NIP-01', () => {
|
||||
'REQ',
|
||||
'id',
|
||||
{
|
||||
ids: ['aa', 'bb', 'cc'],
|
||||
authors: ['aa', 'bb', 'cc'],
|
||||
ids: ['aaaa', 'bbbb', 'cccc'],
|
||||
authors: ['aaaa', 'bbbb', 'cccc'],
|
||||
kinds: [0, 1, 2, 3],
|
||||
since: 1000,
|
||||
until: 1000,
|
||||
@ -67,8 +69,8 @@ describe('NIP-01', () => {
|
||||
'#r': ['00', '11', '22'],
|
||||
},
|
||||
{
|
||||
ids: ['aa', 'bb', 'cc'],
|
||||
authors: ['aa', 'bb', 'cc'],
|
||||
ids: ['aaaa', 'bbbb', 'cccc'],
|
||||
authors: ['aaaa', 'bbbb', 'cccc'],
|
||||
kinds: [0, 1, 2, 3],
|
||||
since: 1000,
|
||||
until: 1000,
|
||||
@ -82,7 +84,7 @@ describe('NIP-01', () => {
|
||||
|
||||
it('returns same message if valid', () => {
|
||||
const result = validateSchema(messageSchema)(message)
|
||||
|
||||
console.log('result', result)
|
||||
expect(result).not.to.have.property('error')
|
||||
expect(result).to.have.deep.property('value', message)
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user