Compare commits

..

5 Commits

Author SHA1 Message Date
fiatjaf
d81a2444b3 release v1.12.1 2023-06-29 15:25:32 -03:00
Alex Gleason
7507943253 Fix nip27.matchAll crash on invalid nip19 2023-06-29 15:24:25 -03:00
PMK
b9a7f814aa Update Kind for ProfileBadge and BadgeDefinition 2023-06-20 15:40:55 -03:00
fiatjaf
0e364701da link to ndk and snort system. 2023-06-17 08:37:20 -03:00
fiatjaf
a55fb8465f mergeFilters() 2023-06-09 23:00:57 -03:00
7 changed files with 104 additions and 17 deletions

View File

@@ -4,6 +4,8 @@ Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
Only depends on _@scure_ and _@noble_ packages.
This package is only providing lower-level functionality. If you want an easy-to-use fully-fledged solution that abstracts the hard parts of Nostr and makes decisions on your behalf, take a look at [NDK](https://github.com/nostr-dev-kit/ndk) and [@snort/system](https://www.npmjs.com/package/@snort/system).
## Installation
```bash

View File

@@ -27,8 +27,8 @@ export enum Kind {
Zap = 9735,
RelayList = 10002,
ClientAuth = 22242,
BadgeDefinition = 30008,
ProfileBadge = 30009,
ProfileBadge = 30008,
BadgeDefinition = 30009,
Article = 30023
}

View File

@@ -1,4 +1,4 @@
import {matchFilter, matchFilters} from './filter.ts'
import {matchFilter, matchFilters, mergeFilters} from './filter.ts'
import {buildEvent} from './test-helpers.ts'
describe('Filter', () => {
@@ -18,7 +18,7 @@ describe('Filter', () => {
kind: 1,
pubkey: 'abc',
created_at: 150,
tags: [['tag', 'value']],
tags: [['tag', 'value']]
})
const result = matchFilter(filter, event)
@@ -162,7 +162,12 @@ describe('Filter', () => {
{authors: ['abc'], limit: 3}
]
const event = buildEvent({id: '123', kind: 1, pubkey: 'abc', created_at: 150})
const event = buildEvent({
id: '123',
kind: 1,
pubkey: 'abc',
created_at: 150
})
const result = matchFilters(filters, event)
@@ -189,11 +194,35 @@ describe('Filter', () => {
{kinds: [1], limit: 2},
{authors: ['abc'], limit: 3}
]
const event = buildEvent({id: '456', kind: 2, pubkey: 'def', created_at: 200})
const event = buildEvent({
id: '456',
kind: 2,
pubkey: 'def',
created_at: 200
})
const result = matchFilters(filters, event)
expect(result).toEqual(false)
})
})
describe('mergeFilters', () => {
it('should merge filters', () => {
expect(
mergeFilters(
{ids: ['a', 'b'], limit: 3},
{authors: ['x'], ids: ['b', 'c']}
)
).toEqual({ids: ['a', 'b', 'c'], limit: 3, authors: ['x']})
expect(
mergeFilters(
{kinds: [1], since: 15, until: 30},
{since: 10, kinds: [7], until: 15},
{kinds: [9, 10]}
)
).toEqual({kinds: [1, 7, 9, 10], since: 10, until: 30})
})
})
})

View File

@@ -56,3 +56,37 @@ export function matchFilters(
}
return false
}
export function mergeFilters(...filters: Filter<number>[]): Filter<number> {
let result: Filter<number> = {}
for (let i = 0; i < filters.length; i++) {
let filter = filters[i]
Object.entries(filter).forEach(([property, values]) => {
if (
property === 'kinds' ||
property === 'ids' ||
property === 'authors' ||
property[0] === '#'
) {
// @ts-ignore
result[property] = result[property] || []
// @ts-ignore
for (let v = 0; v < values.length; v++) {
// @ts-ignore
let value = values[v]
// @ts-ignore
if (!result[property].includes(value)) result[property].push(value)
}
}
})
if (filter.limit && (!result.limit || filter.limit > result.limit))
result.limit = filter.limit
if (filter.until && (!result.until || filter.until > result.until))
result.until = filter.until
if (filter.since && (!result.since || filter.since < result.since))
result.since = filter.since
}
return result
}

View File

@@ -29,6 +29,25 @@ test('matchAll', () => {
])
})
test('matchAll with an invalid nip19', () => {
const result = matchAll(
'Hello npub129tvj896hqqkljerxkccpj9flshwnw999v9uwn9lfmwlj8vnzwgq9y5llnpub1rujdpkd8mwezrvpqd2rx2zphfaztqrtsfg6w3vdnlj!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky'
)
expect([...result]).toEqual([
{
decoded: {
data: '46d731680add2990efe1cc619dc9b8014feeb23261ab9dee50e9d11814de5a2b',
type: 'note'
},
end: 187,
start: 118,
uri: 'nostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky',
value: 'note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky'
}
])
})
test('replaceAll', () => {
const content =
'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky'

View File

@@ -2,8 +2,7 @@ import {decode} from './nip19.ts'
import {NOSTR_URI_REGEX, type NostrURI} from './nip21.ts'
/** Regex to find NIP-21 URIs inside event content. */
export const regex = () =>
new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, 'g')
export const regex = () => new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, 'g')
/** Match result for a Nostr URI in event content. */
export interface NostrURIMatch extends NostrURI {
@@ -14,10 +13,11 @@ export interface NostrURIMatch extends NostrURI {
}
/** Find and decode all NIP-21 URIs. */
export function * matchAll(content: string): Iterable<NostrURIMatch> {
export function* matchAll(content: string): Iterable<NostrURIMatch> {
const matches = content.matchAll(regex())
for (const match of matches) {
try {
const [uri, value] = match
yield {
@@ -27,6 +27,9 @@ export function * matchAll(content: string): Iterable<NostrURIMatch> {
start: match.index!,
end: match.index! + uri.length
}
} catch (_e) {
// do nothing
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "nostr-tools",
"version": "1.11.2",
"version": "1.12.1",
"description": "Tools for making a Nostr client.",
"repository": {
"type": "git",