mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-08 16:28:49 +00:00
Compare commits
15 Commits
v1.15.0
...
kind-as-nu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fccf0ae48 | ||
|
|
842cba25f3 | ||
|
|
318e3f8c88 | ||
|
|
894ffff1f0 | ||
|
|
ce11a5fc89 | ||
|
|
5e85bbc2ed | ||
|
|
eb0a9093f2 | ||
|
|
c73268c4e2 | ||
|
|
6874f58c0a | ||
|
|
e899cc32b7 | ||
|
|
de72172583 | ||
|
|
073dcaafd6 | ||
|
|
8e932f0c5a | ||
|
|
f9a048679f | ||
|
|
6db8b94275 |
20
README.md
20
README.md
@@ -90,13 +90,12 @@ sub.on('event', event => {
|
||||
|
||||
let event = {
|
||||
kind: 1,
|
||||
pubkey: pk,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [],
|
||||
content: 'hello world',
|
||||
}
|
||||
|
||||
// this calculates the event id and signs the event in a single step
|
||||
// this assigns the pubkey, calculates the event id and signs the event in a single step
|
||||
const signedEvent = finishEvent(event, sk)
|
||||
await relay.publish(signedEvent)
|
||||
|
||||
@@ -145,12 +144,19 @@ let event = await pool.get(relays, {
|
||||
ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
|
||||
})
|
||||
|
||||
let batchedEvents = await pool.batchedList('notes', relays, [{ kinds: [1] }])
|
||||
// `batchedList` will wait for other function calls with the same `batchKey`
|
||||
// (e.g. 'notes', 'authors', etc) within a fixed amount of time (default: `100ms`) before sending
|
||||
// next ws request, and batch all requests with similar `batchKey`s together in a single request.
|
||||
|
||||
let relaysForEvent = pool.seenOn('44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245')
|
||||
// relaysForEvent will be an array of URLs from relays a given event was seen on
|
||||
|
||||
pool.close()
|
||||
```
|
||||
|
||||
read more details about `batchedList` on this pr: [https://github.com/nbd-wtf/nostr-tools/pull/279](https://github.com/nbd-wtf/nostr-tools/pull/279#issue-1859315757)
|
||||
|
||||
### Parsing references (mentions) from a content using NIP-10 and NIP-27
|
||||
|
||||
```js
|
||||
@@ -218,7 +224,7 @@ assert(data.relays.length === 2)
|
||||
### Encrypting and decrypting direct messages
|
||||
|
||||
```js
|
||||
import { nip04, getPublicKey, generatePrivateKey } from 'nostr-tools'
|
||||
import {nip44, getPublicKey, generatePrivateKey} from 'nostr-tools'
|
||||
|
||||
// sender
|
||||
let sk1 = generatePrivateKey()
|
||||
@@ -230,7 +236,8 @@ let pk2 = getPublicKey(sk2)
|
||||
|
||||
// on the sender side
|
||||
let message = 'hello'
|
||||
let ciphertext = await nip04.encrypt(sk1, pk2, message)
|
||||
let key = nip44.getSharedSecret(sk1, pk2)
|
||||
let ciphertext = nip44.encrypt(key, message)
|
||||
|
||||
let event = {
|
||||
kind: 4,
|
||||
@@ -245,8 +252,9 @@ sendEvent(event)
|
||||
// on the receiver side
|
||||
sub.on('event', async event => {
|
||||
let sender = event.pubkey
|
||||
pk1 === sender
|
||||
let plaintext = await nip04.decrypt(sk2, pk1, event.content)
|
||||
// pk1 === sender
|
||||
let _key = nip44.getSharedSecret(sk2, pk1)
|
||||
let plaintext = nip44.decrypt(_key, event.content)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
15
build.js
15
build.js
@@ -2,9 +2,17 @@
|
||||
|
||||
const fs = require('fs')
|
||||
const esbuild = require('esbuild')
|
||||
const { join } = require('path');
|
||||
|
||||
const entryPoints = fs.readdirSync(process.cwd())
|
||||
.filter(
|
||||
(file) =>
|
||||
file.endsWith(".ts") && !file.endsWith("test.ts") &&
|
||||
fs.statSync(join(process.cwd(), file)).isFile()
|
||||
);
|
||||
|
||||
let common = {
|
||||
entryPoints: ['index.ts'],
|
||||
entryPoints,
|
||||
bundle: true,
|
||||
sourcemap: 'external',
|
||||
}
|
||||
@@ -12,7 +20,7 @@ let common = {
|
||||
esbuild
|
||||
.build({
|
||||
...common,
|
||||
outfile: 'lib/esm/nostr.mjs',
|
||||
outdir: 'lib/esm',
|
||||
format: 'esm',
|
||||
packages: 'external',
|
||||
})
|
||||
@@ -26,7 +34,7 @@ esbuild
|
||||
esbuild
|
||||
.build({
|
||||
...common,
|
||||
outfile: 'lib/nostr.cjs.js',
|
||||
outdir: 'lib/cjs',
|
||||
format: 'cjs',
|
||||
packages: 'external',
|
||||
})
|
||||
@@ -35,6 +43,7 @@ esbuild
|
||||
esbuild
|
||||
.build({
|
||||
...common,
|
||||
entryPoints: ['index.ts'],
|
||||
outfile: 'lib/nostr.bundle.js',
|
||||
format: 'iife',
|
||||
globalName: 'NostrTools',
|
||||
|
||||
@@ -14,7 +14,7 @@ import { getPublicKey } from './keys.ts'
|
||||
describe('Event', () => {
|
||||
describe('getBlankEvent', () => {
|
||||
it('should return a blank event object', () => {
|
||||
expect(getBlankEvent()).toEqual({
|
||||
expect(getBlankEvent(255)).toEqual({
|
||||
kind: 255,
|
||||
content: '',
|
||||
tags: [],
|
||||
|
||||
61
event.ts
61
event.ts
@@ -8,35 +8,34 @@ import { utf8Encoder } from './utils.ts'
|
||||
/** Designates a verified event signature. */
|
||||
export const verifiedSymbol = Symbol('verified')
|
||||
|
||||
/** @deprecated Use numbers instead. */
|
||||
/* eslint-disable no-unused-vars */
|
||||
export enum Kind {
|
||||
Metadata = 0,
|
||||
Text = 1,
|
||||
RecommendRelay = 2,
|
||||
Contacts = 3,
|
||||
EncryptedDirectMessage = 4,
|
||||
EventDeletion = 5,
|
||||
Repost = 6,
|
||||
Reaction = 7,
|
||||
BadgeAward = 8,
|
||||
ChannelCreation = 40,
|
||||
ChannelMetadata = 41,
|
||||
ChannelMessage = 42,
|
||||
ChannelHideMessage = 43,
|
||||
ChannelMuteUser = 44,
|
||||
Blank = 255,
|
||||
Report = 1984,
|
||||
ZapRequest = 9734,
|
||||
Zap = 9735,
|
||||
RelayList = 10002,
|
||||
ClientAuth = 22242,
|
||||
HttpAuth = 27235,
|
||||
ProfileBadge = 30008,
|
||||
BadgeDefinition = 30009,
|
||||
Article = 30023,
|
||||
FileMetadata = 1063,
|
||||
}
|
||||
export const Kind = {
|
||||
Metadata: 0,
|
||||
Text: 1,
|
||||
RecommendRelay: 2,
|
||||
Contacts: 3,
|
||||
EncryptedDirectMessage: 4,
|
||||
EventDeletion: 5,
|
||||
Repost: 6,
|
||||
Reaction: 7,
|
||||
BadgeAward: 8,
|
||||
ChannelCreation: 40,
|
||||
ChannelMetadata: 41,
|
||||
ChannelMessage: 42,
|
||||
ChannelHideMessage: 43,
|
||||
ChannelMuteUser: 44,
|
||||
Blank: 255,
|
||||
Report: 1984,
|
||||
ZapRequest: 9734,
|
||||
Zap: 9735,
|
||||
RelayList: 10002,
|
||||
ClientAuth: 22242,
|
||||
NwcRequest: 23194,
|
||||
HttpAuth: 27235,
|
||||
ProfileBadge: 30008,
|
||||
BadgeDefinition: 30009,
|
||||
Article: 30023,
|
||||
FileMetadata: 1063,
|
||||
} as const
|
||||
|
||||
export interface Event<K extends number = number> {
|
||||
kind: K
|
||||
@@ -60,9 +59,7 @@ export interface VerifiedEvent<K extends number = number> extends Event<K> {
|
||||
[verifiedSymbol]: true
|
||||
}
|
||||
|
||||
export function getBlankEvent(): EventTemplate<Kind.Blank>
|
||||
export function getBlankEvent<K extends number>(kind: K): EventTemplate<K>
|
||||
export function getBlankEvent<K>(kind: K | Kind.Blank = Kind.Blank) {
|
||||
export function getBlankEvent(kind: number = 255): EventTemplate {
|
||||
return {
|
||||
kind,
|
||||
content: '',
|
||||
|
||||
1
index.ts
1
index.ts
@@ -20,6 +20,7 @@ export * as nip28 from './nip28.ts'
|
||||
export * as nip39 from './nip39.ts'
|
||||
export * as nip42 from './nip42.ts'
|
||||
export * as nip44 from './nip44.ts'
|
||||
export * as nip47 from './nip47.ts'
|
||||
export * as nip57 from './nip57.ts'
|
||||
export * as nip98 from './nip98.ts'
|
||||
|
||||
|
||||
8
justfile
8
justfile
@@ -20,9 +20,9 @@ publish: build emit-types
|
||||
npm publish
|
||||
|
||||
format:
|
||||
eslint --ext .ts --fix .
|
||||
prettier --write .
|
||||
eslint --ext .ts --fix *.ts
|
||||
prettier --write *.ts
|
||||
|
||||
lint:
|
||||
eslint --ext .ts .
|
||||
prettier --check .
|
||||
eslint --ext .ts *.ts
|
||||
prettier --check *.ts
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
import { getPow } from './nip13.ts'
|
||||
import { getPow, minePow } from './nip13.ts'
|
||||
import { Kind } from './event.ts'
|
||||
|
||||
test('identifies proof-of-work difficulty', async () => {
|
||||
const id = '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358'
|
||||
const difficulty = getPow(id)
|
||||
expect(difficulty).toEqual(21)
|
||||
})
|
||||
|
||||
test('mines POW for an event', async () => {
|
||||
const difficulty = 10
|
||||
|
||||
const event = minePow(
|
||||
{
|
||||
kind: Kind.Text,
|
||||
tags: [],
|
||||
content: 'Hello, world!',
|
||||
created_at: 0,
|
||||
pubkey: '79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6',
|
||||
},
|
||||
difficulty,
|
||||
)
|
||||
|
||||
expect(getPow(event.id)).toBeGreaterThanOrEqual(difficulty)
|
||||
})
|
||||
|
||||
36
nip13.ts
36
nip13.ts
@@ -1,3 +1,5 @@
|
||||
import { type UnsignedEvent, type Event, getEventHash } from './event.ts'
|
||||
|
||||
/** Get POW difficulty from a Nostr hex ID. */
|
||||
export function getPow(hex: string): number {
|
||||
let count = 0
|
||||
@@ -14,3 +16,37 @@ export function getPow(hex: string): number {
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
/**
|
||||
* Mine an event with the desired POW. This function mutates the event.
|
||||
* Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.
|
||||
*
|
||||
* Adapted from Snort: https://git.v0l.io/Kieran/snort/src/commit/4df6c19248184218c4c03728d61e94dae5f2d90c/packages/system/src/pow-util.ts#L14-L36
|
||||
*/
|
||||
export function minePow<K extends number>(unsigned: UnsignedEvent<K>, difficulty: number): Omit<Event<K>, 'sig'> {
|
||||
let count = 0
|
||||
|
||||
const event = unsigned as Omit<Event<K>, 'sig'>
|
||||
const tag = ['nonce', count.toString(), difficulty.toString()]
|
||||
|
||||
event.tags.push(tag)
|
||||
|
||||
while (true) {
|
||||
const now = Math.floor(new Date().getTime() / 1000)
|
||||
|
||||
if (now !== event.created_at) {
|
||||
count = 0
|
||||
event.created_at = now
|
||||
}
|
||||
|
||||
tag[1] = (++count).toString()
|
||||
|
||||
event.id = getEventHash(event)
|
||||
|
||||
if (getPow(event.id) >= difficulty) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
2
nip18.ts
2
nip18.ts
@@ -23,7 +23,7 @@ export function finishRepostEvent(
|
||||
reposted: Event<number>,
|
||||
relayUrl: string,
|
||||
privateKey: string,
|
||||
): Event<Kind.Repost> {
|
||||
): Event {
|
||||
return finishEvent(
|
||||
{
|
||||
kind: Kind.Repost,
|
||||
|
||||
@@ -6,8 +6,10 @@ import {
|
||||
npubEncode,
|
||||
nrelayEncode,
|
||||
nsecEncode,
|
||||
neventEncode,
|
||||
type AddressPointer,
|
||||
type ProfilePointer,
|
||||
EventPointer,
|
||||
} from './nip19.ts'
|
||||
|
||||
test('encode and decode nsec', () => {
|
||||
@@ -72,6 +74,40 @@ test('encode and decode naddr', () => {
|
||||
expect(pointer.identifier).toEqual('banana')
|
||||
})
|
||||
|
||||
test('encode and decode nevent', () => {
|
||||
let pk = getPublicKey(generatePrivateKey())
|
||||
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
|
||||
let naddr = neventEncode({
|
||||
id: pk,
|
||||
relays,
|
||||
kind: 30023,
|
||||
})
|
||||
expect(naddr).toMatch(/nevent1\w+/)
|
||||
let { type, data } = decode(naddr)
|
||||
expect(type).toEqual('nevent')
|
||||
const pointer = data as EventPointer
|
||||
expect(pointer.id).toEqual(pk)
|
||||
expect(pointer.relays).toContain(relays[0])
|
||||
expect(pointer.kind).toEqual(30023)
|
||||
})
|
||||
|
||||
test('encode and decode nevent with kind 0', () => {
|
||||
let pk = getPublicKey(generatePrivateKey())
|
||||
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
|
||||
let naddr = neventEncode({
|
||||
id: pk,
|
||||
relays,
|
||||
kind: 0,
|
||||
})
|
||||
expect(naddr).toMatch(/nevent1\w+/)
|
||||
let { type, data } = decode(naddr)
|
||||
expect(type).toEqual('nevent')
|
||||
const pointer = data as EventPointer
|
||||
expect(pointer.id).toEqual(pk)
|
||||
expect(pointer.relays).toContain(relays[0])
|
||||
expect(pointer.kind).toEqual(0)
|
||||
})
|
||||
|
||||
test('decode naddr from habla.news', () => {
|
||||
let { type, data } = decode(
|
||||
'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5',
|
||||
|
||||
23
nip19.ts
23
nip19.ts
@@ -11,6 +11,19 @@ const Bech32MaxSize = 5000
|
||||
*/
|
||||
export const BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/
|
||||
|
||||
function integerToUint8Array(number: number) {
|
||||
// Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).
|
||||
const uint8Array = new Uint8Array(4)
|
||||
|
||||
// Use bitwise operations to extract the bytes.
|
||||
uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)
|
||||
uint8Array[1] = (number >> 16) & 0xff
|
||||
uint8Array[2] = (number >> 8) & 0xff
|
||||
uint8Array[3] = number & 0xff // Least significant byte (LSB)
|
||||
|
||||
return uint8Array
|
||||
}
|
||||
|
||||
export type ProfilePointer = {
|
||||
pubkey: string // hex
|
||||
relays?: string[]
|
||||
@@ -20,6 +33,7 @@ export type EventPointer = {
|
||||
id: string // hex
|
||||
relays?: string[]
|
||||
author?: string
|
||||
kind?: number
|
||||
}
|
||||
|
||||
export type AddressPointer = {
|
||||
@@ -73,6 +87,7 @@ export function decode(nip19: string): DecodeResult {
|
||||
if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')
|
||||
if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')
|
||||
if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')
|
||||
if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')
|
||||
|
||||
return {
|
||||
type: 'nevent',
|
||||
@@ -80,6 +95,7 @@ export function decode(nip19: string): DecodeResult {
|
||||
id: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,
|
||||
kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -172,11 +188,18 @@ export function nprofileEncode(profile: ProfilePointer): `nprofile1${string}` {
|
||||
}
|
||||
|
||||
export function neventEncode(event: EventPointer): `nevent1${string}` {
|
||||
let kindArray
|
||||
if (event.kind != undefined) {
|
||||
kindArray = integerToUint8Array(event.kind)
|
||||
}
|
||||
|
||||
let data = encodeTLV({
|
||||
0: [hexToBytes(event.id)],
|
||||
1: (event.relays || []).map(url => utf8Encoder.encode(url)),
|
||||
2: event.author ? [hexToBytes(event.author)] : [],
|
||||
3: kindArray ? [new Uint8Array(kindArray)] : [],
|
||||
})
|
||||
|
||||
return encodeBech32('nevent', data)
|
||||
}
|
||||
|
||||
|
||||
6
nip25.ts
6
nip25.ts
@@ -16,11 +16,7 @@ export type ReactionEventTemplate = {
|
||||
created_at: number
|
||||
}
|
||||
|
||||
export function finishReactionEvent(
|
||||
t: ReactionEventTemplate,
|
||||
reacted: Event<number>,
|
||||
privateKey: string,
|
||||
): Event<Kind.Reaction> {
|
||||
export function finishReactionEvent(t: ReactionEventTemplate, reacted: Event<number>, privateKey: string): Event {
|
||||
const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))
|
||||
|
||||
return finishEvent(
|
||||
|
||||
13
nip28.ts
13
nip28.ts
@@ -44,10 +44,7 @@ export interface ChannelMuteUserEventTemplate {
|
||||
tags?: string[][]
|
||||
}
|
||||
|
||||
export const channelCreateEvent = (
|
||||
t: ChannelCreateEventTemplate,
|
||||
privateKey: string,
|
||||
): Event<Kind.ChannelCreation> | undefined => {
|
||||
export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: string): Event | undefined => {
|
||||
let content: string
|
||||
if (typeof t.content === 'object') {
|
||||
content = JSON.stringify(t.content)
|
||||
@@ -71,7 +68,7 @@ export const channelCreateEvent = (
|
||||
export const channelMetadataEvent = (
|
||||
t: ChannelMetadataEventTemplate,
|
||||
privateKey: string,
|
||||
): Event<Kind.ChannelMetadata> | undefined => {
|
||||
): Event | undefined => {
|
||||
let content: string
|
||||
if (typeof t.content === 'object') {
|
||||
content = JSON.stringify(t.content)
|
||||
@@ -92,7 +89,7 @@ export const channelMetadataEvent = (
|
||||
)
|
||||
}
|
||||
|
||||
export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: string): Event<Kind.ChannelMessage> => {
|
||||
export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: string): Event => {
|
||||
const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]
|
||||
|
||||
if (t.reply_to_channel_message_event_id) {
|
||||
@@ -114,7 +111,7 @@ export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey:
|
||||
export const channelHideMessageEvent = (
|
||||
t: ChannelHideMessageEventTemplate,
|
||||
privateKey: string,
|
||||
): Event<Kind.ChannelHideMessage> | undefined => {
|
||||
): Event | undefined => {
|
||||
let content: string
|
||||
if (typeof t.content === 'object') {
|
||||
content = JSON.stringify(t.content)
|
||||
@@ -138,7 +135,7 @@ export const channelHideMessageEvent = (
|
||||
export const channelMuteUserEvent = (
|
||||
t: ChannelMuteUserEventTemplate,
|
||||
privateKey: string,
|
||||
): Event<Kind.ChannelMuteUser> | undefined => {
|
||||
): Event | undefined => {
|
||||
let content: string
|
||||
if (typeof t.content === 'object') {
|
||||
content = JSON.stringify(t.content)
|
||||
|
||||
@@ -1,21 +1,75 @@
|
||||
import crypto from 'node:crypto'
|
||||
import { hexToBytes } from '@noble/hashes/utils'
|
||||
import { encrypt, decrypt, utils } from './nip44.ts'
|
||||
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
|
||||
import { v2 as vectors } from './nip44.vectors.json'
|
||||
import { getPublicKey } from './keys.ts'
|
||||
|
||||
import { encrypt, decrypt, getSharedSecret } from './nip44.ts'
|
||||
import { getPublicKey, generatePrivateKey } from './keys.ts'
|
||||
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-undef
|
||||
globalThis.crypto = crypto
|
||||
|
||||
test('encrypt and decrypt message', async () => {
|
||||
let sk1 = generatePrivateKey()
|
||||
let sk2 = generatePrivateKey()
|
||||
let pk1 = getPublicKey(sk1)
|
||||
let pk2 = getPublicKey(sk2)
|
||||
let sharedKey1 = getSharedSecret(sk1, pk2)
|
||||
let sharedKey2 = getSharedSecret(sk2, pk1)
|
||||
|
||||
expect(decrypt(hexToBytes(sk1), encrypt(hexToBytes(sk1), 'hello'))).toEqual('hello')
|
||||
expect(decrypt(sharedKey2, encrypt(sharedKey1, 'hello'))).toEqual('hello')
|
||||
test('NIP44: valid_sec', async () => {
|
||||
for (const v of vectors.valid_sec) {
|
||||
const pub2 = getPublicKey(v.sec2)
|
||||
const key = utils.v2.getConversationKey(v.sec1, pub2)
|
||||
expect(bytesToHex(key)).toEqual(v.shared)
|
||||
const ciphertext = encrypt(key, v.plaintext, { salt: hexToBytes(v.salt) })
|
||||
expect(ciphertext).toEqual(v.ciphertext)
|
||||
const decrypted = decrypt(key, ciphertext)
|
||||
expect(decrypted).toEqual(v.plaintext)
|
||||
}
|
||||
})
|
||||
|
||||
test('NIP44: valid_pub', async () => {
|
||||
for (const v of vectors.valid_pub) {
|
||||
const key = utils.v2.getConversationKey(v.sec1, v.pub2)
|
||||
expect(bytesToHex(key)).toEqual(v.shared)
|
||||
const ciphertext = encrypt(key, v.plaintext, { salt: hexToBytes(v.salt) })
|
||||
expect(ciphertext).toEqual(v.ciphertext)
|
||||
const decrypted = decrypt(key, ciphertext)
|
||||
expect(decrypted).toEqual(v.plaintext)
|
||||
}
|
||||
})
|
||||
|
||||
test('NIP44: invalid', async () => {
|
||||
for (const v of vectors.invalid) {
|
||||
expect(() => {
|
||||
const key = utils.v2.getConversationKey(v.sec1, v.pub2)
|
||||
const ciphertext = decrypt(key, v.ciphertext)
|
||||
}).toThrowError(v.note)
|
||||
}
|
||||
})
|
||||
|
||||
test('NIP44: invalid_conversation_key', async () => {
|
||||
for (const v of vectors.invalid_conversation_key) {
|
||||
expect(() => {
|
||||
const key = utils.v2.getConversationKey(v.sec1, v.pub2)
|
||||
const ciphertext = encrypt(key, 'a')
|
||||
}).toThrowError()
|
||||
}
|
||||
})
|
||||
|
||||
test('NIP44: v1 calcPadding', () => {
|
||||
for (const [len, shouldBePaddedTo] of vectors.padding) {
|
||||
const actual = utils.v2.calcPadding(len)
|
||||
expect(actual).toEqual(shouldBePaddedTo)
|
||||
}
|
||||
})
|
||||
|
||||
// To re-generate vectors and produce new ones:
|
||||
// Create regen.mjs with this content:
|
||||
// import {getPublicKey, nip44} from './lib/esm/nostr.mjs'
|
||||
// import {bytesToHex, hexToBytes} from '@noble/hashes/utils'
|
||||
// import vectors from './nip44.vectors.json' assert { type: "json" };
|
||||
// function genVectors(v) {
|
||||
// const pub2 = v.pub2 ?? getPublicKey(v.sec2);
|
||||
// let sharedKey = nip44.utils.v2.getConversationKey(v.sec1, pub2)
|
||||
// let ciphertext = nip44.encrypt(sharedKey, v.plaintext, { salt: hexToBytes(v.salt) })
|
||||
// console.log({
|
||||
// sec1: v.sec1,
|
||||
// pub2: pub2,
|
||||
// sharedKey: bytesToHex(sharedKey),
|
||||
// salt: v.salt,
|
||||
// plaintext: v.plaintext,
|
||||
// ciphertext
|
||||
// })
|
||||
// }
|
||||
// for (let v of vectors.valid_sec) genVectors(v);
|
||||
// for (let v of vectors.valid_pub) genVectors(v);
|
||||
// const padded = concatBytes(utils.v2.pad(plaintext), new Uint8Array(250))
|
||||
// const mac = randomBytes(32)
|
||||
|
||||
125
nip44.ts
125
nip44.ts
@@ -1,40 +1,107 @@
|
||||
import { base64 } from '@scure/base'
|
||||
import { randomBytes } from '@noble/hashes/utils'
|
||||
import { chacha20 } from '@noble/ciphers/chacha'
|
||||
import { ensureBytes, equalBytes } from '@noble/ciphers/utils'
|
||||
import { secp256k1 } from '@noble/curves/secp256k1'
|
||||
import { hkdf } from '@noble/hashes/hkdf'
|
||||
import { hmac } from '@noble/hashes/hmac'
|
||||
import { sha256 } from '@noble/hashes/sha256'
|
||||
import { xchacha20 } from '@noble/ciphers/chacha'
|
||||
|
||||
import { concatBytes, randomBytes } from '@noble/hashes/utils'
|
||||
import { base64 } from '@scure/base'
|
||||
import { utf8Decoder, utf8Encoder } from './utils.ts'
|
||||
|
||||
export const getSharedSecret = (privkey: string, pubkey: string): Uint8Array =>
|
||||
sha256(secp256k1.getSharedSecret(privkey, '02' + pubkey).subarray(1, 33))
|
||||
export const utils = {
|
||||
v2: {
|
||||
maxPlaintextSize: 65536 - 128, // 64kb - 128
|
||||
minCiphertextSize: 100, // should be 128 if min padded to 32b: base64(1+32+32+32)
|
||||
maxCiphertextSize: 102400, // 100kb
|
||||
|
||||
export function encrypt(key: Uint8Array, text: string, v = 1) {
|
||||
if (v !== 1) {
|
||||
throw new Error('NIP44: unknown encryption version')
|
||||
}
|
||||
getConversationKey(privkeyA: string, pubkeyB: string): Uint8Array {
|
||||
const key = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB)
|
||||
return key.subarray(1, 33)
|
||||
},
|
||||
|
||||
const nonce = randomBytes(24)
|
||||
const plaintext = utf8Encoder.encode(text)
|
||||
const ciphertext = xchacha20(key, nonce, plaintext)
|
||||
getMessageKeys(conversationKey: Uint8Array, salt: Uint8Array) {
|
||||
const keys = hkdf(sha256, conversationKey, salt, 'nip44-v2', 76)
|
||||
return {
|
||||
encryption: keys.subarray(0, 32),
|
||||
nonce: keys.subarray(32, 44),
|
||||
auth: keys.subarray(44, 76),
|
||||
}
|
||||
},
|
||||
|
||||
const payload = new Uint8Array(25 + ciphertext.length)
|
||||
payload.set([v], 0)
|
||||
payload.set(nonce, 1)
|
||||
payload.set(ciphertext, 25)
|
||||
calcPadding(len: number): number {
|
||||
if (!Number.isSafeInteger(len) || len < 0) throw new Error('expected positive integer')
|
||||
if (len <= 32) return 32
|
||||
const nextpower = 1 << (Math.floor(Math.log2(len - 1)) + 1)
|
||||
const chunk = nextpower <= 256 ? 32 : nextpower / 8
|
||||
return chunk * (Math.floor((len - 1) / chunk) + 1)
|
||||
},
|
||||
|
||||
return base64.encode(payload)
|
||||
pad(unpadded: string): Uint8Array {
|
||||
const unpaddedB = utf8Encoder.encode(unpadded)
|
||||
const len = unpaddedB.length
|
||||
if (len < 1 || len >= utils.v2.maxPlaintextSize) throw new Error('invalid plaintext length: must be between 1b and 64KB')
|
||||
const paddedLen = utils.v2.calcPadding(len)
|
||||
const zeros = new Uint8Array(paddedLen - len)
|
||||
const lenBuf = new Uint8Array(2)
|
||||
new DataView(lenBuf.buffer).setUint16(0, len)
|
||||
return concatBytes(lenBuf, unpaddedB, zeros)
|
||||
},
|
||||
|
||||
unpad(padded: Uint8Array): string {
|
||||
const unpaddedLen = new DataView(padded.buffer).getUint16(0)
|
||||
const unpadded = padded.subarray(2, 2 + unpaddedLen)
|
||||
if (
|
||||
unpaddedLen === 0 ||
|
||||
unpadded.length !== unpaddedLen ||
|
||||
padded.length !== 2 + utils.v2.calcPadding(unpaddedLen)
|
||||
)
|
||||
throw new Error('invalid padding')
|
||||
return utf8Decoder.decode(unpadded)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export function decrypt(key: Uint8Array, payload: string) {
|
||||
let data = base64.decode(payload)
|
||||
if (data[0] !== 1) {
|
||||
throw new Error(`NIP44: unknown encryption version: ${data[0]}`)
|
||||
}
|
||||
|
||||
const nonce = data.slice(1, 25)
|
||||
const ciphertext = data.slice(25)
|
||||
const plaintext = xchacha20(key, nonce, ciphertext)
|
||||
|
||||
return utf8Decoder.decode(plaintext)
|
||||
export function encrypt(
|
||||
key: Uint8Array,
|
||||
plaintext: string,
|
||||
options: { salt?: Uint8Array; version?: number } = {},
|
||||
): string {
|
||||
const version = options.version ?? 2
|
||||
if (version !== 2) throw new Error('unknown encryption version ' + version)
|
||||
const salt = options.salt ?? randomBytes(32)
|
||||
ensureBytes(salt, 32)
|
||||
const keys = utils.v2.getMessageKeys(key, salt)
|
||||
const padded = utils.v2.pad(plaintext)
|
||||
const ciphertext = chacha20(keys.encryption, keys.nonce, padded)
|
||||
const mac = hmac(sha256, keys.auth, ciphertext)
|
||||
return base64.encode(concatBytes(new Uint8Array([version]), salt, ciphertext, mac))
|
||||
}
|
||||
|
||||
export function decrypt(key: Uint8Array, ciphertext: string): string {
|
||||
const u = utils.v2
|
||||
ensureBytes(key, 32)
|
||||
|
||||
const clen = ciphertext.length
|
||||
if (clen < u.minCiphertextSize || clen >= u.maxCiphertextSize) throw new Error('invalid ciphertext length: ' + clen)
|
||||
|
||||
if (ciphertext[0] === '#') throw new Error('unknown encryption version')
|
||||
let data: Uint8Array
|
||||
try {
|
||||
data = base64.decode(ciphertext)
|
||||
} catch (error) {
|
||||
throw new Error('invalid base64: ' + (error as any).message)
|
||||
}
|
||||
const vers = data.subarray(0, 1)[0]
|
||||
if (vers !== 2) throw new Error('unknown encryption version ' + vers)
|
||||
|
||||
const salt = data.subarray(1, 33)
|
||||
const ciphertext_ = data.subarray(33, -32)
|
||||
const mac = data.subarray(-32)
|
||||
|
||||
const keys = u.getMessageKeys(key, salt)
|
||||
const calculatedMac = hmac(sha256, keys.auth, ciphertext_)
|
||||
if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')
|
||||
|
||||
const padded = chacha20(keys.encryption, keys.nonce, ciphertext_)
|
||||
return u.unpad(padded)
|
||||
}
|
||||
|
||||
245
nip44.vectors.json
Normal file
245
nip44.vectors.json
Normal file
@@ -0,0 +1,245 @@
|
||||
{
|
||||
"v2": {
|
||||
"valid_sec": [
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"sec2": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"shared": "c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
|
||||
"salt": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"plaintext": "a",
|
||||
"ciphertext": "AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYNpT9ESckRbRUY7bUF5P+1rObpA4BNoksAUQ8myMDd9/37W/J2YHvBpRjvy9uC0+ovbpLc0WLaMFieqAMdIYqR14",
|
||||
"note": "sk1 = 1, sk2 = random, 0x02"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"sec2": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"shared": "c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
|
||||
"salt": "f00000000000000000000000000000f00000000000000000000000000000000f",
|
||||
"plaintext": "🍕🫃",
|
||||
"ciphertext": "AvAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAPKY68BwdF7PIT205jBoaZHSs7OMpKsULW5F5ClOJWiy6XjZy7s2v85KugYmbBKgEC2LytbXbxkr7Jpgfk529K3/pP",
|
||||
"note": "sk1 = 1, sk2 = random, 0x02"
|
||||
},
|
||||
{
|
||||
"sec1": "5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a",
|
||||
"sec2": "4b22aa260e4acb7021e32f38a6cdf4b673c6a277755bfce287e370c924dc936d",
|
||||
"shared": "94da47d851b9c1ed33b3b72f35434f56aa608d60e573e9c295f568011f4f50a4",
|
||||
"salt": "b635236c42db20f021bb8d1cdff5ca75dd1a0cc72ea742ad750f33010b24f73b",
|
||||
"plaintext": "表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀",
|
||||
"ciphertext": "ArY1I2xC2yDwIbuNHN/1ynXdGgzHLqdCrXUPMwELJPc7yuU7XwJ8wCYUrq4aXX86HLnkMx7fPFvNeMk0uek9ma01magfEBIf+vJvZdWKiv48eUu9Cv31plAJsH6kSIsGc5TVYBYipkrQUNRxxJA15QT+uCURF96v3XuSS0k2Pf108AI=",
|
||||
"note": "unicode-heavy string"
|
||||
},
|
||||
{
|
||||
"sec1": "8f40e50a84a7462e2b8d24c28898ef1f23359fff50d8c509e6fb7ce06e142f9c",
|
||||
"sec2": "b9b0a1e9cc20100c5faa3bbe2777303d25950616c4c6a3fa2e3e046f936ec2ba",
|
||||
"shared": "ab99c122d4586cdd5c813058aa543d0e7233545dbf6874fc34a3d8d9a18fbbc3",
|
||||
"salt": "b20989adc3ddc41cd2c435952c0d59a91315d8c5218d5040573fc3749543acaf",
|
||||
"plaintext": "ability🤝的 ȺȾ",
|
||||
"ciphertext": "ArIJia3D3cQc0sQ1lSwNWakTFdjFIY1QQFc/w3SVQ6yvPSc+7YCIFTmGk5OLuh1nhl6TvID7sGKLFUCWRW1eRfV/0a7sT46N3nTQzD7IE67zLWrYqGnE+0DDNz6sJ4hAaFrT"
|
||||
},
|
||||
{
|
||||
"sec1": "875adb475056aec0b4809bd2db9aa00cff53a649e7b59d8edcbf4e6330b0995c",
|
||||
"sec2": "9c05781112d5b0a2a7148a222e50e0bd891d6b60c5483f03456e982185944aae",
|
||||
"shared": "a449f2a85c6d3db0f44c64554a05d11a3c0988d645e4b4b2592072f63662f422",
|
||||
"salt": "8d4442713eb9d4791175cb040d98d6fc5be8864d6ec2f89cf0895a2b2b72d1b1",
|
||||
"plaintext": "pepper👀їжак",
|
||||
"ciphertext": "Ao1EQnE+udR5EXXLBA2Y1vxb6IZNbsL4nPCJWisrctGx1TkkMfiHJxEeSdQ/4Rlaghn0okDCNYLihBsHrDzBsNRC27APmH9mmZcpcg66Mb0exH9V5/lLBWdQW+fcY9GpvXv0"
|
||||
},
|
||||
{
|
||||
"sec1": "eba1687cab6a3101bfc68fd70f214aa4cc059e9ec1b79fdb9ad0a0a4e259829f",
|
||||
"sec2": "dff20d262bef9dfd94666548f556393085e6ea421c8af86e9d333fa8747e94b3",
|
||||
"shared": "decde9938ffcb14fa7ff300105eb1bf239469af9baf376e69755b9070ae48c47",
|
||||
"salt": "2180b52ae645fcf9f5080d81b1f0b5d6f2cd77ff3c986882bb549158462f3407",
|
||||
"plaintext": "( ͡° ͜ʖ ͡°)",
|
||||
"ciphertext": "AiGAtSrmRfz59QgNgbHwtdbyzXf/PJhogrtUkVhGLzQHiR8Hljs6Nl/XsNDAmCz6U1Z3NUGhbCtczc3wXXxDzFkjjMimxsf/74OEzu7LphUadM9iSWvVKPrNXY7lTD0B2muz"
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"shared": "c6f2fde7aa00208c388f506455c31c3fa07caf8b516d43bf7514ee19edcda994",
|
||||
"salt": "e4cd5f7ce4eea024bc71b17ad456a986a74ac426c2c62b0a15eb5c5c8f888b68",
|
||||
"plaintext": "مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ،",
|
||||
"ciphertext": "AuTNX3zk7qAkvHGxetRWqYanSsQmwsYrChXrXFyPiItohfde4vHVRHUupr+Glh9JW4f9EY+w795hvRZbixs0EQgDZ7zwLlymVQI3NNvMqvemQzHUA1I5+9gSu8XSMwX9gDCUAjUJtntCkRt9+tjdy2Wa2ZrDYqCvgirvzbJTIC69Ve3YbKuiTQCKtVi0PA5ZLqVmnkHPIqfPqDOGj/a3dvJVzGSgeijcIpjuEgFF54uirrWvIWmTBDeTA+tlQzJHpB2wQnUndd2gLDb8+eKFUZPBifshD3WmgWxv8wRv6k3DeWuWEZQ70Z+YDpgpeOzuzHj0MDBwMAlY8Qq86Rx6pxY76PLDDfHh3rE2CHJEKl2MhDj7pGXao2o633vSRd9ueG8W"
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"shared": "c6f2fde7aa00208c388f506455c31c3fa07caf8b516d43bf7514ee19edcda994",
|
||||
"salt": "38d1ca0abef9e5f564e89761a86cee04574b6825d3ef2063b10ad75899e4b023",
|
||||
"plaintext": "الكل في المجمو عة (5)",
|
||||
"ciphertext": "AjjRygq++eX1ZOiXYahs7gRXS2gl0+8gY7EK11iZ5LAjTHmhdBC3meTY4A7Lv8s8B86MnmlUBJ8ebzwxFQzDyVCcdSbWFaKe0gigEBdXew7TjrjH8BCpAbtYjoa4YHa8GNjj7zH314ApVnwoByHdLHLB9Vr6VdzkxcJgA6oL4MAsRLg="
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"shared": "c6f2fde7aa00208c388f506455c31c3fa07caf8b516d43bf7514ee19edcda994",
|
||||
"salt": "4f1a31909f3483a9e69c8549a55bbc9af25fa5bbecf7bd32d9896f83ef2e12e0",
|
||||
"plaintext": "𝖑𝖆𝖟𝖞 社會科學院語學研究所",
|
||||
"ciphertext": "Ak8aMZCfNIOp5pyFSaVbvJryX6W77Pe9MtmJb4PvLhLg/25Q5uBC88jl5ghtEREXX6o4QijPzM0uwmkeQ54/6aIqUyzGNVdryWKZ0mee2lmVVWhU+26X6XGFQ5DGRn+1v0POsFUCZ/REh35+beBNHnyvjxD/rbrMfhP2Blc8X5m8Xvk="
|
||||
},
|
||||
{
|
||||
"sec1": "d5633530f5bcfebceb5584cfbbf718a30df0751b729dd9a789b9f30c0587d74e",
|
||||
"sec2": "b74e6a341fb134127272b795a08b59250e5fa45a82a2eb4095e4ce9ed5f5e214",
|
||||
"shared": "c6f2fde7aa00208c388f506455c31c3fa07caf8b516d43bf7514ee19edcda994",
|
||||
"salt": "a3e219242d85465e70adcd640b564b3feff57d2ef8745d5e7a0663b2dccceb54",
|
||||
"plaintext": "🙈 🙉 🙊 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗",
|
||||
"ciphertext": "AqPiGSQthUZecK3NZAtWSz/v9X0u+HRdXnoGY7LczOtU9bUC2ji2A2udRI2VCEQZ7IAmYRRgxodBtd5Yi/5htCUczf1jLHxIt9AhVAZLKuRgbWOuEMq5RBybkxPsSeAkxzXVOlWHZ1Febq5ogkjqY/6Xj8CwwmaZxfbx+d1BKKO3Wa+IFuXwuVAZa1Xo+fan+skyf+2R5QSj10QGAnGO7odAu/iZ9A28eMoSNeXsdxqy1+PRt5Zk4i019xmf7C4PDGSzgFZSvQ2EzusJN5WcsnRFmF1L5rXpX1AYo8HusOpWcGf9PjmFbO+8spUkX1W/T21GRm4o7dro1Y6ycgGOA9BsiQ=="
|
||||
}
|
||||
],
|
||||
"valid_pub": [
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139",
|
||||
"pub2": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"shared": "7a1ccf5ce5a08e380f590de0c02776623b85a61ae67cfb6a017317e505b7cb51",
|
||||
"salt": "a000000000000000000000000000000000000000000000000000000000000001",
|
||||
"plaintext": "⁰⁴⁵₀₁₂",
|
||||
"ciphertext": "AqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2+xmGnjIMPMqqJGmjdYAYZUDUyEEUO3/evHUaO40LePeR91VlMVZ7I+nKJPkaUiKZ3cQiQnA86Uwti2IxepmzOFN",
|
||||
"note": "sec1 = n-2, pub2: random, 0x02"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdeb",
|
||||
"shared": "aa971537d741089885a0b48f2730a125e15b36033d089d4537a4e1204e76b39e",
|
||||
"salt": "b000000000000000000000000000000000000000000000000000000000000002",
|
||||
"plaintext": "A Peer-to-Peer Electronic Cash System",
|
||||
"ciphertext": "ArAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyuqG6RycuPyDPtwxzTcuMQu+is3N5XuWTlvCjligVaVBRydexaylXbsX592MEd3/Jt13BNL/GlpYpGDvLS4Tt/+2s9FX/16e/RDc+czdwXglc4DdSHiq+O06BvvXYfEQOPw=",
|
||||
"note": "sec1 = 2, pub2: "
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"pub2": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"shared": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"salt": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||
"plaintext": "A purely peer-to-peer version of electronic cash would allow online payments to be sent directly from one party to another without going through a financial institution. Digital signatures provide part of the solution, but the main benefits are lost if a trusted third party is still required to prevent double-spending.",
|
||||
"ciphertext": "Anm+Zn753LusVaBilc6HCwcCm/zbLc4o2VnygVsW+BeYb9wHyKevpe7ohJ6OkpceFcb0pySY8TLGwT7Q3zWNDKxc9blXanxKborEXkQH8xNaB2ViJfgxpkutbwbYd0Grix34xzaZBASufdsNm7R768t51tI6sdS0nms6kWLVJpEGu6Ke4Bldv4StJtWBLaTcgsgN+4WxDbBhC/nhwjEQiBBbbmUrPWjaVZXjl8dzzPrYtkSoeBNJs/UNvDwym4+qrmhv4ASTvVflpZgLlSe4seqeu6dWoRqn8uRHZQnPs+XhqwbdCHpeKGB3AfGBykZY0RIr0tjarWdXNasGbIhGM3GiLasioJeabAZw0plCevDkKpZYDaNfMJdzqFVJ8UXRIpvDpQad0SOm8lLum/aBzUpLqTjr3RvSlhYdbuODpd9pR5K60k4L2N8nrPtBv08wlilQg2ymwQgKVE6ipxIzzKMetn8+f0nQ9bHjWFJqxetSuMzzArTUQl9c4q/DwZmCBhI2",
|
||||
"note": "sec1 == pub2 == salt"
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"sec1": "2573d1e9b9ac5de5d570f652cbb9e8d4f235e3d3d334181448e87c417f374e83",
|
||||
"pub2": "8348c2d35549098706e5bab7966d9a9c72fbf6554e918f41c2b6cb275f79ec13",
|
||||
"sharedKey": "8673ec68393a997bfad7eab8661461daf8b3931b7e885d78312a3fb7fe17f41a",
|
||||
"salt": "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db",
|
||||
"plaintext": "n o b l e",
|
||||
"ciphertext": "##Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbOsrsqIEyf8ccwhlrnI/Cx03mDSmeweOLKD7dw5BDZQDxXe2FwUJ8Ag25VoJ4MGhjlPCNmCU/Uqk4k0jwbhgR3fRh",
|
||||
"note": "unknown encryption version"
|
||||
},
|
||||
{
|
||||
"sec1": "11063318c5cb3cd9cafcced42b4db5ea02ec976ed995962d2bc1fa1e9b52e29f",
|
||||
"pub2": "5c49873b6eac3dd363325250cc55d5dd4c7ce9a885134580405736d83506bb74",
|
||||
"sharedKey": "e2aad10de00913088e5cb0f73fa526a6a17e95763cc5b2a127022f5ea5a73445",
|
||||
"salt": "ad408d4be8616dc84bb0bf046454a2a102edac937c35209c43cd7964c5feb781",
|
||||
"plaintext": "⚠️",
|
||||
"ciphertext": "AK1AjUvoYW3IS7C/BGRUoqEC7ayTfDUgnEPNeWTF/reBA4fZmoHrtrz5I5pCHuwWZ22qqL/Xt1VidEZGMLds0yaJ5VwUbeEifEJlPICOFt1ssZJxCUf43HvRwCVTFskbhSMh",
|
||||
"note": "unknown encryption version 0"
|
||||
},
|
||||
{
|
||||
"sec1": "2573d1e9b9ac5de5d570f652cbb9e8d4f235e3d3d334181448e87c417f374e83",
|
||||
"pub2": "8348c2d35549098706e5bab7966d9a9c72fbf6554e918f41c2b6cb275f79ec13",
|
||||
"sharedKey": "8673ec68393a997bfad7eab8661461daf8b3931b7e885d78312a3fb7fe17f41a",
|
||||
"salt": "daaea5ca345b268e5b62060ca72c870c48f713bc1e00ff3fc0ddb78e826f10db",
|
||||
"plaintext": "n o s t r",
|
||||
"ciphertext": "Atqupco0WyaOW2IGDKcshwxI9xO8HgD/P8Ddt46CbxDbOsrsqIEybscEwg5rnI/Cx03mDSmeweOLKD,7dw5BDZQDxXSlCwX1LIcTJEZaJPTz98Ftu0zSE0d93ED7OtdlvNeZx",
|
||||
"note": "invalid base64"
|
||||
},
|
||||
{
|
||||
"sec1": "5a2f39347fed3883c9fe05868a8f6156a292c45f606bc610495fcc020ed158f7",
|
||||
"pub2": "775bbfeba58d07f9d1fbb862e306ac780f39e5418043dadb547c7b5900245e71",
|
||||
"sharedKey": "2e70c0a1cde884b88392458ca86148d859b273a5695ede5bbe41f731d7d88ffd",
|
||||
"salt": "09ff97750b084012e15ecb84614ce88180d7b8ec0d468508a86b6d70c0361a25",
|
||||
"plaintext": "¯\\_(ツ)_/¯",
|
||||
"ciphertext": "Agn/l3ULCEAS4V7LhGFM6IGA17jsDUaFCKhrbXDANholdUejFZPARM22IvOqp1U/UmFSkeSyTBYbbwy5ykmi+mKiEcWL+nVmTOf28MMiC+rTpZys/8p1hqQFpn+XWZRPrVay",
|
||||
"note": "invalid MAC"
|
||||
},
|
||||
{
|
||||
"sec1": "067eda13c4a36090ad28a7a183e9df611186ca01f63cb30fcdfa615ebfd6fb6d",
|
||||
"pub2": "32c1ece2c5dd2160ad03b243f50eff12db605b86ac92da47eacc78144bf0cdd3",
|
||||
"sharedKey": "a808915e31afc5b853d654d2519632dac7298ee2ecddc11695b8eba925935c2a",
|
||||
"salt": "65b14b0b949aaa7d52c417eb753b390e8ad6d84b23af4bec6d9bfa3e03a08af4",
|
||||
"plaintext": "🥎",
|
||||
"ciphertext": "AmWxSwuUmqp9UsQX63U7OQ6K1thLI69L7G2b+j4DoIr0U0P/M1/oKm95z8qz6Kg0zQawLzwk3DskvWA2drXP4zK+tzHpKvWq0KOdx5MdypboSQsP4NXfhh2KoUffjkyIOiMA",
|
||||
"note": "invalid MAC"
|
||||
},
|
||||
{
|
||||
"sec1": "3e7be560fb9f8c965c48953dbd00411d48577e200cf00d7cc427e49d0e8d9c01",
|
||||
"pub2": "e539e5fee58a337307e2a937ee9a7561b45876fb5df405c5e7be3ee564b239cc",
|
||||
"sharedKey": "6ee3efc4255e3b8270e5dd3f7dc7f6b60878cda6218c8df34a3261cd48744931",
|
||||
"salt": "7ab65dbb8bbc2b8e35cafb5745314e1f050325a864d11d0475ef75b3660d91c1",
|
||||
"plaintext": "elliptic-curve cryptography",
|
||||
"ciphertext": "Anq2XbuLvCuONcr7V0UxTh8FAyWoZNEdBHXvdbNmDZHBu7F9m36yBd58mVUBB5ktBTOJREDaQT1KAyPmZidP+IRea1lNw5YAEK7+pbnpfCw8CD0i2n8Pf2IDWlKDhLiVvatw",
|
||||
"note": "invalid padding"
|
||||
},
|
||||
{
|
||||
"sec1": "c22e1d4de967aa39dc143354d8f596cec1d7c912c3140831fff2976ce3e387c1",
|
||||
"pub2": "4e405be192677a2da95ffc733950777213bf880cf7c3b084eeb6f3fe5bd43705",
|
||||
"sharedKey": "1675a773dbf6fbcbef6a293004a4504b6c856978be738b10584b0269d437c8d1",
|
||||
"salt": "7d4283e3b54c885d6afee881f48e62f0a3f5d7a9e1cb71ccab594a7882c39330",
|
||||
"plaintext": "Peer-to-Peer",
|
||||
"ciphertext": "An1Cg+O1TIhdav7ogfSOYvCj9dep4ctxzKtZSniCw5MwhT0hvSnF9Xjp9Lml792qtNbmAVvR6laukTe9eYEjeWPpZFxtkVpYTbbL9wDKFeplDMKsUKVa+roSeSvv0ela9seDVl2Sfso=",
|
||||
"note": "invalid padding"
|
||||
},
|
||||
{
|
||||
"sec1": "be1edab14c5912e5c59084f197f0945242e969c363096cccb59af8898815096f",
|
||||
"pub2": "9eaf0775d971e4941c97189232542e1daefcdb7dddafc39bcea2520217710ba2",
|
||||
"sharedKey": "1741a44c052d5ae363c7845441f73d2b6c28d9bfb3006190012bba12eb4c774b",
|
||||
"salt": "6f9fd72667c273acd23ca6653711a708434474dd9eb15c3edb01ce9a95743e9b",
|
||||
"plaintext": "censorship-resistant and global social network",
|
||||
"ciphertext": "Am+f1yZnwnOs0jymZTcRpwhDRHTdnrFcPtsBzpqVdD6bL9HUMo3Mjkz4bjQo/FJF2LWHmaCr9Byc3hU9D7we+EkNBWenBHasT1G52fZk9r3NKeOC1hLezNwBLr7XXiULh+NbMBDtJh9/aQh1uZ9EpAfeISOzbZXwYwf0P5M85g9XER8hZ2fgJDLb4qMOuQRG6CrPezhr357nS3UHwPC2qHo3uKACxhE+2td+965yDcvMTx4KYTQg1zNhd7PA5v/WPnWeq2B623yLxlevUuo/OvXplFho3QVy7s5QZVop6qV2g2/l/SIsvD0HIcv3V35sywOCBR0K4VHgduFqkx/LEF3NGgAbjONXQHX8ZKushsEeR4TxlFoRSovAyYjhWolz+Ok3KJL2Ertds3H+M/Bdl2WnZGT0IbjZjn3DS+b1Ke0R0X4Onww2ZG3+7o6ncIwTc+lh1O7YQn00V0HJ+EIp03heKV2zWdVSC615By/+Yt9KAiV56n5+02GAuNqA",
|
||||
"note": "invalid padding"
|
||||
}
|
||||
],
|
||||
"invalid_conversation_key": [
|
||||
{
|
||||
"sec1": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 higher than curve.n"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 is 0"
|
||||
},
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139",
|
||||
"pub2": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"note": "pub2 is invalid, no sqrt, all-ff"
|
||||
},
|
||||
{
|
||||
"sec1": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "sec1 == curve.n"
|
||||
},
|
||||
{
|
||||
"sec1": "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"pub2": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
|
||||
"note": "pub2 is invalid, no sqrt"
|
||||
}
|
||||
],
|
||||
"padding": [
|
||||
[16, 32],
|
||||
[32, 32],
|
||||
[33, 64],
|
||||
[37, 64],
|
||||
[45, 64],
|
||||
[49, 64],
|
||||
[64, 64],
|
||||
[65, 96],
|
||||
[100, 128],
|
||||
[111, 128],
|
||||
[200, 224],
|
||||
[250, 256],
|
||||
[320, 320],
|
||||
[383, 384],
|
||||
[384, 384],
|
||||
[400, 448],
|
||||
[500, 512],
|
||||
[512, 512],
|
||||
[515, 640],
|
||||
[700, 768],
|
||||
[800, 896],
|
||||
[900, 1024],
|
||||
[1020, 1024],
|
||||
[74123, 81920]
|
||||
]
|
||||
}
|
||||
}
|
||||
71
nip47.test.ts
Normal file
71
nip47.test.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { makeNwcRequestEvent, parseConnectionString } from './nip47'
|
||||
import { Kind } from './event'
|
||||
import { decrypt } from './nip04.ts'
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-undef
|
||||
globalThis.crypto = crypto
|
||||
|
||||
describe('parseConnectionString', () => {
|
||||
test('returns pubkey, relay, and secret if connection string is valid', () => {
|
||||
const connectionString =
|
||||
'nostr+walletconnect:b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c'
|
||||
const { pubkey, relay, secret } = parseConnectionString(connectionString)
|
||||
|
||||
expect(pubkey).toBe('b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4')
|
||||
expect(relay).toBe('wss://relay.damus.io')
|
||||
expect(secret).toBe('71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c')
|
||||
})
|
||||
|
||||
test('throws an error if no pubkey in connection string', async () => {
|
||||
const connectionString =
|
||||
'nostr+walletconnect:relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c'
|
||||
|
||||
expect(() => parseConnectionString(connectionString)).toThrow('invalid connection string')
|
||||
})
|
||||
|
||||
test('throws an error if no relay in connection string', async () => {
|
||||
const connectionString =
|
||||
'nostr+walletconnect:b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c'
|
||||
|
||||
expect(() => parseConnectionString(connectionString)).toThrow('invalid connection string')
|
||||
})
|
||||
|
||||
test('throws an error if no secret in connection string', async () => {
|
||||
const connectionString =
|
||||
'nostr+walletconnect:b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io'
|
||||
|
||||
expect(() => parseConnectionString(connectionString)).toThrow('invalid connection string')
|
||||
})
|
||||
})
|
||||
|
||||
describe('makeNwcRequestEvent', () => {
|
||||
test('returns a valid NWC request event', async () => {
|
||||
const pubkey = 'b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4'
|
||||
const secret = '71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c'
|
||||
const invoice =
|
||||
'lnbc210n1pjdgyvupp5x43awdarnfd4mdlsklelux0nyckwfu5c708ykuet8vcjnjp3rnpqdqu2askcmr9wssx7e3q2dshgmmndp5scqzzsxqyz5vqsp52l7y9peq9pka3vd3j7aps7gjnalsmy46ndj2mlkz00dltjgqfumq9qyyssq5fasr5dxed8l4qjfnqq48a02jzss3asf8sly7sfaqtr9w3yu2q9spsxhghs3y9aqdf44zkrrg9jjjdg6amade4h0hulllkwk33eqpucp6d5jye'
|
||||
const timeBefore = Date.now() / 1000
|
||||
const result = await makeNwcRequestEvent({
|
||||
pubkey,
|
||||
secret,
|
||||
invoice,
|
||||
})
|
||||
const timeAfter = Date.now() / 1000
|
||||
expect(result.kind).toBe(Kind.NwcRequest)
|
||||
expect(result.created_at).toBeGreaterThan(timeBefore)
|
||||
expect(result.created_at).toBeLessThan(timeAfter)
|
||||
expect(await decrypt(secret, pubkey, result.content)).toEqual(
|
||||
JSON.stringify({
|
||||
method: 'pay_invoice',
|
||||
params: {
|
||||
invoice,
|
||||
},
|
||||
}),
|
||||
)
|
||||
expect(result.tags).toEqual([['p', pubkey]])
|
||||
expect(result.id).toEqual(expect.any(String))
|
||||
expect(result.sig).toEqual(expect.any(String))
|
||||
})
|
||||
})
|
||||
42
nip47.ts
Normal file
42
nip47.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { finishEvent } from './event.ts'
|
||||
import { encrypt } from './nip04.ts'
|
||||
import { Kind } from './event'
|
||||
|
||||
export function parseConnectionString(connectionString: string) {
|
||||
const { pathname, searchParams } = new URL(connectionString)
|
||||
const pubkey = pathname
|
||||
const relay = searchParams.get('relay')
|
||||
const secret = searchParams.get('secret')
|
||||
|
||||
if (!pubkey || !relay || !secret) {
|
||||
throw new Error('invalid connection string')
|
||||
}
|
||||
|
||||
return { pubkey, relay, secret }
|
||||
}
|
||||
|
||||
export async function makeNwcRequestEvent({
|
||||
pubkey,
|
||||
secret,
|
||||
invoice,
|
||||
}: {
|
||||
pubkey: string
|
||||
secret: string
|
||||
invoice: string
|
||||
}) {
|
||||
const content = {
|
||||
method: 'pay_invoice',
|
||||
params: {
|
||||
invoice,
|
||||
},
|
||||
}
|
||||
const encryptedContent = await encrypt(secret, pubkey, JSON.stringify(content))
|
||||
const eventTemplate = {
|
||||
kind: Kind.NwcRequest,
|
||||
created_at: Math.round(Date.now() / 1000),
|
||||
content: encryptedContent,
|
||||
tags: [['p', pubkey]],
|
||||
}
|
||||
|
||||
return finishEvent(eventTemplate, secret)
|
||||
}
|
||||
16
nip57.ts
16
nip57.ts
@@ -13,7 +13,7 @@ export function useFetchImplementation(fetchImplementation: any) {
|
||||
_fetch = fetchImplementation
|
||||
}
|
||||
|
||||
export async function getZapEndpoint(metadata: Event<Kind.Metadata>): Promise<null | string> {
|
||||
export async function getZapEndpoint(metadata: Event): Promise<null | string> {
|
||||
try {
|
||||
let lnurl: string = ''
|
||||
let { lud06, lud16 } = JSON.parse(metadata.content)
|
||||
@@ -53,12 +53,12 @@ export function makeZapRequest({
|
||||
amount: number
|
||||
comment: string
|
||||
relays: string[]
|
||||
}): EventTemplate<Kind.ZapRequest> {
|
||||
}): EventTemplate {
|
||||
if (!amount) throw new Error('amount not given')
|
||||
if (!profile) throw new Error('profile not given')
|
||||
|
||||
let zr: EventTemplate<Kind.ZapRequest> = {
|
||||
kind: 9734,
|
||||
let zr: EventTemplate = {
|
||||
kind: Kind.ZapRequest,
|
||||
created_at: Math.round(Date.now() / 1000),
|
||||
content: comment,
|
||||
tags: [
|
||||
@@ -111,12 +111,12 @@ export function makeZapReceipt({
|
||||
preimage?: string
|
||||
bolt11: string
|
||||
paidAt: Date
|
||||
}): EventTemplate<Kind.Zap> {
|
||||
let zr: Event<Kind.ZapRequest> = JSON.parse(zapRequest)
|
||||
}): EventTemplate {
|
||||
let zr: Event = JSON.parse(zapRequest)
|
||||
let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a')
|
||||
|
||||
let zap: EventTemplate<Kind.Zap> = {
|
||||
kind: 9735,
|
||||
let zap: EventTemplate = {
|
||||
kind: Kind.Zap,
|
||||
created_at: Math.round(paidAt.getTime() / 1000),
|
||||
content: '',
|
||||
tags: [...tagsFromZapRequest, ['bolt11', bolt11], ['description', zapRequest]],
|
||||
|
||||
148
package.json
148
package.json
@@ -1,25 +1,153 @@
|
||||
{
|
||||
"name": "nostr-tools",
|
||||
"version": "1.15.0",
|
||||
"version": "1.17.0",
|
||||
"description": "Tools for making a Nostr client.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nbd-wtf/nostr-tools.git"
|
||||
},
|
||||
"files": [
|
||||
"./lib/**/*"
|
||||
"lib"
|
||||
],
|
||||
"types": "./lib/index.d.ts",
|
||||
"main": "lib/nostr.cjs.js",
|
||||
"module": "lib/esm/nostr.mjs",
|
||||
"sideEffects": false,
|
||||
"module": "./lib/esm/index.js",
|
||||
"main": "./lib/cjs/index.js",
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./lib/esm/nostr.mjs",
|
||||
"require": "./lib/nostr.cjs.js",
|
||||
"types": "./lib/index.d.ts"
|
||||
".": {
|
||||
"import": "./lib/esm/index.js",
|
||||
"require": "./lib/cjs/index.js",
|
||||
"types": "./lib/types/index.d.ts"
|
||||
},
|
||||
"./keys": {
|
||||
"import": "./lib/esm/keys.js",
|
||||
"require": "./lib/cjs/keys.js",
|
||||
"types": "./lib/types/keys.d.ts"
|
||||
},
|
||||
"./relay": {
|
||||
"import": "./lib/esm/relay.js",
|
||||
"require": "./lib/cjs/relay.js",
|
||||
"types": "./lib/types/relay.d.ts"
|
||||
},
|
||||
"./event": {
|
||||
"import": "./lib/esm/event.js",
|
||||
"require": "./lib/cjs/event.js",
|
||||
"types": "./lib/types/event.d.ts"
|
||||
},
|
||||
"./filter": {
|
||||
"import": "./lib/esm/filter.js",
|
||||
"require": "./lib/cjs/filter.js",
|
||||
"types": "./lib/types/filter.d.ts"
|
||||
},
|
||||
"./pool": {
|
||||
"import": "./lib/esm/pool.js",
|
||||
"require": "./lib/cjs/pool.js",
|
||||
"types": "./lib/types/pool.d.ts"
|
||||
},
|
||||
"./references": {
|
||||
"import": "./lib/esm/references.js",
|
||||
"require": "./lib/cjs/references.js",
|
||||
"types": "./lib/types/references.d.ts"
|
||||
},
|
||||
"./nip04": {
|
||||
"import": "./lib/esm/nip04.js",
|
||||
"require": "./lib/cjs/nip04.js",
|
||||
"types": "./lib/types/nip04.d.ts"
|
||||
},
|
||||
"./nip05": {
|
||||
"import": "./lib/esm/nip05.js",
|
||||
"require": "./lib/cjs/nip05.js",
|
||||
"types": "./lib/types/nip05.d.ts"
|
||||
},
|
||||
"./nip06": {
|
||||
"import": "./lib/esm/nip06.js",
|
||||
"require": "./lib/cjs/nip06.js",
|
||||
"types": "./lib/types/nip06.d.ts"
|
||||
},
|
||||
"./nip10": {
|
||||
"import": "./lib/esm/nip10.js",
|
||||
"require": "./lib/cjs/nip10.js",
|
||||
"types": "./lib/types/nip10.d.ts"
|
||||
},
|
||||
"./nip13": {
|
||||
"import": "./lib/esm/nip13.js",
|
||||
"require": "./lib/cjs/nip13.js",
|
||||
"types": "./lib/types/nip13.d.ts"
|
||||
},
|
||||
"./nip18": {
|
||||
"import": "./lib/esm/nip18.js",
|
||||
"require": "./lib/cjs/nip18.js",
|
||||
"types": "./lib/types/nip18.d.ts"
|
||||
},
|
||||
"./nip19": {
|
||||
"import": "./lib/esm/nip19.js",
|
||||
"require": "./lib/cjs/nip19.js",
|
||||
"types": "./lib/types/nip19.d.ts"
|
||||
},
|
||||
"./nip21": {
|
||||
"import": "./lib/esm/nip21.js",
|
||||
"require": "./lib/cjs/nip21.js",
|
||||
"types": "./lib/types/nip21.d.ts"
|
||||
},
|
||||
"./nip25": {
|
||||
"import": "./lib/esm/nip25.js",
|
||||
"require": "./lib/cjs/nip25.js",
|
||||
"types": "./lib/types/nip25.d.ts"
|
||||
},
|
||||
"./nip26": {
|
||||
"import": "./lib/esm/nip26.js",
|
||||
"require": "./lib/cjs/nip26.js",
|
||||
"types": "./lib/types/nip26.d.ts"
|
||||
},
|
||||
"./nip27": {
|
||||
"import": "./lib/esm/nip27.js",
|
||||
"require": "./lib/cjs/nip27.js",
|
||||
"types": "./lib/types/nip27.d.ts"
|
||||
},
|
||||
"./nip28": {
|
||||
"import": "./lib/esm/nip28.js",
|
||||
"require": "./lib/cjs/nip28.js",
|
||||
"types": "./lib/types/nip28.d.ts"
|
||||
},
|
||||
"./nip39": {
|
||||
"import": "./lib/esm/nip39.js",
|
||||
"require": "./lib/cjs/nip39.js",
|
||||
"types": "./lib/types/nip39.d.ts"
|
||||
},
|
||||
"./nip42": {
|
||||
"import": "./lib/esm/nip42.js",
|
||||
"require": "./lib/cjs/nip42.js",
|
||||
"types": "./lib/types/nip42.d.ts"
|
||||
},
|
||||
"./nip44": {
|
||||
"import": "./lib/esm/nip44.js",
|
||||
"require": "./lib/cjs/nip44.js",
|
||||
"types": "./lib/types/nip44.d.ts"
|
||||
},
|
||||
"./nip57": {
|
||||
"import": "./lib/esm/nip57.js",
|
||||
"require": "./lib/cjs/nip57.js",
|
||||
"types": "./lib/types/nip57.d.ts"
|
||||
},
|
||||
"./nip98": {
|
||||
"import": "./lib/esm/nip98.js",
|
||||
"require": "./lib/cjs/nip98.js",
|
||||
"types": "./lib/types/nip98.d.ts"
|
||||
},
|
||||
"./fakejson": {
|
||||
"import": "./lib/esm/fakejson.js",
|
||||
"require": "./lib/cjs/fakejson.js",
|
||||
"types": "./lib/types/fakejson.d.ts"
|
||||
},
|
||||
"./utils": {
|
||||
"import": "./lib/esm/utils.js",
|
||||
"require": "./lib/cjs/utils.js",
|
||||
"types": "./lib/types/utils.d.ts"
|
||||
}
|
||||
},
|
||||
"license": "Unlicense",
|
||||
"dependencies": {
|
||||
"@noble/ciphers": "^0.2.0",
|
||||
"@noble/ciphers": "0.2.0",
|
||||
"@noble/curves": "1.1.0",
|
||||
"@noble/hashes": "1.3.1",
|
||||
"@scure/base": "1.1.1",
|
||||
@@ -42,7 +170,7 @@
|
||||
"nostr"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "node build",
|
||||
"build": "node build && tsc",
|
||||
"format": "prettier --plugin-search-dir . --write .",
|
||||
"test": "jest"
|
||||
},
|
||||
|
||||
6
pool.ts
6
pool.ts
@@ -1,8 +1,8 @@
|
||||
import { relayInit, eventsGenerator, type Relay, type Sub, type SubscriptionOptions } from './relay.ts'
|
||||
import { eventsGenerator, relayInit, type Relay, type Sub, type SubscriptionOptions } from './relay.ts'
|
||||
import { normalizeURL } from './utils.ts'
|
||||
|
||||
import type { Event } from './event.ts'
|
||||
import { matchFilters, type Filter } from './filter.ts'
|
||||
import { matchFilters, mergeFilters, type Filter } from './filter.ts'
|
||||
|
||||
type BatchedRequest = {
|
||||
filters: Filter<any>[]
|
||||
@@ -213,7 +213,7 @@ export class SimplePool {
|
||||
relays.push(...br.relays)
|
||||
})
|
||||
|
||||
const sub = this.sub(relays, filters)
|
||||
const sub = this.sub(relays, [mergeFilters(...filters)])
|
||||
sub.on('event', event => {
|
||||
batchedRequests.forEach(br => matchFilters(br.filters, event) && br.events.push(event))
|
||||
})
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "lib",
|
||||
"outDir": "lib/types",
|
||||
"resolveJsonModule": true,
|
||||
"rootDir": ".",
|
||||
"allowImportingTsExtensions": true
|
||||
}
|
||||
|
||||
318
yarn.lock
318
yarn.lock
@@ -4,7 +4,7 @@
|
||||
|
||||
"@aashutoshrathi/word-wrap@^1.2.3":
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
|
||||
resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz"
|
||||
integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
|
||||
|
||||
"@ampproject/remapping@^2.2.0":
|
||||
@@ -27,7 +27,7 @@
|
||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz"
|
||||
integrity sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==
|
||||
|
||||
"@babel/core@^7.11.6", "@babel/core@^7.12.3":
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8":
|
||||
version "7.21.8"
|
||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz"
|
||||
integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==
|
||||
@@ -304,131 +304,26 @@
|
||||
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@esbuild/android-arm64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.9.tgz#474da719599f99d820ec010c92846a4f685fa28a"
|
||||
integrity sha512-ndIAZJUeLx4O+4AJbFQCurQW4VRUXjDsUvt1L+nP8bVELOWdmdCEOtlIweCUE6P+hU0uxYbEK2AEP0n5IVQvhg==
|
||||
|
||||
"@esbuild/android-arm@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.9.tgz#b0747ec074bba3ca652bfa8de3f55acfbb2d259e"
|
||||
integrity sha512-kW5ccqWHVOOTGUkkJbtfoImtqu3kA1PFkivM+9QPFSHphPfPBlBalX9eDRqPK+wHCqKhU48/78T791qPgC9e9A==
|
||||
|
||||
"@esbuild/android-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.9.tgz#1cd75e8ed7d6d7eb5f9896f623df63882bd8e887"
|
||||
integrity sha512-UbMcJB4EHrAVOnknQklREPgclNU2CPet2h+sCBCXmF2mfoYWopBn/CfTfeyOkb/JglOcdEADqAljFndMKnFtOw==
|
||||
|
||||
"@esbuild/darwin-arm64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.9.tgz"
|
||||
integrity sha512-d7D7/nrt4CxPul98lx4PXhyNZwTYtbdaHhOSdXlZuu5zZIznjqtMqLac8Bv+IuT6SVHiHUwrkL6ywD7mOgLW+A==
|
||||
|
||||
"@esbuild/darwin-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.9.tgz#5a19c00781595e0dfeef1826b3512d04c37b98ff"
|
||||
integrity sha512-LZc+Wlz06AkJYtwWsBM3x2rSqTG8lntDuftsUNQ3fCx9ZttYtvlDcVtgb+NQ6t9s6K5No5zutN3pcjZEC2a4iQ==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.9.tgz#2b7c16f5d15c259ed279b293b97c28c4a4bb107f"
|
||||
integrity sha512-gIj0UQZlQo93CHYouHKkpzP7AuruSaMIm1etcWIxccFEVqCN1xDr6BWlN9bM+ol/f0W9w3hx3HDuEwcJVtGneQ==
|
||||
|
||||
"@esbuild/freebsd-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.9.tgz#2db48ffeeab149c2b970494a60b82bf3004b8630"
|
||||
integrity sha512-GNors4vaMJ7lzGOuhzNc7jvgsQZqErGA8rsW+nck8N1nYu86CvsJW2seigVrQQWOV4QzEP8Zf3gm+QCjA2hnBQ==
|
||||
|
||||
"@esbuild/linux-arm64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.9.tgz#4c63c9f8ddd690d140ac3e0f360226d3fcdd75d8"
|
||||
integrity sha512-YPxQunReYp8RQ1FvexFrOEqqf+nLbS3bKVZF5FRT2uKM7Wio7BeATqAwO02AyrdSEntt3I5fhFsujUChIa8CZg==
|
||||
|
||||
"@esbuild/linux-arm@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.9.tgz#7704de1c2a30bc68d8f615d3ecb1cf68f001256a"
|
||||
integrity sha512-cNx1EF99c2t1Ztn0lk9N+MuwBijGF8mH6nx9GFsB3e0lpUpPkCE/yt5d+7NP9EwJf5uzqdjutgVYoH1SNqzudA==
|
||||
|
||||
"@esbuild/linux-ia32@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.9.tgz#bf0fda9f046e6c8332d7c8350b8a94d63acb4ceb"
|
||||
integrity sha512-zb12ixDIKNwFpIqR00J88FFitVwOEwO78EiUi8wi8FXlmSc3GtUuKV/BSO+730Kglt0B47+ZrJN1BhhOxZaVrw==
|
||||
|
||||
"@esbuild/linux-loong64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.9.tgz#c16378b898fa38f5f788f76fbce16a45c49c8793"
|
||||
integrity sha512-X8te4NLxtHiNT6H+4Pfm5RklzItA1Qy4nfyttihGGX+Koc53Ar20ViC+myY70QJ8PDEOehinXZj/F7QK3A+MKQ==
|
||||
|
||||
"@esbuild/linux-mips64el@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.9.tgz#492605f13f19dc06c350d94e4048c21478b9dec4"
|
||||
integrity sha512-ZqyMDLt02c5smoS3enlF54ndK5zK4IpClLTxF0hHfzHJlfm4y8IAkIF8LUW0W7zxcKy7oAwI7BRDqeVvC120SA==
|
||||
|
||||
"@esbuild/linux-ppc64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.9.tgz#ccaf759fc4f7a5fe72bdac05b4f5bf18ef1fe01b"
|
||||
integrity sha512-k+ca5W5LDBEF3lfDwMV6YNXwm4wEpw9krMnNvvlNz3MrKSD2Eb2c861O0MaKrZkG/buTQAP4vkavbLwgIe6xjg==
|
||||
|
||||
"@esbuild/linux-riscv64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.9.tgz#542d0e68bc99fb658fe732b0917931c09775f1a3"
|
||||
integrity sha512-GuInVdogjmg9DhgkEmNipHkC+3tzkanPJzgzTC2ihsvrruLyFoR1YrTGixblNSMPudQLpiqkcwGwwe0oqfrvfA==
|
||||
|
||||
"@esbuild/linux-s390x@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.9.tgz#4398f9d9d64dba4cfa6eed267476eaa9c9b7f214"
|
||||
integrity sha512-49wQ0aYkvwXonGsxc7LuuLNICMX8XtO92Iqmug5Qau0kpnV6SP34jk+jIeu4suHwAbSbRhVFtDv75yRmyfQcHw==
|
||||
|
||||
"@esbuild/linux-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.9.tgz#67c6b418ef36addbca17af0d7a2274c37ddffba2"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.9.tgz"
|
||||
integrity sha512-Nx4oKEAJ6EcQlt4dK7qJyuZUoXZG7CAeY22R7rqZijFzwFfMOD+gLP56uV7RrV86jGf8PeRY8TBsRmOcZoG42w==
|
||||
|
||||
"@esbuild/netbsd-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.9.tgz#22ed58e404ebeb2475b821bc4e25f1027eb0c912"
|
||||
integrity sha512-d0WnpgJ+FTiMZXEQ1NOv9+0gvEhttbgKEvVqWWAtl1u9AvlspKXbodKHzQ5MLP6YV1y52Xp+p8FMYqj8ykTahg==
|
||||
|
||||
"@esbuild/openbsd-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.9.tgz#2b2597b4edd4d26946f7c56838680fbeb4d455eb"
|
||||
integrity sha512-jccK11278dvEscHFfMk5EIPjF4wv1qGD0vps7mBV1a6TspdR36O28fgPem/SA/0pcsCPHjww5ouCLwP+JNAFlw==
|
||||
|
||||
"@esbuild/sunos-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.9.tgz#c132603a19ef79c0d7bd95afb09f41618ea8dda2"
|
||||
integrity sha512-OetwTSsv6mIDLqN7I7I2oX9MmHGwG+AP+wKIHvq+6sIHwcPPJqRx+DJB55jy9JG13CWcdcQno/7V5MTJ5a0xfQ==
|
||||
|
||||
"@esbuild/win32-arm64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.9.tgz#bf74d007d7f0fe1fe32c4fff82d27b271b3e1d58"
|
||||
integrity sha512-tKSSSK6unhxbGbHg+Cc+JhRzemkcsX0tPBvG0m5qsWbkShDK9c+/LSb13L18LWVdOQZwuA55Vbakxmt6OjBDOQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.9.tgz#e46478e77431bca1a8b80f6260fc6b0020aa8127"
|
||||
integrity sha512-ZTQ5vhNS5gli0KK8I6/s6+LwXmNEfq1ftjnSVyyNm33dBw8zDpstqhGXYUbZSWWLvkqiRRjgxgmoncmi6Yy7Ng==
|
||||
|
||||
"@esbuild/win32-x64@0.16.9":
|
||||
version "0.16.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.9.tgz#4595a29c2930c5157aa1be0963abbbac989647c9"
|
||||
integrity sha512-C4ZX+YFIp6+lPrru3tpH6Gaapy8IBRHw/e7l63fzGDhn/EaiGpQgbIlT5paByyy+oMvRFQoxxyvC4LE0AjJMqQ==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
|
||||
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz"
|
||||
integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==
|
||||
|
||||
"@eslint/eslintrc@^2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396"
|
||||
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz"
|
||||
integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
@@ -443,12 +338,12 @@
|
||||
|
||||
"@eslint/js@8.48.0":
|
||||
version "8.48.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb"
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz"
|
||||
integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.10":
|
||||
version "0.11.11"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz"
|
||||
integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==
|
||||
dependencies:
|
||||
"@humanwhocodes/object-schema" "^1.2.1"
|
||||
@@ -661,7 +556,7 @@
|
||||
slash "^3.0.0"
|
||||
write-file-atomic "^4.0.2"
|
||||
|
||||
"@jest/types@^29.5.0":
|
||||
"@jest/types@^29.0.0", "@jest/types@^29.5.0":
|
||||
version "29.5.0"
|
||||
resolved "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz"
|
||||
integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==
|
||||
@@ -692,16 +587,16 @@
|
||||
resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@1.4.14":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.15"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"
|
||||
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
||||
|
||||
"@jridgewell/sourcemap-codec@1.4.14":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.18"
|
||||
resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz"
|
||||
@@ -715,14 +610,14 @@
|
||||
resolved "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.2.0.tgz"
|
||||
integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==
|
||||
|
||||
"@noble/curves@1.1.0", "@noble/curves@~1.1.0":
|
||||
"@noble/curves@~1.1.0", "@noble/curves@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz"
|
||||
integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==
|
||||
dependencies:
|
||||
"@noble/hashes" "1.3.1"
|
||||
|
||||
"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1":
|
||||
"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz"
|
||||
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
|
||||
@@ -735,7 +630,7 @@
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
@@ -748,7 +643,7 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@scure/base@1.1.1", "@scure/base@~1.1.0":
|
||||
"@scure/base@~1.1.0", "@scure/base@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz"
|
||||
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
|
||||
@@ -874,14 +769,9 @@
|
||||
expect "^29.0.0"
|
||||
pretty-format "^29.0.0"
|
||||
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.9":
|
||||
version "7.0.11"
|
||||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz"
|
||||
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
||||
|
||||
"@types/json-schema@^7.0.12":
|
||||
"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.9":
|
||||
version "7.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb"
|
||||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz"
|
||||
integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
|
||||
|
||||
"@types/minimist@^1.2.0":
|
||||
@@ -912,14 +802,9 @@
|
||||
resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz"
|
||||
integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==
|
||||
|
||||
"@types/semver@^7.3.12":
|
||||
version "7.3.13"
|
||||
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz"
|
||||
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
|
||||
|
||||
"@types/semver@^7.5.0":
|
||||
"@types/semver@^7.3.12", "@types/semver@^7.5.0":
|
||||
version "7.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367"
|
||||
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz"
|
||||
integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==
|
||||
|
||||
"@types/stack-utils@^2.0.0":
|
||||
@@ -939,9 +824,9 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^6.5.0":
|
||||
"@typescript-eslint/eslint-plugin@^5.0.0 || ^6.0.0", "@typescript-eslint/eslint-plugin@^6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz#5cee33edf0d45d5ec773e3b3111206b098ac8599"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz"
|
||||
integrity sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.5.1"
|
||||
@@ -956,9 +841,9 @@
|
||||
semver "^7.5.4"
|
||||
ts-api-utils "^1.0.1"
|
||||
|
||||
"@typescript-eslint/parser@^6.5.0":
|
||||
"@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha", "@typescript-eslint/parser@^6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.5.0.tgz#3d6ed231c5e307c5f5f4a0d86893ec01e92b8c77"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz"
|
||||
integrity sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager" "6.5.0"
|
||||
@@ -977,7 +862,7 @@
|
||||
|
||||
"@typescript-eslint/scope-manager@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz#f2cb20895aaad41b3ad27cc3a338ce8598f261c5"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz"
|
||||
integrity sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "6.5.0"
|
||||
@@ -985,7 +870,7 @@
|
||||
|
||||
"@typescript-eslint/type-utils@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz#6d246c93739282bc0d2e623f28d0dec6cfcc38d7"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz"
|
||||
integrity sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "6.5.0"
|
||||
@@ -1000,7 +885,7 @@
|
||||
|
||||
"@typescript-eslint/types@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.5.0.tgz#f4e55cfd99ac5346ea772770bf212a3e689a8f04"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz"
|
||||
integrity sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.59.2":
|
||||
@@ -1018,7 +903,7 @@
|
||||
|
||||
"@typescript-eslint/typescript-estree@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz#1cef6bc822585e9ef89d88834bc902d911d747ed"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz"
|
||||
integrity sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "6.5.0"
|
||||
@@ -1029,19 +914,6 @@
|
||||
semver "^7.5.4"
|
||||
ts-api-utils "^1.0.1"
|
||||
|
||||
"@typescript-eslint/utils@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.5.0.tgz#6668bee4f7f24978b11df8a2ea42d56eebc4662c"
|
||||
integrity sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@types/json-schema" "^7.0.12"
|
||||
"@types/semver" "^7.5.0"
|
||||
"@typescript-eslint/scope-manager" "6.5.0"
|
||||
"@typescript-eslint/types" "6.5.0"
|
||||
"@typescript-eslint/typescript-estree" "6.5.0"
|
||||
semver "^7.5.4"
|
||||
|
||||
"@typescript-eslint/utils@^5.10.0":
|
||||
version "5.59.2"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz"
|
||||
@@ -1056,6 +928,19 @@
|
||||
eslint-scope "^5.1.1"
|
||||
semver "^7.3.7"
|
||||
|
||||
"@typescript-eslint/utils@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz"
|
||||
integrity sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@types/json-schema" "^7.0.12"
|
||||
"@types/semver" "^7.5.0"
|
||||
"@typescript-eslint/scope-manager" "6.5.0"
|
||||
"@typescript-eslint/types" "6.5.0"
|
||||
"@typescript-eslint/typescript-estree" "6.5.0"
|
||||
semver "^7.5.4"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.59.2":
|
||||
version "5.59.2"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz"
|
||||
@@ -1066,7 +951,7 @@
|
||||
|
||||
"@typescript-eslint/visitor-keys@6.5.0":
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz#1a6f474a0170a447b76f0699ce6700110fd11436"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz"
|
||||
integrity sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "6.5.0"
|
||||
@@ -1077,9 +962,9 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
acorn@^8.9.0:
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
|
||||
version "8.10.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
|
||||
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
|
||||
|
||||
ajv@^6.12.4:
|
||||
@@ -1171,7 +1056,7 @@ available-typed-arrays@^1.0.5:
|
||||
resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz"
|
||||
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
|
||||
|
||||
babel-jest@^29.5.0:
|
||||
babel-jest@^29.0.0, babel-jest@^29.5.0:
|
||||
version "29.5.0"
|
||||
resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz"
|
||||
integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==
|
||||
@@ -1251,7 +1136,7 @@ braces@^3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
browserslist@^4.21.3:
|
||||
browserslist@^4.21.3, "browserslist@>= 4.21.0":
|
||||
version "4.21.5"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz"
|
||||
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
|
||||
@@ -1324,7 +1209,16 @@ caniuse-lite@^1.0.30001449:
|
||||
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001486.tgz"
|
||||
integrity sha512-uv7/gXuHi10Whlj0pp5q/tsK/32J2QSqVRKQhs2j8VsDCjgyruAh/eEXHF822VqO9yT6iZKw3nRwZRSPBE9OQg==
|
||||
|
||||
chalk@^2.0.0, chalk@^2.4.1:
|
||||
chalk@^2.0.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^2.4.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
@@ -1389,16 +1283,16 @@ color-convert@^2.0.1:
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
|
||||
@@ -1411,7 +1305,12 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
convert-source-map@^1.6.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz"
|
||||
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
|
||||
|
||||
convert-source-map@^1.7.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz"
|
||||
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
|
||||
@@ -1448,7 +1347,7 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
d@1, d@^1.0.1:
|
||||
d@^1.0.1, d@1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz"
|
||||
integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
|
||||
@@ -1696,7 +1595,7 @@ escape-string-regexp@^4.0.0:
|
||||
|
||||
eslint-config-prettier@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f"
|
||||
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz"
|
||||
integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==
|
||||
|
||||
eslint-formatter-pretty@^4.1.0:
|
||||
@@ -1722,7 +1621,7 @@ eslint-plugin-babel@^5.3.1:
|
||||
|
||||
eslint-plugin-jest@^27.2.3:
|
||||
version "27.2.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz"
|
||||
integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/utils" "^5.10.0"
|
||||
@@ -1747,25 +1646,20 @@ eslint-scope@^5.1.1:
|
||||
|
||||
eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
|
||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
|
||||
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz"
|
||||
integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==
|
||||
|
||||
eslint-visitor-keys@^3.4.3:
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint@^8.48.0:
|
||||
"eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.48.0, eslint@>=4.0.0, eslint@>=7.0.0:
|
||||
version "8.48.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz"
|
||||
integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
@@ -1818,7 +1712,7 @@ esm-loader-typescript@^1.0.3:
|
||||
|
||||
espree@^9.6.0, espree@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
|
||||
resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz"
|
||||
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
|
||||
dependencies:
|
||||
acorn "^8.9.0"
|
||||
@@ -1918,7 +1812,7 @@ fast-glob@^3.2.9:
|
||||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
|
||||
fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
@@ -1956,7 +1850,15 @@ fill-range@^7.0.1:
|
||||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
find-up@^4.0.0, find-up@^4.1.0:
|
||||
find-up@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
|
||||
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
|
||||
dependencies:
|
||||
locate-path "^5.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
find-up@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
|
||||
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
|
||||
@@ -2006,11 +1908,6 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||
@@ -2139,7 +2036,7 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.9:
|
||||
|
||||
graphemer@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
||||
resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
|
||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
||||
|
||||
hard-rejection@^2.1.0:
|
||||
@@ -2683,7 +2580,7 @@ jest-resolve-dependencies@^29.5.0:
|
||||
jest-regex-util "^29.4.3"
|
||||
jest-snapshot "^29.5.0"
|
||||
|
||||
jest-resolve@^29.5.0:
|
||||
jest-resolve@*, jest-resolve@^29.5.0:
|
||||
version "29.5.0"
|
||||
resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz"
|
||||
integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==
|
||||
@@ -2830,7 +2727,7 @@ jest-worker@^29.5.0:
|
||||
merge-stream "^2.0.0"
|
||||
supports-color "^8.0.0"
|
||||
|
||||
jest@^29.5.0:
|
||||
jest@*, jest@^29.0.0, jest@^29.5.0:
|
||||
version "29.5.0"
|
||||
resolved "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz"
|
||||
integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==
|
||||
@@ -3212,7 +3109,7 @@ onetime@^5.1.2:
|
||||
|
||||
optionator@^0.9.3:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
|
||||
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz"
|
||||
integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==
|
||||
dependencies:
|
||||
"@aashutoshrathi/word-wrap" "^1.2.3"
|
||||
@@ -3363,7 +3260,7 @@ prelude-ls@^1.2.1:
|
||||
|
||||
prettier@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
|
||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz"
|
||||
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
|
||||
|
||||
pretty-format@^29.0.0, pretty-format@^29.5.0:
|
||||
@@ -3517,30 +3414,33 @@ safe-regex-test@^1.0.0:
|
||||
get-intrinsic "^1.1.3"
|
||||
is-regex "^1.1.4"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.5.0:
|
||||
semver@^5.5.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
semver@7.x, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8:
|
||||
version "7.5.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz"
|
||||
integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^6.0.0, semver@^6.3.0:
|
||||
semver@^6.0.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.5.4:
|
||||
semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.4, semver@7.x:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
"semver@2 || 3 || 4 || 5":
|
||||
version "5.7.1"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz"
|
||||
@@ -3809,7 +3709,7 @@ trim-newlines@^3.0.0:
|
||||
|
||||
ts-api-utils@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99"
|
||||
resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz"
|
||||
integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==
|
||||
|
||||
ts-jest@^29.1.0:
|
||||
@@ -3918,7 +3818,7 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript@^5.0.2, typescript@^5.0.4:
|
||||
typescript@^5.0.2, typescript@^5.0.4, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.2.0, "typescript@>=4.3 <6":
|
||||
version "5.0.4"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz"
|
||||
integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==
|
||||
|
||||
Reference in New Issue
Block a user