Compare commits

...

8 Commits

Author SHA1 Message Date
fiatjaf
bf7e00d32a hotfix types. 2023-04-18 15:29:28 -03:00
fiatjaf
9241089997 v1.10.0 with @noble/secp256k1 back, nip42 support and nip19 typing improvements. 2023-04-18 15:17:57 -03:00
Lynn Zenn
32c47e9bd8 relay: separate auth() and publish() methods 2023-04-18 15:16:40 -03:00
Lynn Zenn
6e58fe371c relay: add support for NIP42 authentication 2023-04-18 15:16:40 -03:00
Lynn Zenn
26e35d50e0 relay: fix type errors 2023-04-18 15:16:40 -03:00
fiatjaf
ef3184a6e0 remove @noble/curves. people are not ready for it, causes BigInt issues. 2023-04-18 15:14:21 -03:00
Alex Gleason
56fe3dd5dd nip19: improve return type 2023-04-18 07:30:43 -03:00
Jonathan Staab
f1bb5030c8 Add support for count 2023-04-16 06:43:38 -03:00
14 changed files with 289 additions and 159 deletions

View File

@@ -1,6 +1,5 @@
import {schnorr} from '@noble/curves/secp256k1'
import * as secp256k1 from '@noble/secp256k1'
import {sha256} from '@noble/hashes/sha256'
import {bytesToHex} from '@noble/hashes/utils'
import {utf8Encoder} from './utils'
import {getPublicKey} from './keys'
@@ -79,7 +78,7 @@ export function serializeEvent(evt: UnsignedEvent): string {
export function getEventHash(event: UnsignedEvent): string {
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
return bytesToHex(eventHash)
return secp256k1.utils.bytesToHex(eventHash)
}
const isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object
@@ -105,7 +104,7 @@ export function validateEvent<T>(event: T): event is T & UnsignedEvent {
}
export function verifySignature(event: Event): boolean {
return schnorr.verify(
return secp256k1.schnorr.verifySync(
event.sig,
getEventHash(event),
event.pubkey
@@ -113,7 +112,7 @@ export function verifySignature(event: Event): boolean {
}
export function signEvent(event: UnsignedEvent, key: string): string {
return bytesToHex(
schnorr.sign(getEventHash(event), key)
return secp256k1.utils.bytesToHex(
secp256k1.schnorr.signSync(getEventHash(event), key)
)
}

View File

@@ -13,7 +13,17 @@ export * as nip13 from './nip13'
export * as nip19 from './nip19'
export * as nip26 from './nip26'
export * as nip39 from './nip39'
export * as nip42 from './nip42'
export * as nip57 from './nip57'
export * as fj from './fakejson'
export * as utils from './utils'
// monkey patch secp256k1
import * as secp256k1 from '@noble/secp256k1'
import {hmac} from '@noble/hashes/hmac'
import {sha256} from '@noble/hashes/sha256'
secp256k1.utils.hmacSha256Sync = (key, ...msgs) =>
hmac(sha256, key, secp256k1.utils.concatBytes(...msgs))
secp256k1.utils.sha256Sync = (...msgs) =>
sha256(secp256k1.utils.concatBytes(...msgs))

View File

@@ -1,10 +1,9 @@
import {schnorr} from '@noble/curves/secp256k1'
import {bytesToHex} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1'
export function generatePrivateKey(): string {
return bytesToHex(schnorr.utils.randomPrivateKey())
return secp256k1.utils.bytesToHex(secp256k1.utils.randomPrivateKey())
}
export function getPublicKey(privateKey: string): string {
return bytesToHex(schnorr.getPublicKey(privateKey))
return secp256k1.utils.bytesToHex(secp256k1.schnorr.getPublicKey(privateKey))
}

View File

@@ -1,5 +1,5 @@
import {randomBytes} from '@noble/hashes/utils'
import {secp256k1} from '@noble/curves/secp256k1'
import * as secp256k1 from '@noble/secp256k1'
import {base64} from '@scure/base'
import {utf8Decoder, utf8Encoder} from './utils'

View File

@@ -1,4 +1,4 @@
import {bytesToHex} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1'
import {wordlist} from '@scure/bip39/wordlists/english.js'
import {
generateMnemonic,
@@ -14,7 +14,7 @@ export function privateKeyFromSeedWords(
let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))
let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey
if (!privateKey) throw new Error('could not derive private key')
return bytesToHex(privateKey)
return secp256k1.utils.bytesToHex(privateKey)
}
export function generateSeedWords(): string {

View File

@@ -1,8 +1,8 @@
import {hexToBytes} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1'
/** Get POW difficulty from a Nostr hex ID. */
export function getPow(id: string): number {
return getLeadingZeroBits(hexToBytes(id))
return getLeadingZeroBits(secp256k1.utils.hexToBytes(id))
}
/**

View File

@@ -1,4 +1,4 @@
import {bytesToHex, concatBytes, hexToBytes} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1'
import {bech32} from '@scure/base'
import {utf8Decoder, utf8Encoder} from './utils'
@@ -23,10 +23,16 @@ export type AddressPointer = {
relays?: string[]
}
export function decode(nip19: string): {
type: string
data: ProfilePointer | EventPointer | AddressPointer | string
} {
export type DecodeResult =
| {type: 'nprofile'; data: ProfilePointer}
| {type: 'nrelay'; data: string}
| {type: 'nevent'; data: EventPointer}
| {type: 'naddr'; data: AddressPointer}
| {type: 'nsec'; data: string}
| {type: 'npub'; data: string}
| {type: 'note'; data: string}
export function decode(nip19: string): DecodeResult {
let {prefix, words} = bech32.decode(nip19, Bech32MaxSize)
let data = new Uint8Array(bech32.fromWords(words))
@@ -39,7 +45,7 @@ export function decode(nip19: string): {
return {
type: 'nprofile',
data: {
pubkey: bytesToHex(tlv[0][0]),
pubkey: secp256k1.utils.bytesToHex(tlv[0][0]),
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : []
}
}
@@ -54,10 +60,10 @@ export function decode(nip19: string): {
return {
type: 'nevent',
data: {
id: bytesToHex(tlv[0][0]),
id: secp256k1.utils.bytesToHex(tlv[0][0]),
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],
author: tlv[2]?.[0]
? bytesToHex(tlv[2][0])
? secp256k1.utils.bytesToHex(tlv[2][0])
: undefined
}
}
@@ -75,8 +81,8 @@ export function decode(nip19: string): {
type: 'naddr',
data: {
identifier: utf8Decoder.decode(tlv[0][0]),
pubkey: bytesToHex(tlv[2][0]),
kind: parseInt(bytesToHex(tlv[3][0]), 16),
pubkey: secp256k1.utils.bytesToHex(tlv[2][0]),
kind: parseInt(secp256k1.utils.bytesToHex(tlv[3][0]), 16),
relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : []
}
}
@@ -95,7 +101,7 @@ export function decode(nip19: string): {
case 'nsec':
case 'npub':
case 'note':
return {type: prefix, data: bytesToHex(data)}
return {type: prefix, data: secp256k1.utils.bytesToHex(data)}
default:
throw new Error(`unknown prefix ${prefix}`)
@@ -132,14 +138,14 @@ export function noteEncode(hex: string): string {
}
function encodeBytes(prefix: string, hex: string): string {
let data = hexToBytes(hex)
let data = secp256k1.utils.hexToBytes(hex)
let words = bech32.toWords(data)
return bech32.encode(prefix, words, Bech32MaxSize)
}
export function nprofileEncode(profile: ProfilePointer): string {
let data = encodeTLV({
0: [hexToBytes(profile.pubkey)],
0: [secp256k1.utils.hexToBytes(profile.pubkey)],
1: (profile.relays || []).map(url => utf8Encoder.encode(url))
})
let words = bech32.toWords(data)
@@ -148,9 +154,9 @@ export function nprofileEncode(profile: ProfilePointer): string {
export function neventEncode(event: EventPointer): string {
let data = encodeTLV({
0: [hexToBytes(event.id)],
0: [secp256k1.utils.hexToBytes(event.id)],
1: (event.relays || []).map(url => utf8Encoder.encode(url)),
2: event.author ? [hexToBytes(event.author)] : []
2: event.author ? [secp256k1.utils.hexToBytes(event.author)] : []
})
let words = bech32.toWords(data)
return bech32.encode('nevent', words, Bech32MaxSize)
@@ -163,7 +169,7 @@ export function naddrEncode(addr: AddressPointer): string {
let data = encodeTLV({
0: [utf8Encoder.encode(addr.identifier)],
1: (addr.relays || []).map(url => utf8Encoder.encode(url)),
2: [hexToBytes(addr.pubkey)],
2: [secp256k1.utils.hexToBytes(addr.pubkey)],
3: [new Uint8Array(kind)]
})
let words = bech32.toWords(data)
@@ -191,5 +197,5 @@ function encodeTLV(tlv: TLV): Uint8Array {
})
})
return concatBytes(...entries)
return secp256k1.utils.concatBytes(...entries)
}

View File

@@ -1,5 +1,4 @@
import {schnorr} from '@noble/curves/secp256k1'
import {bytesToHex} from '@noble/hashes/utils'
import * as secp256k1 from '@noble/secp256k1'
import {sha256} from '@noble/hashes/sha256'
import {Event} from './event'
@@ -37,8 +36,8 @@ export function createDelegation(
utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`)
)
let sig = bytesToHex(
schnorr.sign(sighash, privateKey)
let sig = secp256k1.utils.bytesToHex(
secp256k1.schnorr.signSync(sighash, privateKey)
)
return {
@@ -85,7 +84,7 @@ export function getDelegator(event: Event): string | null {
let sighash = sha256(
utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`)
)
if (!schnorr.verify(sig, sighash, pubkey)) return null
if (!secp256k1.schnorr.verifySync(sig, sighash, pubkey)) return null
return pubkey
}

27
nip42.test.js Normal file
View File

@@ -0,0 +1,27 @@
/* eslint-env jest */
require('websocket-polyfill')
const {
relayInit,
generatePrivateKey,
finishEvent,
nip42
} = require('./lib/nostr.cjs')
test('auth flow', done => {
const relay = relayInit('wss://nostr.kollider.xyz')
relay.connect()
const sk = generatePrivateKey()
relay.on('auth', async challenge => {
await expect(
nip42.authenticate({
challenge,
relay,
sign: e => finishEvent(e, sk)
})
).rejects.toBeTruthy()
relay.close()
done()
})
})

42
nip42.ts Normal file
View File

@@ -0,0 +1,42 @@
import {EventTemplate, Event, Kind} from './event'
import {Relay} from './relay'
/**
* Authenticate via NIP-42 flow.
*
* @example
* const sign = window.nostr.signEvent
* relay.on('auth', challenge =>
* authenticate({ relay, sign, challenge })
* )
*/
export const authenticate = async ({
challenge,
relay,
sign
}: {
challenge: string
relay: Relay
sign: (e: EventTemplate) => Promise<Event>
}): Promise<void> => {
const e: EventTemplate = {
kind: Kind.ClientAuth,
created_at: Math.floor(Date.now() / 1000),
tags: [
['relay', relay.url],
['challenge', challenge]
],
content: ''
}
const pub = relay.auth(await sign(e))
return new Promise((resolve, reject) => {
pub.on('ok', function ok() {
pub.off('ok', ok)
resolve()
})
pub.on('failed', function fail(reason: string) {
pub.off('failed', fail)
reject(reason)
})
})
}

View File

@@ -1,6 +1,6 @@
{
"name": "nostr-tools",
"version": "1.9.0",
"version": "1.10.0",
"description": "Tools for making a Nostr client.",
"repository": {
"type": "git",
@@ -18,11 +18,11 @@
},
"license": "Public domain",
"dependencies": {
"@noble/curves": "1.0.0",
"@noble/hashes": "1.3.0",
"@noble/hashes": "1.2.0",
"@noble/secp256k1": "1.7.1",
"@scure/base": "1.1.1",
"@scure/bip32": "1.3.0",
"@scure/bip39": "1.2.0"
"@scure/bip32": "1.1.4",
"@scure/bip39": "1.1.1"
},
"keywords": [
"decentralization",

View File

@@ -2,7 +2,7 @@ import {Relay, relayInit} from './relay'
import {normalizeURL} from './utils'
import {Filter} from './filter'
import {Event} from './event'
import {SubscriptionOptions, Sub, Pub} from './relay'
import {SubscriptionOptions, Sub, Pub, CountPayload} from './relay'
export class SimplePool {
private _conn: {[url: string]: Relay}
@@ -53,7 +53,7 @@ export class SimplePool {
}
let subs: Sub[] = []
let eventListeners: Set<(event: Event) => void> = new Set()
let eventListeners: Set<any> = new Set()
let eoseListeners: Set<() => void> = new Set()
let eosesMissing = relays.length

112
relay.ts
View File

@@ -9,9 +9,14 @@ type RelayEvent = {
disconnect: () => void | Promise<void>
error: () => void | Promise<void>
notice: (msg: string) => void | Promise<void>
auth: (challenge: string) => void | Promise<void>
}
export type CountPayload = {
count: number
}
type SubEvent = {
event: (event: Event) => void | Promise<void>
count: (payload: CountPayload) => void | Promise<void>
eose: () => void | Promise<void>
}
export type Relay = {
@@ -22,7 +27,12 @@ export type Relay = {
sub: (filters: Filter[], opts?: SubscriptionOptions) => Sub
list: (filters: Filter[], opts?: SubscriptionOptions) => Promise<Event[]>
get: (filter: Filter, opts?: SubscriptionOptions) => Promise<Event | null>
count: (
filters: Filter[],
opts?: SubscriptionOptions
) => Promise<CountPayload | null>
publish: (event: Event) => Pub
auth: (event: Event) => Pub
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(
event: T,
listener: U
@@ -51,27 +61,32 @@ export type Sub = {
export type SubscriptionOptions = {
id?: string
verb?: 'REQ' | 'COUNT'
skipVerification?: boolean
alreadyHaveEvent?: null | ((id: string, relay: string) => boolean)
}
const newListeners = (): {[TK in keyof RelayEvent]: RelayEvent[TK][]} => ({
connect: [],
disconnect: [],
error: [],
notice: [],
auth: []
})
export function relayInit(
url: string,
options: {
getTimeout?: number
listTimeout?: number
countTimeout?: number
} = {}
): Relay {
let {listTimeout = 3000, getTimeout = 3000} = options
let {listTimeout = 3000, getTimeout = 3000, countTimeout = 3000} = options
var ws: WebSocket
var openSubs: {[id: string]: {filters: Filter[]} & SubscriptionOptions} = {}
var listeners: {[TK in keyof RelayEvent]: RelayEvent[TK][]} = {
connect: [],
disconnect: [],
error: [],
notice: []
}
var listeners = newListeners()
var subListeners: {
[subid: string]: {[TK in keyof SubEvent]: SubEvent[TK][]}
} = {}
@@ -146,7 +161,7 @@ export function relayInit(
// will naturally be caught by the encompassing try..catch block
switch (data[0]) {
case 'EVENT':
case 'EVENT': {
let id = data[1]
let event = data[2]
if (
@@ -159,6 +174,14 @@ export function relayInit(
;(subListeners[id]?.event || []).forEach(cb => cb(event))
}
return
}
case 'COUNT':
let id = data[1]
let payload = data[2]
if (openSubs[id]) {
;(subListeners[id]?.count || []).forEach(cb => cb(payload))
}
return
case 'EOSE': {
let id = data[1]
if (id in subListeners) {
@@ -183,6 +206,11 @@ export function relayInit(
let notice = data[1]
listeners.notice.forEach(cb => cb(notice))
return
case 'AUTH': {
let challenge = data[1]
listeners.auth?.forEach(cb => cb(challenge))
return
}
}
} catch (err) {
return
@@ -220,6 +248,7 @@ export function relayInit(
const sub = (
filters: Filter[],
{
verb = 'REQ',
skipVerification = false,
alreadyHaveEvent = null,
id = Math.random().toString().slice(2)
@@ -233,7 +262,7 @@ export function relayInit(
skipVerification,
alreadyHaveEvent
}
trySend(['REQ', subid, ...filters])
trySend([verb, subid, ...filters])
return {
sub: (newFilters, newOpts = {}) =>
@@ -253,6 +282,7 @@ export function relayInit(
): void => {
subListeners[subid] = subListeners[subid] || {
event: [],
count: [],
eose: []
}
subListeners[subid][type].push(cb)
@@ -268,6 +298,29 @@ export function relayInit(
}
}
function _publishEvent(event: Event, type: string) {
if (!event.id) throw new Error(`event ${event} has no id`)
let id = event.id
trySend([type, event])
return {
on: (type: 'ok' | 'failed', cb: any) => {
pubListeners[id] = pubListeners[id] || {
ok: [],
failed: []
}
pubListeners[id][type].push(cb)
},
off: (type: 'ok' | 'failed', cb: any) => {
let listeners = pubListeners[id]
if (!listeners) return
let idx = listeners[type].indexOf(cb)
if (idx >= 0) listeners[type].splice(idx, 1)
}
}
}
return {
url,
sub,
@@ -318,31 +371,28 @@ export function relayInit(
resolve(event)
})
}),
publish(event: Event): Pub {
if (!event.id) throw new Error(`event ${event} has no id`)
let id = event.id
trySend(['EVENT', event])
return {
on: (type: 'ok' | 'failed', cb: any) => {
pubListeners[id] = pubListeners[id] || {
ok: [],
failed: []
}
pubListeners[id][type].push(cb)
},
off: (type: 'ok' | 'failed', cb: any) => {
let listeners = pubListeners[id]
if (!listeners) return
let idx = listeners[type].indexOf(cb)
if (idx >= 0) listeners[type].splice(idx, 1)
}
}
count: (filters: Filter[]): Promise<CountPayload | null> =>
new Promise(resolve => {
let s = sub(filters, {...sub, verb: 'COUNT'})
let timeout = setTimeout(() => {
s.unsub()
resolve(null)
}, countTimeout)
s.on('count', (event: CountPayload) => {
s.unsub()
clearTimeout(timeout)
resolve(event)
})
}),
publish(event): Pub {
return _publishEvent(event, 'EVENT')
},
auth(event): Pub {
return _publishEvent(event, 'AUTH')
},
connect,
close(): void {
listeners = {connect: [], disconnect: [], error: [], notice: []}
listeners = newListeners()
subListeners = {}
pubListeners = {}
if (ws.readyState === WebSocket.OPEN) {

166
yarn.lock
View File

@@ -705,17 +705,15 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@noble/curves@1.0.0", "@noble/curves@~1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932"
integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==
dependencies:
"@noble/hashes" "1.3.0"
"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==
"@noble/hashes@1.3.0", "@noble/hashes@~1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1"
integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==
"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -743,21 +741,21 @@
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
"@scure/bip32@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87"
integrity sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==
"@scure/bip32@1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.4.tgz#2c91a7be0156b15f26dd0c843a06a1917f129efd"
integrity sha512-m925ACYK0wPELsF7Z/VdLGmKj1StIeHraPMYB9xiAFiq/PnvqWd/99I0TQ2OZhjjlMDsDJeZlyXMWi0beaA7NA==
dependencies:
"@noble/curves" "~1.0.0"
"@noble/hashes" "~1.3.0"
"@noble/hashes" "~1.2.0"
"@noble/secp256k1" "~1.7.0"
"@scure/base" "~1.1.0"
"@scure/bip39@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.0.tgz#a207e2ef96de354de7d0002292ba1503538fc77b"
integrity sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==
"@scure/bip39@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5"
integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==
dependencies:
"@noble/hashes" "~1.3.0"
"@noble/hashes" "~1.2.0"
"@scure/base" "~1.1.0"
"@sinclair/typebox@^0.25.16":
@@ -904,14 +902,14 @@
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^5.51.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz#b1d4b0ad20243269d020ef9bbb036a40b0849829"
integrity sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.0.tgz#c0e10eeb936debe5d1c3433cf36206a95befefd0"
integrity sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==
dependencies:
"@eslint-community/regexpp" "^4.4.0"
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/type-utils" "5.58.0"
"@typescript-eslint/utils" "5.58.0"
"@typescript-eslint/scope-manager" "5.59.0"
"@typescript-eslint/type-utils" "5.59.0"
"@typescript-eslint/utils" "5.59.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
@@ -920,71 +918,71 @@
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.51.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.58.0.tgz#2ac4464cf48bef2e3234cb178ede5af352dddbc6"
integrity sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.0.tgz#0ad7cd019346cc5d150363f64869eca10ca9977c"
integrity sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==
dependencies:
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/typescript-estree" "5.58.0"
"@typescript-eslint/scope-manager" "5.59.0"
"@typescript-eslint/types" "5.59.0"
"@typescript-eslint/typescript-estree" "5.59.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz#5e023a48352afc6a87be6ce3c8e763bc9e2f0bc8"
integrity sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==
"@typescript-eslint/scope-manager@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.0.tgz#86501d7a17885710b6716a23be2e93fc54a4fe8c"
integrity sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==
dependencies:
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/visitor-keys" "5.58.0"
"@typescript-eslint/types" "5.59.0"
"@typescript-eslint/visitor-keys" "5.59.0"
"@typescript-eslint/type-utils@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz#f7d5b3971483d4015a470d8a9e5b8a7d10066e52"
integrity sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==
"@typescript-eslint/type-utils@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.0.tgz#8e8d1420fc2265989fa3a0d897bde37f3851e8c9"
integrity sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==
dependencies:
"@typescript-eslint/typescript-estree" "5.58.0"
"@typescript-eslint/utils" "5.58.0"
"@typescript-eslint/typescript-estree" "5.59.0"
"@typescript-eslint/utils" "5.59.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.58.0.tgz#54c490b8522c18986004df7674c644ffe2ed77d8"
integrity sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==
"@typescript-eslint/types@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32"
integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==
"@typescript-eslint/typescript-estree@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz#4966e6ff57eaf6e0fce2586497edc097e2ab3e61"
integrity sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==
"@typescript-eslint/typescript-estree@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.0.tgz#8869156ee1dcfc5a95be3ed0e2809969ea28e965"
integrity sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==
dependencies:
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/visitor-keys" "5.58.0"
"@typescript-eslint/types" "5.59.0"
"@typescript-eslint/visitor-keys" "5.59.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.58.0.tgz#430d7c95f23ec457b05be5520c1700a0dfd559d5"
integrity sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==
"@typescript-eslint/utils@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.0.tgz#063d066b3bc4850c18872649ed0da9ee72d833d5"
integrity sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.58.0"
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/typescript-estree" "5.58.0"
"@typescript-eslint/scope-manager" "5.59.0"
"@typescript-eslint/types" "5.59.0"
"@typescript-eslint/typescript-estree" "5.59.0"
eslint-scope "^5.1.1"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.58.0":
version "5.58.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz#eb9de3a61d2331829e6761ce7fd13061781168b4"
integrity sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==
"@typescript-eslint/visitor-keys@5.59.0":
version "5.59.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.0.tgz#a59913f2bf0baeb61b5cfcb6135d3926c3854365"
integrity sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==
dependencies:
"@typescript-eslint/types" "5.58.0"
"@typescript-eslint/types" "5.59.0"
eslint-visitor-keys "^3.3.0"
acorn-jsx@^5.3.2:
@@ -1230,9 +1228,9 @@ camelcase@^6.2.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001449:
version "1.0.30001478"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz#0ef8a1cf8b16be47a0f9fc4ecfc952232724b32a"
integrity sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==
version "1.0.30001480"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz#9bbd35ee44c2480a1e3a3b9f4496f5066817164a"
integrity sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==
chalk@^2.0.0, chalk@^2.4.1:
version "2.4.2"
@@ -1434,9 +1432,9 @@ doctrine@^3.0.0:
esutils "^2.0.2"
electron-to-chromium@^1.4.284:
version "1.4.364"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.364.tgz#da9702efd0101627f250f5e90a90a829feb41d7f"
integrity sha512-v6GxKdF57qfweXSfnne9nw1vS/86G4+UtscEe+3HQF+zhhrjAY4+9A4gstIQO56gyZvVrt9MZwt9aevCz/tohQ==
version "1.4.367"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.367.tgz#d9ddc529ba2315fc852b722c359e4a40e86aa742"
integrity sha512-mNuDxb+HpLhPGUKrg0hSxbTjHWw8EziwkwlJNkFUj3W60ypigLDRVz04vU+VRsJPi8Gub+FDhYUpuTm9xiEwRQ==
emittery@^0.13.1:
version "0.13.1"
@@ -2182,7 +2180,7 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
is-core-module@^2.12.0, is-core-module@^2.5.0:
is-core-module@^2.11.0, is-core-module@^2.5.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4"
integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==
@@ -3354,11 +3352,11 @@ resolve.exports@^2.0.0:
integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==
resolve@^1.10.0, resolve@^1.20.0:
version "1.22.3"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283"
integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==
version "1.22.2"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
is-core-module "^2.12.0"
is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
@@ -3396,9 +3394,9 @@ safe-regex-test@^1.0.0:
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.4.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.4.0.tgz#8481c92feffc531ab1e012a8ffc15bdd3a0f4318"
integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==
version "7.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0"
integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==
dependencies:
lru-cache "^6.0.0"
@@ -3800,9 +3798,9 @@ unbox-primitive@^1.0.2:
which-boxed-primitive "^1.0.2"
update-browserslist-db@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
version "1.0.11"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"
integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"