mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 08:38:50 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d81a2444b3 | ||
|
|
7507943253 | ||
|
|
b9a7f814aa | ||
|
|
0e364701da | ||
|
|
a55fb8465f |
@@ -4,6 +4,8 @@ Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
|
|||||||
|
|
||||||
Only depends on _@scure_ and _@noble_ packages.
|
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
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
4
event.ts
4
event.ts
@@ -27,8 +27,8 @@ export enum Kind {
|
|||||||
Zap = 9735,
|
Zap = 9735,
|
||||||
RelayList = 10002,
|
RelayList = 10002,
|
||||||
ClientAuth = 22242,
|
ClientAuth = 22242,
|
||||||
BadgeDefinition = 30008,
|
ProfileBadge = 30008,
|
||||||
ProfileBadge = 30009,
|
BadgeDefinition = 30009,
|
||||||
Article = 30023
|
Article = 30023
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {matchFilter, matchFilters} from './filter.ts'
|
import {matchFilter, matchFilters, mergeFilters} from './filter.ts'
|
||||||
import {buildEvent} from './test-helpers.ts'
|
import {buildEvent} from './test-helpers.ts'
|
||||||
|
|
||||||
describe('Filter', () => {
|
describe('Filter', () => {
|
||||||
@@ -18,7 +18,7 @@ describe('Filter', () => {
|
|||||||
kind: 1,
|
kind: 1,
|
||||||
pubkey: 'abc',
|
pubkey: 'abc',
|
||||||
created_at: 150,
|
created_at: 150,
|
||||||
tags: [['tag', 'value']],
|
tags: [['tag', 'value']]
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = matchFilter(filter, event)
|
const result = matchFilter(filter, event)
|
||||||
@@ -162,7 +162,12 @@ describe('Filter', () => {
|
|||||||
{authors: ['abc'], limit: 3}
|
{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)
|
const result = matchFilters(filters, event)
|
||||||
|
|
||||||
@@ -189,11 +194,35 @@ describe('Filter', () => {
|
|||||||
{kinds: [1], limit: 2},
|
{kinds: [1], limit: 2},
|
||||||
{authors: ['abc'], limit: 3}
|
{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)
|
const result = matchFilters(filters, event)
|
||||||
|
|
||||||
expect(result).toEqual(false)
|
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})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
34
filter.ts
34
filter.ts
@@ -56,3 +56,37 @@ export function matchFilters(
|
|||||||
}
|
}
|
||||||
return false
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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', () => {
|
test('replaceAll', () => {
|
||||||
const content =
|
const content =
|
||||||
'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky'
|
'Hello nostr:npub108pv4cg5ag52nq082kd5leu9ffrn2gdg6g4xdwatn73y36uzplmq9uyev6!\n\nnostr:note1gmtnz6q2m55epmlpe3semjdcq987av3jvx4emmjsa8g3s9x7tg4sclreky'
|
||||||
|
|||||||
23
nip27.ts
23
nip27.ts
@@ -2,8 +2,7 @@ import {decode} from './nip19.ts'
|
|||||||
import {NOSTR_URI_REGEX, type NostrURI} from './nip21.ts'
|
import {NOSTR_URI_REGEX, type NostrURI} from './nip21.ts'
|
||||||
|
|
||||||
/** Regex to find NIP-21 URIs inside event content. */
|
/** Regex to find NIP-21 URIs inside event content. */
|
||||||
export const regex = () =>
|
export const regex = () => new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, 'g')
|
||||||
new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, 'g')
|
|
||||||
|
|
||||||
/** Match result for a Nostr URI in event content. */
|
/** Match result for a Nostr URI in event content. */
|
||||||
export interface NostrURIMatch extends NostrURI {
|
export interface NostrURIMatch extends NostrURI {
|
||||||
@@ -14,18 +13,22 @@ export interface NostrURIMatch extends NostrURI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Find and decode all NIP-21 URIs. */
|
/** 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())
|
const matches = content.matchAll(regex())
|
||||||
|
|
||||||
for (const match of matches) {
|
for (const match of matches) {
|
||||||
const [uri, value] = match
|
try {
|
||||||
|
const [uri, value] = match
|
||||||
|
|
||||||
yield {
|
yield {
|
||||||
uri: uri as `nostr:${string}`,
|
uri: uri as `nostr:${string}`,
|
||||||
value,
|
value,
|
||||||
decoded: decode(value),
|
decoded: decode(value),
|
||||||
start: match.index!,
|
start: match.index!,
|
||||||
end: match.index! + uri.length
|
end: match.index! + uri.length
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nostr-tools",
|
"name": "nostr-tools",
|
||||||
"version": "1.11.2",
|
"version": "1.12.1",
|
||||||
"description": "Tools for making a Nostr client.",
|
"description": "Tools for making a Nostr client.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
Reference in New Issue
Block a user