nostr package part 3

This commit is contained in:
ennmichael 2023-02-25 12:07:01 +01:00
parent 623d9735e5
commit 408be48082
No known key found for this signature in database
GPG Key ID: 6E6E183431A26AF7
13 changed files with 899 additions and 276 deletions

View File

@ -0,0 +1,12 @@
module.exports = {
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
root: true,
ignorePatterns: ["dist/"],
env: {
browser: true,
node: true,
mocha: true,
},
}

2
packages/nostr/NOTES.md Normal file
View File

@ -0,0 +1,2 @@
- Don't use arrays for callbacks because there's no way to clear them,
passing undefined or null to on* should clear the callback

View File

@ -0,0 +1,6 @@
version: "3.1"
services:
relay:
image: scsibug/nostr-rs-relay
ports:
- 12648:8080

View File

@ -5,15 +5,26 @@
"types": "dist/src/index.d.ts",
"scripts": {
"build": "tsc",
"watch": "tsc -w"
"watch": "tsc -w",
"test": "ts-mocha --type-check -j 1 test/*.ts",
"lint": "eslint ."
},
"devDependencies": {
"@types/expect": "^24.3.0",
"@types/mocha": "^10.0.1",
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"eslint": "^8.34.0",
"mocha": "^10.2.0",
"ts-mocha": "^10.0.0",
"typescript": "^4.9.5"
},
"prettier": {
"semi": false
},
"dependencies": {
"@noble/secp256k1": "^1.7.1",
"bech32": "^2.0.0",
"isomorphic-ws": "^5.0.0",
"ws": "^8.12.1"
}

View File

@ -1,7 +1,7 @@
import { ProtocolError } from "../error"
import { Filters, SubscriptionId } from "."
import { formatOutgoingMessage, parseIncomingMessage, RawEvent } from "../raw"
import { Event } from "../event"
import { RawEvent, SignedEvent } from "../event"
import WebSocket from "ws"
/**
* The connection to a relay. This is the lowest layer of the nostr protocol.
@ -23,8 +23,8 @@ export class Conn {
// different, and the NIP-44 stuff should be handled by Nostr.
#pending: OutgoingMessage[] = []
readonly #msgCallbacks: IncomingMessageCallback[] = []
readonly #errorCallbacks: ConnErrorCallback[] = []
#msgCallback?: IncomingMessageCallback
#errorCallback?: ErrorCallback
get url(): string {
return this.#socket.url
@ -34,27 +34,22 @@ export class Conn {
this.#socket = new WebSocket(endpoint)
// Handle incoming messages.
this.#socket.addEventListener("message", (msgData) => {
this.#socket.addEventListener("message", async (msgData) => {
const value = msgData.data.valueOf()
// Validate and parse the message.
if (typeof value !== "string") {
const err = new ProtocolError(`invalid message data: ${value}`)
for (const cb of this.#errorCallbacks) {
cb(err)
}
this.#errorCallback?.(err)
return
}
try {
const msg = parseIncomingMessage(value)
for (const cb of this.#msgCallbacks) {
cb(msg)
}
const msg = await parseIncomingMessage(value)
this.#msgCallback?.(msg)
} catch (err) {
if (err instanceof ProtocolError) {
for (const cb of this.#errorCallbacks) {
cb(err)
}
this.#errorCallback?.(err)
} else {
// TODO Not sure if this is the case?
throw err
}
}
@ -69,12 +64,16 @@ export class Conn {
})
}
onMessage(cb: IncomingMessageCallback): void {
this.#msgCallbacks.push(cb)
}
onError(cb: ConnErrorCallback): void {
this.#errorCallbacks.push(cb)
on(on: "message", cb: IncomingMessageCallback): void
on(on: "error", cb: ErrorCallback): void
on(on: "message" | "error", cb: IncomingMessageCallback | ErrorCallback) {
if (on === "message") {
this.#msgCallback = cb as IncomingMessageCallback
} else if (on === "error") {
this.#errorCallback = cb as ErrorCallback
} else {
throw new Error(`unexpected input: ${on}`)
}
}
send(msg: OutgoingMessage): void {
@ -82,7 +81,7 @@ export class Conn {
this.#pending.push(msg)
return
}
this.#socket.send(formatOutgoingMessage(msg))
this.#socket.send(serializeOutgoingMessage(msg))
}
close(): void {
@ -106,7 +105,7 @@ export const enum IncomingKind {
export interface IncomingEvent {
kind: IncomingKind.Event
subscriptionId: SubscriptionId
event: Event
signed: SignedEvent
raw: RawEvent
}
@ -137,7 +136,7 @@ export const enum OutgoingKind {
*/
export interface OutgoingEvent {
kind: OutgoingKind.Event
event: Event
signed: SignedEvent
}
/**
@ -146,7 +145,7 @@ export interface OutgoingEvent {
export interface OutgoingSubscription {
kind: OutgoingKind.Subscription
id: SubscriptionId
filters: Filters[]
filters: Filters
}
/**
@ -158,4 +157,123 @@ export interface OutgoingUnsubscription {
}
type IncomingMessageCallback = (message: IncomingMessage) => unknown
type ConnErrorCallback = (error: ProtocolError) => unknown
type ErrorCallback = (error: ProtocolError) => unknown
interface RawFilters {
ids?: string[]
authors?: string[]
kinds?: number[]
["#e"]?: string[]
["#p"]?: string[]
since?: number
until?: number
limit?: number
}
async function parseIncomingMessage(data: string): Promise<IncomingMessage> {
const json = parseJson(data)
if (!(json instanceof Array)) {
throw new ProtocolError(`incoming message is not an array: ${data}`)
}
if (json.length === 3) {
if (json[0] !== "EVENT") {
throw new ProtocolError(`expected "EVENT" message, but got: ${data}`)
}
if (typeof json[1] !== "string") {
throw new ProtocolError(
`second element of "EVENT" should be a string, but wasn't: ${data}`
)
}
if (typeof json[2] !== "object") {
throw new ProtocolError(
`second element of "EVENT" should be an object, but wasn't: ${data}`
)
}
const raw = parseEventData(json[2])
return {
kind: IncomingKind.Event,
subscriptionId: new SubscriptionId(json[1]),
signed: await SignedEvent.verify(raw),
raw,
}
} else if (json.length === 2) {
if (json[0] !== "NOTICE") {
throw new ProtocolError(`expected "NOTICE" message, but got: ${data}`)
}
if (typeof json[1] !== "string") {
throw new ProtocolError(
`second element of "NOTICE" should be a string, but wasn't: ${data}`
)
}
return {
kind: IncomingKind.Notice,
notice: json[1],
}
} else {
throw new ProtocolError(
`incoming message has unexpected number of elements: ${data}`
)
}
}
function serializeOutgoingMessage(msg: OutgoingMessage): string {
if (msg.kind === OutgoingKind.Event) {
return JSON.stringify(["EVENT", msg.signed.serialize()])
} else if (msg.kind === OutgoingKind.Subscription) {
return JSON.stringify([
"REQ",
msg.id.toString(),
serializeFilters(msg.filters),
])
} else if (msg.kind === OutgoingKind.Unsubscription) {
return JSON.stringify(["CLOSE", msg.id.toString()])
} else {
throw new Error(`invalid message: ${JSON.stringify(msg)}`)
}
}
function serializeFilters(filters: Filters): RawFilters {
return {
ids: filters.ids?.map((id) => id.toString()),
authors: filters.authors?.map((author) => author.toString()),
kinds: filters.kinds?.map((kind) => kind),
["#e"]: filters.eventTags?.map((e) => e.toString()),
["#p"]: filters.pubkeyTags?.map((p) => p.toString()),
// TODO The Math.floor has been repeated too many times at this point, have a unix timestamp function in event.ts
since:
filters.since !== undefined
? Math.floor(filters.since.getTime() / 1000)
: undefined,
until:
filters.until !== undefined
? Math.floor(filters.until.getTime() / 1000)
: undefined,
limit: filters.limit,
}
}
function parseEventData(json: object): RawEvent {
if (
typeof json["id"] !== "string" ||
typeof json["pubkey"] !== "string" ||
typeof json["created_at"] !== "number" ||
typeof json["kind"] !== "number" ||
!(json["tags"] instanceof Array) ||
!json["tags"].every(
(x) => x instanceof Array && x.every((y) => typeof y === "string")
) ||
typeof json["content"] !== "string" ||
typeof json["sig"] !== "string"
) {
throw new ProtocolError(`invalid event: ${JSON.stringify(json)}`)
}
return json as RawEvent
}
function parseJson(data: string) {
try {
return JSON.parse(data)
} catch (e) {
throw new ProtocolError(`invalid event json: ${data}`)
}
}

View File

@ -1,14 +1,8 @@
import { ProtocolError } from "../error"
import {
EventId,
Event,
serializeId as serializeEventId,
EventKind,
} from "../event"
import { PublicKey } from "../keypair"
import { EventId, Event, EventKind, SignedEvent, RawEvent } from "../event"
import { PrivateKey, PublicKey } from "../keypair"
import { Conn, IncomingKind, OutgoingKind } from "./conn"
import * as secp from "@noble/secp256k1"
import { RawEvent } from "../raw"
/**
* A nostr client.
@ -35,36 +29,44 @@ export class Nostr {
*/
write: boolean
}
>
> = new Map()
/**
* Mapping of subscription IDs to corresponding filters.
*/
readonly #subscriptions: Map<string, Filters[]> = new Map()
readonly #subscriptions: Map<string, Filters> = new Map()
readonly #eventCallbacks: EventCallback[] = []
readonly #noticeCallbacks: NoticeCallback[] = []
readonly #errorCallbacks: ErrorCallback[] = []
#eventCallback?: EventCallback
#noticeCallback?: NoticeCallback
#errorCallback?: ErrorCallback
/**
* Add a new callback for received events.
*/
onEvent(cb: EventCallback): void {
this.#eventCallbacks.push(cb)
}
on(on: "event", cb: EventCallback | undefined | null): void
/**
* Add a new callback for received notices.
*/
onNotice(cb: NoticeCallback): void {
this.#noticeCallbacks.push(cb)
}
on(on: "notice", cb: NoticeCallback | undefined | null): void
/**
* Add a new callback for errors.
*/
onError(cb: ErrorCallback): void {
this.#errorCallbacks.push(cb)
on(on: "error", cb: ErrorCallback | undefined | null): void
// TODO Also add on: ("subscribed", subscriptionId) which checks "OK"/"NOTICE" and makes a callback?
// TODO Also add on: ("sent", eventId) which checks "OK"/"NOTICE" and makes a callback?
on(
on: "event" | "notice" | "error",
cb: EventCallback | NoticeCallback | ErrorCallback | undefined | null
) {
if (on === "event") {
this.#eventCallback = (cb as EventCallback) ?? undefined
} else if (on === "notice") {
this.#noticeCallback = (cb as NoticeCallback) ?? undefined
} else if (on === "error") {
this.#errorCallback = (cb as ErrorCallback) ?? undefined
} else {
throw new Error(`unexpected input: ${on}`)
}
}
/**
@ -73,7 +75,7 @@ export class Nostr {
* this method will only update it with the new options, and an exception will be thrown
* if no options are specified.
*/
connect(url: URL | string, opts?: { read?: boolean; write?: boolean }): void {
open(url: URL | string, opts?: { read?: boolean; write?: boolean }): void {
// If the connection already exists, update the options.
const existingConn = this.#conns.get(url.toString())
if (existingConn !== undefined) {
@ -95,36 +97,27 @@ export class Nostr {
const conn = new Conn(url)
// Handle messages on this connection.
conn.onMessage(async (msg) => {
conn.on("message", async (msg) => {
if (msg.kind === IncomingKind.Event) {
for (const cb of this.#eventCallbacks) {
cb(
{
event: msg.event,
eventId: await serializeEventId(msg.raw),
subscriptionId: msg.subscriptionId,
raw: msg.raw,
},
this
)
}
this.#eventCallback?.(
{
signed: msg.signed,
subscriptionId: msg.subscriptionId,
raw: msg.raw,
},
this
)
} else if (msg.kind === IncomingKind.Notice) {
for (const cb of this.#noticeCallbacks) {
cb(msg.notice, this)
}
this.#noticeCallback?.(msg.notice, this)
} else {
const err = new ProtocolError(`invalid message ${msg}`)
for (const cb of this.#errorCallbacks) {
cb(err, this)
}
this.#errorCallback?.(err, this)
}
})
// Forward connection errors to the error callbacks.
conn.onError((err) => {
for (const cb of this.#errorCallbacks) {
cb(err, this)
}
conn.on("error", (err) => {
this.#errorCallback?.(err, this)
})
// Resend existing subscriptions to this connection.
@ -146,12 +139,23 @@ export class Nostr {
}
/**
* Disconnect from a relay. If there is no open connection to this relay, an exception is thrown.
* Disconnect from relays.
*
* @param url If specified, only close the connection to this relay. If the connection does
* not exist, an exception will be thrown. If this parameter is not specified, all connections
* will be closed.
*
* TODO There needs to be a way to check connection state. isOpen(), isReady(), isClosing() maybe?
* Because of how WebSocket states work this isn't as simple as it seems.
*/
disconnect(url: URL | string): void {
close(url?: URL | string): void {
if (url === undefined) {
for (const { conn } of this.#conns.values()) {
conn.close()
}
this.#conns.clear()
return
}
const c = this.#conns.get(url.toString())
if (c === undefined) {
throw new Error(`connection to ${url} doesn't exist`)
@ -175,10 +179,9 @@ export class Nostr {
* @returns The subscription ID.
*/
subscribe(
filters: Filters[],
subscriptionId?: SubscriptionId
filters: Filters = {},
subscriptionId: SubscriptionId = SubscriptionId.random()
): SubscriptionId {
subscriptionId ??= SubscriptionId.random()
this.#subscriptions.set(subscriptionId.toString(), filters)
for (const { conn, read } of this.#conns.values()) {
if (!read) {
@ -216,14 +219,18 @@ export class Nostr {
/**
* Publish an event.
*/
async publish(event: Event): Promise<void> {
async publish(event: Event, key: PrivateKey): Promise<void> {
if (event.pubkey.toString() !== key.pubkey.toString()) {
throw new Error("invalid private key")
}
for (const { conn, write } of this.#conns.values()) {
if (!write) {
continue
}
const signed = await SignedEvent.sign(event, key)
conn.send({
kind: OutgoingKind.Event,
event,
signed: signed,
})
}
}
@ -240,7 +247,7 @@ export class SubscriptionId {
}
static random(): SubscriptionId {
return new SubscriptionId(secp.utils.randomBytes(32).toString())
return new SubscriptionId(secp.utils.bytesToHex(secp.utils.randomBytes(32)))
}
toString() {
@ -290,8 +297,7 @@ export type NoticeCallback = (notice: string, nostr: Nostr) => unknown
export type ErrorCallback = (error: ProtocolError, nostr: Nostr) => unknown
export interface EventParams {
event: Event
eventId: EventId
signed: SignedEvent
subscriptionId: SubscriptionId
raw: RawEvent
}

View File

@ -1,8 +1,6 @@
import { ProtocolError } from "./error"
import { RawEvent } from "./raw"
import * as secp from "@noble/secp256k1"
import { PublicKey } from "./keypair"
import { parseHex } from "./util"
import { PublicKey, PrivateKey } from "./keypair"
// TODO This file is missing proper documentation
// TODO Add remaining event types
@ -52,22 +50,146 @@ export interface UnknownEvent extends EventCommon {
kind: Exclude<EventKind, EventKind.SetMetadata | EventKind.TextNote>
}
export async function createEvent(raw: RawEvent): Promise<Event> {
// TODO Doc comment
export class EventId {
#hex: string
static async create(event: Event | RawEvent): Promise<EventId> {
// It's not defined whether JSON.stringify produces a string with whitespace stripped.
// Building the JSON string manually as follows ensures that there's no whitespace.
// In hindsight using JSON as a data format for hashing and signing is not the best
// design decision.
if ("id" in event) {
// Raw event.
const serializedTags = `[${event.tags
.map((tag) => `[${tag.map((v) => `"${v}"`).join(",")}]`)
.join(",")}]`
const serialized = `[0,"${event.pubkey}",${event.created_at},${event.kind},${serializedTags},"${event.content}"]`
const hash = await secp.utils.sha256(
Uint8Array.from(charCodes(serialized))
)
return new EventId(secp.utils.bytesToHex(hash).toLowerCase())
} else {
// Not a raw event.
const tags = serializeEventTags(event)
const content = serializeEventContent(event)
const serializedTags = `[${tags
.map((tag) => `[${tag.map((v) => `"${v}"`).join(",")}]`)
.join(",")}]`
const serialized = `[0,"${event.pubkey}",${Math.floor(
event.createdAt.getTime() / 1000
)},${event.kind},${serializedTags},"${content}"]`
const hash = await secp.utils.sha256(
Uint8Array.from(charCodes(serialized))
)
return new EventId(secp.utils.bytesToHex(hash).toLowerCase())
}
}
private constructor(hex: string) {
this.#hex = hex
}
toString(): string {
return this.#hex
}
}
// TODO Document
export class SignedEvent {
#event: Readonly<Event>
#eventId: EventId
#signature: string
static async sign(event: Event, key: PrivateKey): Promise<SignedEvent> {
const id = await EventId.create(event)
const sig = secp.utils
.bytesToHex(await secp.schnorr.sign(id.toString(), key.leak()))
.toLowerCase()
return new SignedEvent(event, id, sig)
}
static async verify(raw: RawEvent): Promise<SignedEvent> {
const id = await EventId.create(raw)
if (id.toString() !== raw.id) {
throw new ProtocolError(`invalid event id: ${raw.id}, expected ${id}`)
}
if (!(await secp.schnorr.verify(raw.sig, id.toString(), raw.pubkey))) {
throw new ProtocolError(`invalid signature: ${raw.sig}`)
}
return new SignedEvent(parseEvent(raw), id, raw.sig)
}
private constructor(event: Event, eventId: EventId, signature: string) {
// TODO Copy the event data and document that it's being copied
this.#event = event
this.#eventId = eventId
this.#signature = signature
}
// TODO Document this
get eventId(): EventId {
return this.#eventId
}
// TODO Document this
get event(): Event {
// TODO Copy the event data and document that it's being copied
return this.#event
}
// TODO Document this
get signature(): string {
return this.#signature
}
/**
* Serialize the event into its raw format.
*/
serialize(): RawEvent {
const { event, eventId: id, signature } = this
const tags = serializeEventTags(event)
const content = serializeEventContent(event)
return {
id: id.toString(),
pubkey: event.pubkey.toString(),
created_at: Math.floor(event.createdAt.getTime() / 1000),
kind: event.kind,
tags,
content,
sig: signature,
}
}
}
export interface RawEvent {
id: string
pubkey: string
created_at: number
kind: number
tags: string[][]
content: string
sig: string
}
/**
* Parse an event from its raw format.
*/
function parseEvent(raw: RawEvent): Event {
const pubkey = new PublicKey(raw.pubkey)
const createdAt = new Date(raw.created_at * 1000)
const event = {
pubkey,
createdAt,
}
await checkSignature(raw, event)
return (
createSetMetadataEvent(raw, event) ??
createTextNodeEvent(raw, event) ??
createUnknownEvent(raw, event)
parseSetMetadataEvent(raw, event) ??
parseTextNodeEvent(raw, event) ??
parseUnknownEvent(raw, event)
)
}
function createSetMetadataEvent(
function parseSetMetadataEvent(
raw: RawEvent,
event: EventCommon
): SetMetadataEvent | undefined {
@ -89,7 +211,7 @@ function createSetMetadataEvent(
}
}
function createTextNodeEvent(
function parseTextNodeEvent(
raw: RawEvent,
event: EventCommon
): TextNoteEvent | undefined {
@ -103,53 +225,30 @@ function createTextNodeEvent(
}
}
function createUnknownEvent(raw: RawEvent, event: EventCommon): UnknownEvent {
function parseUnknownEvent(raw: RawEvent, event: EventCommon): UnknownEvent {
return {
...event,
kind: raw.kind,
}
}
export class EventId {
#hex: string
constructor(hex: string | Uint8Array) {
this.#hex = parseHex(hex)
if (this.#hex.length !== 128) {
throw new ProtocolError(`invalid event id: ${this.#hex}`)
}
}
toString(): string {
return this.#hex
}
function serializeEventTags(_event: Event): string[][] {
// TODO As I add different event kinds, this will change
return []
}
async function checkSignature(
raw: RawEvent,
event: EventCommon
): Promise<void> {
const id = serializeId(raw)
const bytes = await secp.schnorr.sign(id.toString(), event.pubkey.toString())
const hex = secp.utils.bytesToHex(bytes).toLowerCase()
if (hex.toString() !== raw.sig) {
throw new ProtocolError("invalid signature: ${hex}")
function serializeEventContent(event: Event): string {
if (event.kind === EventKind.SetMetadata) {
// TODO Maybe rename userMetadata to content?
return JSON.stringify(event.userMetadata)
} else if (event.kind === EventKind.TextNote) {
// TODO Maybe rename note to content?
return event.note
} else {
return ""
}
}
export async function serializeId(raw: RawEvent): Promise<EventId> {
// It's not defined whether JSON.stringify produces a string with whitespace stripped.
// Building the JSON string manually this way ensures that there's no whitespace.
// In hindsight using JSON as a data format for hashing and signing is not the best
// design decision.
const serializedTags = `[${raw.tags
.map((tag) => `[${tag.map((v) => `"${v}"`).join(",")}]`)
.join(",")}]`
const serialized = `[0,"${raw.pubkey}",${raw.created_at},${raw.kind},${serializedTags},"${raw.content}"]`
const hash = await secp.utils.sha256(Uint8Array.from(charCodes(serialized)))
return new EventId(secp.utils.bytesToHex(hash).toLowerCase())
}
function parseJson(data: string) {
try {
return JSON.parse(data)
@ -159,16 +258,7 @@ function parseJson(data: string) {
}
function* charCodes(data: string): Iterable<number> {
for (let i = 0; i < length; i++) {
for (let i = 0; i < data.length; i++) {
yield data.charCodeAt(i)
}
}
// TODO This is an example of how this API can be used, remove this later
function isItNice(e: Event): void {
if (e.kind === EventKind.SetMetadata) {
console.log(e.userMetadata)
} else if (e.kind === EventKind.TextNote) {
console.log(e.note)
}
}

View File

@ -1,5 +1,6 @@
import { bech32 } from "bech32"
import { ProtocolError } from "./error"
import { parseHex } from "./util"
import * as secp from "@noble/secp256k1"
/**
* A 32-byte secp256k1 public key.
@ -7,10 +8,13 @@ import { parseHex } from "./util"
export class PublicKey {
#hex: string
constructor(hex: string | Uint8Array) {
this.#hex = parseHex(hex)
/**
* Expects the key encoded as an npub1-prefixed bech32 string, hex string, or byte buffer.
*/
constructor(key: string | Uint8Array) {
this.#hex = parseKey(key, "npub1")
if (this.#hex.length !== 64) {
throw new ProtocolError(`invalid pubkey: ${hex}`)
throw new ProtocolError(`invalid pubkey: ${key}`)
}
}
@ -25,14 +29,49 @@ export class PublicKey {
export class PrivateKey {
#hex: string
constructor(hex: string | Uint8Array) {
this.#hex = parseHex(hex)
/**
* Expects the key encoded as an nsec1-prefixed bech32 string, hex string, or byte buffer.
*/
constructor(key: string | Uint8Array) {
this.#hex = parseKey(key, "nsec1")
if (this.#hex.length !== 64) {
throw new ProtocolError(`invalid private key: ${this.#hex}`)
}
}
toString(): string {
get pubkey(): PublicKey {
return new PublicKey(secp.schnorr.getPublicKey(this.#hex))
}
// TODO Document this
leak(): string {
return this.#hex
}
}
/**
* Parse a key into its hex representation.
*/
function parseKey(key: string | Uint8Array, bechPrefix: string): string {
if (typeof key === "string") {
// Is the key encoded in bech32?
if (key.startsWith(bechPrefix)) {
const { words } = bech32.decode(key)
const bytes = Uint8Array.from(bech32.fromWords(words))
return secp.utils.bytesToHex(bytes).toLowerCase()
}
// If not, it must be lowercase hex.
const valid = "0123456789abcdef"
if (key.length % 2 != 0) {
throw new ProtocolError(`invalid lowercase hex string: ${key}`)
}
for (const c of key) {
if (!valid.includes(c)) {
throw new ProtocolError(`invalid lowercase hex string: ${key}`)
}
}
return key
} else {
return secp.utils.bytesToHex(key).toLowerCase()
}
}

View File

@ -1,69 +0,0 @@
/**
* Types defining data in the format sent over the wire.
*/
import { ProtocolError } from "./error"
import { IncomingMessage, OutgoingMessage } from "./client/conn"
export interface RawEvent {
id: string
pubkey: string
created_at: number
kind: number
tags: string[][]
content: string
sig: string
}
interface RawFilters {
ids: string[]
authors: string[]
kinds: number[]
["#e"]: string[]
["#p"]: string[]
since: number
until: number
limit: number
}
type RawIncomingMessage = ["EVENT", string, RawEvent] | ["NOTICE", string]
type RawOutgoingMessage =
| ["EVENT", RawEvent]
| ["REQ", string, RawFilters]
| ["CLOSE", string]
export function parseIncomingMessage(msg: string): IncomingMessage {
throw new Error("todo")
}
export function formatOutgoingMessage(msg: OutgoingMessage): string {
throw new Error("todo")
}
function parseRawEvent(data: string): RawEvent {
const json = parseJson(data)
if (
typeof json["id"] !== "string" ||
typeof json["pubkey"] !== "string" ||
typeof json["created_at"] !== "number" ||
typeof json["kind"] !== "number" ||
!(json["tags"] instanceof Array) ||
!json["tags"].every(
(x) => x instanceof Array && x.every((y) => typeof y === "string")
) ||
typeof json["content"] !== "string" ||
typeof json["sig"] !== "string"
) {
throw new ProtocolError(`invalid event: ${data}`)
}
return json
}
function parseJson(data: string) {
try {
return JSON.parse(data)
} catch (e) {
throw new ProtocolError(`invalid event json: ${data}`)
}
}

View File

@ -1,22 +0,0 @@
import * as secp from "@noble/secp256k1"
import { ProtocolError } from "./error"
/**
* Check that the input is a valid lowercase hex string.
*/
export function parseHex(hex: string | Uint8Array): string {
if (typeof hex === "string") {
const valid = "0123456789abcdef"
if (hex.length % 2 != 0) {
throw new ProtocolError(`invalid hex string: ${hex}`)
}
for (const c of hex) {
if (!valid.includes(c)) {
throw new ProtocolError(`invalid hex string: ${hex}`)
}
}
return hex
} else {
return secp.utils.bytesToHex(hex).toLowerCase()
}
}

View File

@ -0,0 +1,55 @@
import { Nostr } from "../src/client"
import { EventKind } from "../src/event"
import { PrivateKey } from "../src/keypair"
import assert from "assert"
// TODO Switch out the relay implementation and see if the issue persists
describe("single event communication", function () {
it("ok", function (done) {
const secret = new PrivateKey(
"nsec1xlu55y6fqfgrq448xslt6a8j2rh7lj08hyhgs94ryq04yf6surwsjl0kzh"
)
const pubkey = secret.pubkey
const timestamp = new Date()
const note = "hello world"
const publisher = new Nostr()
publisher.open("ws://localhost:12648")
const subscriber = new Nostr()
subscriber.open("ws://localhost:12648")
subscriber.on("event", ({ signed: { event } }) => {
assert.equal(event.kind, EventKind.TextNote)
assert.equal(event.pubkey.toString(), pubkey.toString())
assert.equal(event.createdAt.toString(), timestamp.toString())
if (event.kind === EventKind.TextNote) {
assert.equal(event.note, note)
}
// There is a bug with the nostr relay used for testing where if the publish and
// subscribe happen at the same time, the same event might end up being broadcast twice.
// To prevent reacting to the same event and calling done() twice, remove the callback
// for future events.
subscriber.on("event", null)
publisher.close()
subscriber.close()
done()
})
subscriber.subscribe()
publisher.publish(
{
kind: EventKind.TextNote,
createdAt: timestamp,
note,
pubkey,
},
secret
)
})
})

View File

@ -6,7 +6,9 @@
"sourceMap": true,
"composite": true,
"outDir": "dist",
"moduleResolution": "node"
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src"]
}

449
yarn.lock
View File

@ -1432,6 +1432,13 @@
dependencies:
jest-get-type "^29.4.2"
"@jest/expect-utils@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.4.3.tgz#95ce4df62952f071bcd618225ac7c47eaa81431e"
integrity sha512-/6JWbkxHOP8EoS8jeeTd9dTfc9Uawi+43oLKHfp6zzux3U2hqOOVnV3ai4RpDYHOccL6g+5nrxpoc8DmJxtXVQ==
dependencies:
jest-get-type "^29.4.3"
"@jest/fake-timers@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74"
@ -1498,6 +1505,13 @@
dependencies:
"@sinclair/typebox" "^0.25.16"
"@jest/schemas@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==
dependencies:
"@sinclair/typebox" "^0.25.16"
"@jest/source-map@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf"
@ -1593,6 +1607,18 @@
"@types/yargs" "^17.0.8"
chalk "^4.0.0"
"@jest/types@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.3.tgz#9069145f4ef09adf10cec1b2901b2d390031431f"
integrity sha512-bPYfw8V65v17m2Od1cv44FH+SiKW7w2Xu7trhcdTLUmSv85rfKsP+qXSjO4KGJr4dtPSzl/gvslZBXctf1qGEA==
dependencies:
"@jest/schemas" "^29.4.3"
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^17.0.8"
chalk "^4.0.0"
"@jridgewell/gen-mapping@^0.1.0":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
@ -1667,7 +1693,7 @@
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==
"@noble/secp256k1@^1.7.0":
"@noble/secp256k1@^1.7.0", "@noble/secp256k1@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==
@ -2033,6 +2059,13 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
"@types/expect@^24.3.0":
version "24.3.0"
resolved "https://registry.yarnpkg.com/@types/expect/-/expect-24.3.0.tgz#d7cab8b3c10c2d92a0cbb31981feceb81d3486f1"
integrity sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==
dependencies:
expect "*"
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33":
version "4.17.33"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543"
@ -2140,6 +2173,11 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==
"@types/mocha@^10.0.1":
version "10.0.1"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
@ -2319,6 +2357,22 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/eslint-plugin@^5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz#24b8b4a952f3c615fe070e3c461dd852b5056734"
integrity sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==
dependencies:
"@typescript-eslint/scope-manager" "5.53.0"
"@typescript-eslint/type-utils" "5.53.0"
"@typescript-eslint/utils" "5.53.0"
debug "^4.3.4"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
natural-compare-lite "^1.4.0"
regexpp "^3.2.0"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@^5.0.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.51.0.tgz#936124843a9221863f027a08063b737578838bea"
@ -2336,6 +2390,16 @@
"@typescript-eslint/typescript-estree" "5.51.0"
debug "^4.3.4"
"@typescript-eslint/parser@^5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.53.0.tgz#a1f2b9ae73b83181098747e96683f1b249ecab52"
integrity sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==
dependencies:
"@typescript-eslint/scope-manager" "5.53.0"
"@typescript-eslint/types" "5.53.0"
"@typescript-eslint/typescript-estree" "5.53.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz#ad3e3c2ecf762d9a4196c0fbfe19b142ac498990"
@ -2344,6 +2408,14 @@
"@typescript-eslint/types" "5.51.0"
"@typescript-eslint/visitor-keys" "5.51.0"
"@typescript-eslint/scope-manager@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz#42b54f280e33c82939275a42649701024f3fafef"
integrity sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==
dependencies:
"@typescript-eslint/types" "5.53.0"
"@typescript-eslint/visitor-keys" "5.53.0"
"@typescript-eslint/type-utils@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz#7af48005531700b62a20963501d47dfb27095988"
@ -2354,11 +2426,26 @@
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/type-utils@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz#41665449935ba9b4e6a1ba6e2a3f4b2c31d6cf97"
integrity sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==
dependencies:
"@typescript-eslint/typescript-estree" "5.53.0"
"@typescript-eslint/utils" "5.53.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.51.0.tgz#e7c1622f46c7eea7e12bbf1edfb496d4dec37c90"
integrity sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==
"@typescript-eslint/types@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f"
integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==
"@typescript-eslint/typescript-estree@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz#0ec8170d7247a892c2b21845b06c11eb0718f8de"
@ -2372,6 +2459,19 @@
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/typescript-estree@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz#bc651dc28cf18ab248ecd18a4c886c744aebd690"
integrity sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==
dependencies:
"@typescript-eslint/types" "5.53.0"
"@typescript-eslint/visitor-keys" "5.53.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.51.0", "@typescript-eslint/utils@^5.43.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.51.0.tgz#074f4fabd5b12afe9c8aa6fdee881c050f8b4d47"
@ -2386,6 +2486,20 @@
eslint-utils "^3.0.0"
semver "^7.3.7"
"@typescript-eslint/utils@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.53.0.tgz#e55eaad9d6fffa120575ffaa530c7e802f13bce8"
integrity sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==
dependencies:
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.53.0"
"@typescript-eslint/types" "5.53.0"
"@typescript-eslint/typescript-estree" "5.53.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.51.0":
version "5.51.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz#c0147dd9a36c0de758aaebd5b48cae1ec59eba87"
@ -2394,6 +2508,14 @@
"@typescript-eslint/types" "5.51.0"
eslint-visitor-keys "^3.3.0"
"@typescript-eslint/visitor-keys@5.53.0":
version "5.53.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz#8a5126623937cdd909c30d8fa72f79fa56cc1a9f"
integrity sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==
dependencies:
"@typescript-eslint/types" "5.53.0"
eslint-visitor-keys "^3.3.0"
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -2655,6 +2777,11 @@ ajv@^8.0.0, ajv@^8.6.0, ajv@^8.8.0:
require-from-string "^2.0.2"
uri-js "^4.2.2"
ansi-colors@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1:
version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@ -2801,6 +2928,11 @@ array.prototype.tosorted@^1.1.1:
es-shim-unscopables "^1.0.0"
get-intrinsic "^1.1.3"
arrify@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
asap@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
@ -3152,6 +3284,11 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
browser-stdout@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4:
version "4.21.5"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7"
@ -3169,7 +3306,7 @@ bser@2.1.1:
dependencies:
node-int64 "^0.4.0"
buffer-from@^1.0.0:
buffer-from@^1.0.0, buffer-from@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
@ -3228,7 +3365,7 @@ camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelcase@^6.2.0, camelcase@^6.2.1:
camelcase@^6.0.0, camelcase@^6.2.0, camelcase@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
@ -3290,7 +3427,7 @@ check-types@^11.1.1:
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4"
integrity sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==
chokidar@^3.4.2, chokidar@^3.5.3:
chokidar@3.5.3, chokidar@^3.4.2, chokidar@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@ -3807,7 +3944,7 @@ debug@2.6.9, debug@^2.6.0:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -3821,6 +3958,11 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
decamelize@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
decimal.js@^10.2.1:
version "10.4.3"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
@ -3973,6 +4115,21 @@ diff-sequences@^29.4.2:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.2.tgz#711fe6bd8a5869fe2539cee4a5152425ff671fda"
integrity sha512-R6P0Y6PrsH3n4hUXxL3nns0rbRk6Q33js3ygJBeEpbzLzgcNuJ61+u0RXasFpTKISw99TxUzFnumSnRLsjhLaw==
diff-sequences@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
diff@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
diff@^3.1.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
diff@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
@ -4287,6 +4444,11 @@ escape-html@~1.0.3:
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@ -4297,11 +4459,6 @@ escape-string-regexp@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escodegen@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
@ -4485,7 +4642,7 @@ eslint-webpack-plugin@^3.1.1:
normalize-path "^3.0.0"
schema-utils "^4.0.0"
eslint@^8.3.0:
eslint@^8.3.0, eslint@^8.34.0:
version "8.34.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6"
integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==
@ -4628,6 +4785,17 @@ exit@^0.1.2:
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
expect@*:
version "29.4.3"
resolved "https://registry.yarnpkg.com/expect/-/expect-29.4.3.tgz#5e47757316df744fe3b8926c3ae8a3ebdafff7fe"
integrity sha512-uC05+Q7eXECFpgDrHdXA4k2rpMyStAYPItEDLyQDo5Ta7fVkJnNA/4zh/OIVkVVNZ1oOK1PipQoyNjuZ6sz6Dg==
dependencies:
"@jest/expect-utils" "^29.4.3"
jest-get-type "^29.4.3"
jest-matcher-utils "^29.4.3"
jest-message-util "^29.4.3"
jest-util "^29.4.3"
expect@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74"
@ -4794,6 +4962,14 @@ find-cache-dir@^3.3.1:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
find-up@5.0.0, find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@ -4809,14 +4985,6 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
dependencies:
locate-path "^6.0.0"
path-exists "^4.0.0"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@ -4825,6 +4993,11 @@ flat-cache@^3.0.4:
flatted "^3.1.0"
rimraf "^3.0.2"
flat@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
flatted@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
@ -5000,6 +5173,18 @@ glob-to-regexp@^0.4.1:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
glob@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@ -5144,7 +5329,7 @@ hast-util-whitespace@^2.0.0:
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557"
integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==
he@^1.2.0:
he@1.2.0, he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@ -5571,6 +5756,11 @@ is-path-inside@^3.0.3:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-plain-obj@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
@ -5656,6 +5846,11 @@ is-typedarray@^1.0.0:
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
is-weakmap@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
@ -5857,6 +6052,16 @@ jest-diff@^29.4.2:
jest-get-type "^29.4.2"
pretty-format "^29.4.2"
jest-diff@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.4.3.tgz#42f4eb34d0bf8c0fb08b0501069b87e8e84df347"
integrity sha512-YB+ocenx7FZ3T5O9lMVMeLYV4265socJKtkwgk/6YUz/VsEzYDkiMuMhWzZmxm3wDRQvayJu/PjkjjSkjoHsCA==
dependencies:
chalk "^4.0.0"
diff-sequences "^29.4.3"
jest-get-type "^29.4.3"
pretty-format "^29.4.3"
jest-docblock@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0"
@ -5910,6 +6115,11 @@ jest-get-type@^29.4.2:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.2.tgz#7cb63f154bca8d8f57364d01614477d466fa43fe"
integrity sha512-vERN30V5i2N6lqlFu4ljdTqQAgrkTFMC9xaIIfOPYBw04pufjXRty5RuXBiB1d72tGbURa/UgoiHB90ruOSivg==
jest-get-type@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5"
integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==
jest-haste-map@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f"
@ -5981,6 +6191,16 @@ jest-matcher-utils@^29.4.2:
jest-get-type "^29.4.2"
pretty-format "^29.4.2"
jest-matcher-utils@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.4.3.tgz#ea68ebc0568aebea4c4213b99f169ff786df96a0"
integrity sha512-TTciiXEONycZ03h6R6pYiZlSkvYgT0l8aa49z/DLSGYjex4orMUcafuLXYyyEDWB1RKglq00jzwY00Ei7yFNVg==
dependencies:
chalk "^4.0.0"
jest-diff "^29.4.3"
jest-get-type "^29.4.3"
pretty-format "^29.4.3"
jest-message-util@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf"
@ -6026,6 +6246,21 @@ jest-message-util@^29.4.2:
slash "^3.0.0"
stack-utils "^2.0.3"
jest-message-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.3.tgz#65b5280c0fdc9419503b49d4f48d4999d481cb5b"
integrity sha512-1Y8Zd4ZCN7o/QnWdMmT76If8LuDv23Z1DRovBj/vcSFNlGCJGoO8D1nJDw1AdyAGUk0myDLFGN5RbNeJyCRGCw==
dependencies:
"@babel/code-frame" "^7.12.13"
"@jest/types" "^29.4.3"
"@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.9"
micromatch "^4.0.4"
pretty-format "^29.4.3"
slash "^3.0.0"
stack-utils "^2.0.3"
jest-mock@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6"
@ -6201,6 +6436,18 @@ jest-util@^29.4.2:
graceful-fs "^4.2.9"
picomatch "^2.2.3"
jest-util@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.3.tgz#851a148e23fc2b633c55f6dad2e45d7f4579f496"
integrity sha512-ToSGORAz4SSSoqxDSylWX8JzkOQR7zoBtNRsA7e+1WUX5F8jrOwaNpuh1YfJHJKDHXLHmObv5eOjejUd+/Ws+Q==
dependencies:
"@jest/types" "^29.4.3"
"@types/node" "*"
chalk "^4.0.0"
ci-info "^3.2.0"
graceful-fs "^4.2.9"
picomatch "^2.2.3"
jest-validate@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067"
@ -6304,6 +6551,13 @@ js-sha3@0.8.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
js-yaml@4.1.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
@ -6312,13 +6566,6 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsdom@^16.6.0:
version "16.7.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710"
@ -6394,7 +6641,7 @@ json-stable-stringify@^1.0.1:
dependencies:
jsonify "^0.0.1"
json5@^1.0.1:
json5@^1.0.1, json5@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
@ -6614,6 +6861,14 @@ lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
dependencies:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
log-update@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
@ -6666,6 +6921,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
makeerror@1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
@ -7025,6 +7285,13 @@ minimalistic-assert@^1.0.0:
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
minimatch@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
dependencies:
brace-expansion "^2.0.1"
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@ -7044,13 +7311,40 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
mkdirp@~0.5.1:
mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
dependencies:
minimist "^1.2.6"
mocha@^10.2.0:
version "10.2.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8"
integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==
dependencies:
ansi-colors "4.1.1"
browser-stdout "1.3.1"
chokidar "3.5.3"
debug "4.3.4"
diff "5.0.0"
escape-string-regexp "4.0.0"
find-up "5.0.0"
glob "7.2.0"
he "1.2.0"
js-yaml "4.1.0"
log-symbols "4.1.0"
minimatch "5.0.1"
ms "2.1.3"
nanoid "3.3.3"
serialize-javascript "6.0.0"
strip-json-comments "3.1.1"
supports-color "8.1.1"
workerpool "6.2.1"
yargs "16.2.0"
yargs-parser "20.2.4"
yargs-unparser "2.0.0"
mri@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
@ -7086,6 +7380,11 @@ nano-time@1.0.0:
dependencies:
big-integer "^1.6.16"
nanoid@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
@ -8136,6 +8435,15 @@ pretty-format@^29.0.0, pretty-format@^29.4.2:
ansi-styles "^5.0.0"
react-is "^18.0.0"
pretty-format@^29.4.3:
version "29.4.3"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.3.tgz#25500ada21a53c9e8423205cf0337056b201244c"
integrity sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==
dependencies:
"@jest/schemas" "^29.4.3"
ansi-styles "^5.0.0"
react-is "^18.0.0"
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@ -8941,6 +9249,13 @@ send@0.18.0:
range-parser "~1.2.1"
statuses "2.0.1"
serialize-javascript@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
dependencies:
randombytes "^2.1.0"
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
@ -9323,7 +9638,7 @@ strip-final-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
@ -9348,6 +9663,13 @@ stylehacks@^5.1.1:
browserslist "^4.21.4"
postcss-selector-parser "^6.0.4"
supports-color@8.1.1, supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -9362,13 +9684,6 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624"
@ -9602,6 +9917,29 @@ tryer@^1.0.1:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
ts-mocha@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9"
integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==
dependencies:
ts-node "7.0.1"
optionalDependencies:
tsconfig-paths "^3.5.0"
ts-node@7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf"
integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==
dependencies:
arrify "^1.0.0"
buffer-from "^1.1.0"
diff "^3.1.0"
make-error "^1.1.1"
minimist "^1.2.0"
mkdirp "^0.5.1"
source-map-support "^0.5.6"
yn "^2.0.0"
tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
@ -9612,6 +9950,16 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"
tsconfig-paths@^3.5.0:
version "3.14.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==
dependencies:
"@types/json5" "^0.0.29"
json5 "^1.0.2"
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@ -10367,6 +10715,11 @@ workbox-window@6.5.4:
"@types/trusted-types" "^2.0.2"
workbox-core "6.5.4"
workerpool@6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
wrap-ansi@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
@ -10455,12 +10808,27 @@ yaml@^2.1.3:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4"
integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==
yargs-parser@20.2.4:
version "20.2.4"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
yargs-parser@^20.2.2:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs@^16.2.0:
yargs-unparser@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
dependencies:
camelcase "^6.0.0"
decamelize "^4.0.0"
flat "^5.0.2"
is-plain-obj "^2.1.0"
yargs@16.2.0, yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
@ -10473,6 +10841,11 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yn@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a"
integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"