From eeb9f2d13c12258dee91115ded669a9b885e3238 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Mon, 22 May 2023 13:03:18 -0700 Subject: [PATCH 001/137] feat: begin adding some group conversation features --- package-lock.json | 91 ++++------------ package.json | 1 - src/Invitation.ts | 2 + src/conversations/Conversations.ts | 73 ++++++++++++- src/conversations/GroupConversation.ts | 90 ++++++++++++++++ src/index.ts | 1 + src/keystore/InMemoryKeystore.ts | 140 ++++++++++++++++++++++--- src/keystore/interfaces.ts | 14 +++ test/keystore/InMemoryKeystore.test.ts | 2 +- 9 files changed, 330 insertions(+), 84 deletions(-) create mode 100644 src/conversations/GroupConversation.ts diff --git a/package-lock.json b/package-lock.json index 143be190c..eaaf6677e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", @@ -2612,27 +2611,32 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "dev": true }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "dev": true }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dev": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2641,27 +2645,32 @@ "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "dev": true }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "dev": true }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "dev": true }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "dev": true }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true }, "node_modules/@semantic-release/commit-analyzer": { "version": "9.0.2", @@ -2987,7 +2996,8 @@ "node_modules/@types/long": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", + "dev": true }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -2998,7 +3008,8 @@ "node_modules/@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3290,41 +3301,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@xmtp/proto": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.24.0.tgz", - "integrity": "sha512-RPzv+E7TOttY3Xs6+LE2ctQxzVLcdZLMzSeS+MEG2vBO8Dl/bhojGs/MehJorZzWHCLtL5VDPq0IY164RLqC7w==", - "dependencies": { - "long": "^5.2.0", - "protobufjs": "^7.0.0", - "rxjs": "^7.8.0", - "undici": "^5.8.1" - } - }, - "node_modules/@xmtp/proto/node_modules/protobufjs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.0.0.tgz", - "integrity": "sha512-ffNIEm+quOcYtQvHdW406v1NQmZSuqVklxsXk076BtuFnlYZfigLU+JOMrTD8TUOyqHYbRI/fSVNvgd25YeN3w==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -12533,19 +12509,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -13789,14 +13752,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.8.2.tgz", - "integrity": "sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A==", - "engines": { - "node": ">=12.18" - } - }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", diff --git a/package.json b/package.json index b864aa071..1ca13058b 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,6 @@ }, "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", diff --git a/src/Invitation.ts b/src/Invitation.ts index 4dabc1b73..1b23c797c 100644 --- a/src/Invitation.ts +++ b/src/Invitation.ts @@ -6,11 +6,13 @@ import Ciphertext from './crypto/Ciphertext' import { decrypt, encrypt } from './crypto' import { PrivateKeyBundleV2 } from './crypto/PrivateKeyBundle' import { dateToNs, buildDirectMessageTopicV2 } from './utils' +import { InvitationV1_GroupContext } from '@xmtp/proto/ts/dist/types/message_contents/invitation.pb' // eslint-disable-line camelcase const { b64Decode } = fetcher export type InvitationContext = { conversationId: string metadata: { [k: string]: string } + groupContext?: InvitationV1_GroupContext // eslint-disable-line camelcase } /** diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 83579e07c..b8b4d8b75 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -17,6 +17,8 @@ import { import { PublicKeyBundle } from '../crypto' import { SortDirection } from '../ApiClient' import Long from 'long' +import { toSignedPublicKeyBundle } from '../keystore/utils' +import { GroupConversation } from './GroupConversation' const CLOCK_SKEW_OFFSET_MS = 10000 @@ -182,7 +184,15 @@ export default class Conversations { const out: ConversationV2[] = [] for (const response of responses) { try { - const convo = this.saveInviteResponseToConversation(response) + let convo = this.saveInviteResponseToConversation(response) + + if (convo.context?.groupContext?.initialMembers) { + convo = GroupConversation.from( + convo, + convo.context?.groupContext?.initialMembers + ) + } + out.push(convo) } catch (e) { console.warn('Error saving invite response to conversation: ', e) @@ -429,6 +439,67 @@ export default class Conversations { return seenPeers } + async newGroupConversation( + context: InvitationContext + ): Promise { + const timestamp = new Date() + + const initialMembers = context.groupContext?.initialMembers + + if (!initialMembers) { + throw new Error('No initial members provided') + } + + const members = await Promise.all( + initialMembers.map(async (member) => { + let contact = await this.client.getUserContact(member) + if (!contact) { + throw new Error(`Recipient ${member} is not on the XMTP network`) + } + + // Coerce the contact into a V2 bundle + if (contact instanceof PublicKeyBundle) { + contact = SignedPublicKeyBundle.fromLegacyBundle(contact) + } + + return toSignedPublicKeyBundle(contact) + }) + ) + + const inviteResponses = await this.client.keystore.createInvites({ + recipients: members, + context, + createdNs: dateToNs(timestamp), + }) + + const envelopes = inviteResponses.map((response) => { + if (!response.conversation) { + throw new Error( + 'no conversation for response: ' + JSON.stringify(response) + ) + } + + return { + contentTopic: buildUserInviteTopic(response.conversation?.peerAddress), + message: response.payload, + timestamp, + } + }) + + await this.client.publishEnvelopes(envelopes) + + const conversation = inviteResponses[0].conversation + + if (!conversation) { + throw new Error('no conversation for response') + } + + return GroupConversation.from( + this.conversationReferenceToV2(conversation), + initialMembers + ) + } + /** * Creates a new conversation for the given address. Will throw an error if the peer is not found in the XMTP network */ diff --git a/src/conversations/GroupConversation.ts b/src/conversations/GroupConversation.ts new file mode 100644 index 000000000..32759fef1 --- /dev/null +++ b/src/conversations/GroupConversation.ts @@ -0,0 +1,90 @@ +import Client from '../Client' +import { Conversation, ConversationV2 } from './Conversation' +import { InvitationContext } from '../Invitation' +import { PublicKeyBundle, SignedPublicKeyBundle } from '../crypto' +import { toSignedPublicKeyBundle } from '../keystore/utils' +import { buildUserInviteTopic, dateToNs } from '../utils' + +export class GroupConversation extends ConversationV2 implements Conversation { + client: Client + peerAddress: string + topic: string + createdAt: Date + memberAddresses: string[] = [] + + constructor( + client: Client, + topic: string, + peerAddress: string, + createdAt: Date, + context: InvitationContext | undefined, + membersAddresses: string[] + ) { + super(client, topic, peerAddress, createdAt, context) + this.topic = topic + this.createdAt = createdAt + this.context = context + this.client = client + this.peerAddress = peerAddress + this.memberAddresses = membersAddresses + } + + static from( + conversation: Conversation, + memberAddresses: string[] + ): GroupConversation { + if (!(conversation instanceof ConversationV2)) { + throw new Error('Conversation is not a V2 conversation') + } + + return new GroupConversation( + conversation.client, + conversation.topic, + conversation.peerAddress, + conversation.createdAt, + conversation.context, + memberAddresses + ) + } + + async addMember(newMemberAddress: string) { + const timestamp = new Date() + + let contact = await this.client.getUserContact(newMemberAddress) + if (!contact) { + throw new Error( + `Recipient ${newMemberAddress} is not on the XMTP network` + ) + } + + // Coerce the contact into a V2 bundle + if (contact instanceof PublicKeyBundle) { + contact = SignedPublicKeyBundle.fromLegacyBundle(contact) + } + + const recipient = toSignedPublicKeyBundle(contact) + + const inviteResponse = await this.client.keystore.createInviteFromTopic({ + context: this.context, + contentTopic: this.topic, + recipient, + createdNs: dateToNs(timestamp), + }) + + if (!inviteResponse.conversation) { + throw new Error( + 'no conversation for response: ' + JSON.stringify(inviteResponse) + ) + } + + const envelope = { + contentTopic: buildUserInviteTopic( + inviteResponse.conversation?.peerAddress + ), + message: inviteResponse.payload, + timestamp, + } + + await this.client.publishEnvelopes([envelope]) + } +} diff --git a/src/index.ts b/src/index.ts index a8e096393..674c1fd0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,7 @@ export { LegacyOptions, } from './Client' export { Conversations, Conversation } from './conversations' +export { GroupConversation } from './conversations/GroupConversation' export { CodecRegistry, ContentTypeId, diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 156637059..a7ad62806 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -10,7 +10,7 @@ import { PrivateKeyBundleV2, } from './../crypto/PrivateKeyBundle' import { InvitationV1, SealedInvitation } from './../Invitation' -import { PrivateKey, PublicKeyBundle } from '../crypto' +import { PrivateKey, PublicKeyBundle, SignedPublicKeyBundle } from '../crypto' import { Keystore, TopicData } from './interfaces' import { decryptV1, encryptV1, encryptV2, decryptV2 } from './encryption' import { KeystoreError } from './errors' @@ -27,6 +27,9 @@ import { nsToDate } from '../utils' import InviteStore from './InviteStore' import { Persistence } from './persistence' import LocalAuthenticator from '../authn/LocalAuthenticator' +import Long from 'long' +import { Wallet } from 'ethers' +import Client from '../Client' const { ErrorCode } = keystore export default class InMemoryKeystore implements Keystore { @@ -251,28 +254,139 @@ export default class InMemoryKeystore implements Keystore { const invitation = InvitationV1.createRandom(req.context) const created = nsToDate(req.createdNs) const recipient = toSignedPublicKeyBundle(req.recipient) - const sealed = await SealedInvitation.createV1({ - sender: this.v2Keys, + + return await this.makeInvite( + this.v2Keys, recipient, created, - invitation, - }) - const topicData = { - invitation, - createdNs: req.createdNs, - peerAddress: await recipient.walletSignatureAddress(), + req.createdNs, + invitation + ) + } catch (e) { + throw convertError(e as Error, ErrorCode.ERROR_CODE_INVALID_INPUT) + } + } + + async createInvites( + req: keystore.CreateInvitesRequest + ): Promise { + try { + if (!validateObject(req, ['recipients'], [])) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'missing recipients' + ) } - await this.inviteStore.add([topicData]) - return keystore.CreateInviteResponse.fromPartial({ - conversation: topicDataToConversationReference(topicData), - payload: sealed.toBytes(), + // Register an address on the network for the group + const sharedWallet = Wallet.createRandom() + const sharedClient = await Client.create(sharedWallet) + const sharedPrivateKeyBundle = + await sharedClient.keystore.getPrivateKeyBundle() + + if (!sharedPrivateKeyBundle) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'missing private key bundle' + ) + } + + const invitation = InvitationV1.createRandom(req.context) + const created = nsToDate(req.createdNs) + const recipients = req.recipients.map(toSignedPublicKeyBundle) + + return Promise.all( + recipients.map(async (recipient) => { + return await this.makeInvite( + PrivateKeyBundleV2.fromLegacyBundle( + new PrivateKeyBundleV1(sharedPrivateKeyBundle) + ), + recipient, + created, + req.createdNs, + invitation + ) + }) + ) + } catch (e) { + throw convertError(e as Error, ErrorCode.ERROR_CODE_INVALID_INPUT) + } + } + + async createInviteFromTopic( + req: keystore.CreateInviteFromTopicRequest + ): Promise { + try { + if (!validateObject(req, ['contentTopic'], [])) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'missing topic' + ) + } + + const topicData = this.inviteStore.lookup(req.contentTopic) + if (!topicData) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'missing topic data' + ) + } + + const invitation = new InvitationV1({ + context: topicData.invitation.context, + topic: req.contentTopic, + aes256GcmHkdfSha256: topicData.invitation.aes256GcmHkdfSha256, }) + + const created = nsToDate(req.createdNs) + const recipient = toSignedPublicKeyBundle(req.recipient) + + return await this.makeInvite( + this.v2Keys, + recipient, + created, + req.createdNs, + invitation + ) } catch (e) { throw convertError(e as Error, ErrorCode.ERROR_CODE_INVALID_INPUT) } } + private async makeInvite( + senderKeys: PrivateKeyBundleV2, + recipient: SignedPublicKeyBundle, + created: Date, + createdNs: Long, + invitation: InvitationV1 + ): Promise { + const sealed = await SealedInvitation.createV1({ + sender: senderKeys, + recipient, + created, + invitation, + }) + + const conversation = topicDataToConversationReference({ + invitation, + createdNs, + peerAddress: await recipient.walletSignatureAddress(), + }) + + const topicData = { + invitation, + createdNs, + peerAddress: await recipient.walletSignatureAddress(), + } + + await this.inviteStore.add([topicData]) + + return keystore.CreateInviteResponse.fromPartial({ + conversation, + payload: sealed.toBytes(), + }) + } + async signDigest( req: keystore.SignDigestRequest ): Promise { diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index e220f2dd9..a8abe4a5f 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -42,6 +42,20 @@ export interface Keystore { createInvite( req: keystore.CreateInviteRequest ): Promise + /** + * Create multiple sealed/encrypted invites and store the Topic keys in the Keystore for later use. + * The returned invite payload must be sent to the network for the other party to be able to communicate. + */ + createInvites( + req: keystore.CreateInvitesRequest + ): Promise + /** + * Create a sealed/encrypted invite for the given topic and store the Topic keys in the Keystore for later use. + * The returned invite payload must be sent to the network for the other party to be able to communicate. + */ + createInviteFromTopic( + req: keystore.CreateInviteFromTopicRequest + ): Promise /** * Create an XMTP auth token to be used as a header on XMTP API requests */ diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index 777edcae0..9f16ee81e 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -482,7 +482,7 @@ describe('InMemoryKeystore', () => { it('creates an auth token', async () => { const authToken = new Token(await aliceKeystore.createAuthToken({})) expect(authToken.authDataBytes).toBeDefined() - expect(authToken.authData.createdNs).toBeInstanceOf(Long) + expect(Long.isLong(authToken.authData.createdNs)).toBe(true) expect(authToken.authDataSignature).toBeDefined() expect(authToken.identityKey?.secp256k1Uncompressed).toBeDefined() expect(authToken.identityKey?.signature).toBeDefined() From 25edc2eef389a2449e352dca15c427626a85f5fd Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 12:36:04 -0700 Subject: [PATCH 002/137] Use metadata instead of group context, remove redundant fields --- src/Invitation.ts | 2 -- src/conversations/Conversations.ts | 11 +++++------ src/keystore/InMemoryKeystore.ts | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Invitation.ts b/src/Invitation.ts index 1b23c797c..4dabc1b73 100644 --- a/src/Invitation.ts +++ b/src/Invitation.ts @@ -6,13 +6,11 @@ import Ciphertext from './crypto/Ciphertext' import { decrypt, encrypt } from './crypto' import { PrivateKeyBundleV2 } from './crypto/PrivateKeyBundle' import { dateToNs, buildDirectMessageTopicV2 } from './utils' -import { InvitationV1_GroupContext } from '@xmtp/proto/ts/dist/types/message_contents/invitation.pb' // eslint-disable-line camelcase const { b64Decode } = fetcher export type InvitationContext = { conversationId: string metadata: { [k: string]: string } - groupContext?: InvitationV1_GroupContext // eslint-disable-line camelcase } /** diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index b8b4d8b75..bc1da03db 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -186,11 +186,10 @@ export default class Conversations { try { let convo = this.saveInviteResponseToConversation(response) - if (convo.context?.groupContext?.initialMembers) { - convo = GroupConversation.from( - convo, - convo.context?.groupContext?.initialMembers - ) + const initialMembers = convo.context?.metadata.initialMembers.split(',') + + if (initialMembers) { + convo = GroupConversation.from(convo, initialMembers) } out.push(convo) @@ -444,7 +443,7 @@ export default class Conversations { ): Promise { const timestamp = new Date() - const initialMembers = context.groupContext?.initialMembers + const initialMembers = context.metadata.initialMembers?.split(',') if (!initialMembers) { throw new Error('No initial members provided') diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index a7ad62806..b1a746c14 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -338,14 +338,14 @@ export default class InMemoryKeystore implements Keystore { aes256GcmHkdfSha256: topicData.invitation.aes256GcmHkdfSha256, }) - const created = nsToDate(req.createdNs) + const created = nsToDate(topicData.createdNs) const recipient = toSignedPublicKeyBundle(req.recipient) return await this.makeInvite( this.v2Keys, recipient, created, - req.createdNs, + topicData.createdNs, invitation ) } catch (e) { From 03022c1890ec7c56bc71f5d2208c1ade47240a1c Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 14:42:39 -0700 Subject: [PATCH 003/137] Remove shared wallet --- src/conversations/GroupConversation.ts | 1 - src/keystore/InMemoryKeystore.ts | 31 ++++++++++---------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/conversations/GroupConversation.ts b/src/conversations/GroupConversation.ts index 32759fef1..5f5254240 100644 --- a/src/conversations/GroupConversation.ts +++ b/src/conversations/GroupConversation.ts @@ -65,7 +65,6 @@ export class GroupConversation extends ConversationV2 implements Conversation { const recipient = toSignedPublicKeyBundle(contact) const inviteResponse = await this.client.keystore.createInviteFromTopic({ - context: this.context, contentTopic: this.topic, recipient, createdNs: dateToNs(timestamp), diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index b1a746c14..5060dbd6a 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -23,7 +23,7 @@ import { getKeyMaterial, topicDataToConversationReference, } from './utils' -import { nsToDate } from '../utils' +import { dateToNs, nsToDate } from '../utils' import InviteStore from './InviteStore' import { Persistence } from './persistence' import LocalAuthenticator from '../authn/LocalAuthenticator' @@ -278,19 +278,6 @@ export default class InMemoryKeystore implements Keystore { ) } - // Register an address on the network for the group - const sharedWallet = Wallet.createRandom() - const sharedClient = await Client.create(sharedWallet) - const sharedPrivateKeyBundle = - await sharedClient.keystore.getPrivateKeyBundle() - - if (!sharedPrivateKeyBundle) { - throw new KeystoreError( - ErrorCode.ERROR_CODE_INVALID_INPUT, - 'missing private key bundle' - ) - } - const invitation = InvitationV1.createRandom(req.context) const created = nsToDate(req.createdNs) const recipients = req.recipients.map(toSignedPublicKeyBundle) @@ -298,9 +285,7 @@ export default class InMemoryKeystore implements Keystore { return Promise.all( recipients.map(async (recipient) => { return await this.makeInvite( - PrivateKeyBundleV2.fromLegacyBundle( - new PrivateKeyBundleV1(sharedPrivateKeyBundle) - ), + this.v2Keys, recipient, created, req.createdNs, @@ -324,6 +309,13 @@ export default class InMemoryKeystore implements Keystore { ) } + if (!validateObject(req, ['createdNs'], [])) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'missing createdNs' + ) + } + const topicData = this.inviteStore.lookup(req.contentTopic) if (!topicData) { throw new KeystoreError( @@ -338,13 +330,14 @@ export default class InMemoryKeystore implements Keystore { aes256GcmHkdfSha256: topicData.invitation.aes256GcmHkdfSha256, }) - const created = nsToDate(topicData.createdNs) const recipient = toSignedPublicKeyBundle(req.recipient) + topicData.createdNs = req.createdNs + return await this.makeInvite( this.v2Keys, recipient, - created, + nsToDate(req.createdNs), topicData.createdNs, invitation ) From a46043f800b8b7207c56f3ce031dd744b8eb9394 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 14:47:24 -0700 Subject: [PATCH 004/137] cleanup --- src/keystore/InMemoryKeystore.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 5060dbd6a..88f8788e3 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -23,13 +23,11 @@ import { getKeyMaterial, topicDataToConversationReference, } from './utils' -import { dateToNs, nsToDate } from '../utils' +import { nsToDate } from '../utils' import InviteStore from './InviteStore' import { Persistence } from './persistence' import LocalAuthenticator from '../authn/LocalAuthenticator' import Long from 'long' -import { Wallet } from 'ethers' -import Client from '../Client' const { ErrorCode } = keystore export default class InMemoryKeystore implements Keystore { From 8b39ad8850777939b009e525a384e58a1b31b69b Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 14:57:27 -0700 Subject: [PATCH 005/137] Add super basic test --- test/conversations/Conversations.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index ff5316410..b777c4b26 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -10,6 +10,8 @@ import { buildUserIntroTopic, sleep, } from '../../src/utils' +import { InvitationV1 } from '../../src/Invitation' +import { InvitationV1_Context } from '@xmtp/proto/ts/dist/types/message_contents/invitation.pb' describe('conversations', () => { let alice: Client @@ -368,4 +370,24 @@ describe('conversations', () => { expect(invites).toHaveLength(1) }) }) + + describe('newGroupConversation', () => { + it('sends invites to recipients', async () => { + const context = { + conversationId: '', + metadata: { + groupID: 'the-group-id', + initialMembers: [alice.address, charlie.address].join(','), + }, + } + + await bob.conversations.newGroupConversation(context) + + let invites = await alice.listInvitations() + expect(invites).toHaveLength(1) + + invites = await charlie.listInvitations() + expect(invites).toHaveLength(1) + }) + }) }) From e10adaaf37cbb3ed75be42cc0ebf83022effda4a Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 15:26:34 -0700 Subject: [PATCH 006/137] unlink proto npm --- package-lock.json | 109 +++++++++++++++++++++++++++++++++++++--------- package.json | 1 + 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index eaaf6677e..b5ae0ddc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@noble/secp256k1": "^1.5.2", + "@xmtp/proto": "^3.25.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", @@ -2611,32 +2612,27 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "dev": true + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "dev": true + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dev": true, "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -2645,32 +2641,27 @@ "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "dev": true + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "dev": true + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "dev": true + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "dev": true + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "dev": true + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "node_modules/@semantic-release/commit-analyzer": { "version": "9.0.2", @@ -3008,8 +2999,7 @@ "node_modules/@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3301,6 +3291,40 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@xmtp/proto": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.25.0.tgz", + "integrity": "sha512-neVPGr40QRAWmIcG3R3d3g6ziSdY8bmKeSFRb6zWANXB3wluHoEGmud5/jZw4u/AY3E6FuNCwVODGku86iIeHw==", + "dependencies": { + "long": "^5.2.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.8.0", + "undici": "^5.8.1" + } + }, + "node_modules/@xmtp/proto/node_modules/protobufjs": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", + "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -3856,6 +3880,17 @@ "semver": "^7.0.0" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -12509,6 +12544,19 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", + "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -12938,6 +12986,14 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -13752,6 +13808,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", diff --git a/package.json b/package.json index 1ca13058b..738c66a3f 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ }, "dependencies": { "@noble/secp256k1": "^1.5.2", + "@xmtp/proto": "^3.25.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", From 39d452a40d8f939aa3991efe98c32bd22b88adc3 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 23 May 2023 15:28:33 -0700 Subject: [PATCH 007/137] Make sure we're not mutating when we don't wanna --- src/keystore/InMemoryKeystore.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 88f8788e3..f53ecd9bc 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -314,7 +314,7 @@ export default class InMemoryKeystore implements Keystore { ) } - const topicData = this.inviteStore.lookup(req.contentTopic) + let topicData = this.inviteStore.lookup(req.contentTopic) if (!topicData) { throw new KeystoreError( ErrorCode.ERROR_CODE_INVALID_INPUT, @@ -322,6 +322,8 @@ export default class InMemoryKeystore implements Keystore { ) } + topicData = { ...topicData } + const invitation = new InvitationV1({ context: topicData.invitation.context, topic: req.contentTopic, From 6cc1dc1b242c342b8ae7e72225ff7bc3d65bd9e3 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 09:49:30 -0700 Subject: [PATCH 008/137] Update test to reflect group-ness being part of the conversation ID --- test/conversations/Conversations.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index b777c4b26..9b09ea4ce 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -374,9 +374,8 @@ describe('conversations', () => { describe('newGroupConversation', () => { it('sends invites to recipients', async () => { const context = { - conversationId: '', + conversationId: 'xmtp.org/groups/the-group-id', metadata: { - groupID: 'the-group-id', initialMembers: [alice.address, charlie.address].join(','), }, } From ad6d5821c733216035c44971442c42dd15a9ec93 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 09:49:44 -0700 Subject: [PATCH 009/137] Don't consider empty initialMembers as a group --- src/conversations/Conversations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index bc1da03db..4c4a6b8bd 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -188,7 +188,7 @@ export default class Conversations { const initialMembers = convo.context?.metadata.initialMembers.split(',') - if (initialMembers) { + if (initialMembers && initialMembers.length > 0) { convo = GroupConversation.from(convo, initialMembers) } From 0061e3dc26ac31525d64eab16f6a108883f789ff Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 09:50:51 -0700 Subject: [PATCH 010/137] use local we already have --- src/conversations/GroupConversation.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/conversations/GroupConversation.ts b/src/conversations/GroupConversation.ts index 5f5254240..ff9da2ce6 100644 --- a/src/conversations/GroupConversation.ts +++ b/src/conversations/GroupConversation.ts @@ -77,9 +77,7 @@ export class GroupConversation extends ConversationV2 implements Conversation { } const envelope = { - contentTopic: buildUserInviteTopic( - inviteResponse.conversation?.peerAddress - ), + contentTopic: buildUserInviteTopic(newMemberAddress), message: inviteResponse.payload, timestamp, } From 6869df990910523f236b1863141e6f359f5f8dc5 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 10:03:06 -0700 Subject: [PATCH 011/137] Simplify API for creating a new group convo --- src/conversations/Conversations.ts | 18 ++++++++++++------ test/conversations/Conversations.test.ts | 12 ++++-------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 4c4a6b8bd..0495d941c 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -19,6 +19,7 @@ import { SortDirection } from '../ApiClient' import Long from 'long' import { toSignedPublicKeyBundle } from '../keystore/utils' import { GroupConversation } from './GroupConversation' +import { bytesToHex } from '../crypto/utils' const CLOCK_SKEW_OFFSET_MS = 10000 @@ -439,16 +440,21 @@ export default class Conversations { } async newGroupConversation( - context: InvitationContext + initialMembers: string[] ): Promise { - const timestamp = new Date() - - const initialMembers = context.metadata.initialMembers?.split(',') - - if (!initialMembers) { + if (initialMembers.length === 0) { throw new Error('No initial members provided') } + const groupID = bytesToHex(crypto.getRandomValues(new Uint8Array(32))) + const context = { + conversationId: `xmtp.org/groups/${groupID}`, + metadata: { + initialMembers: initialMembers.join(','), + }, + } + + const timestamp = new Date() const members = await Promise.all( initialMembers.map(async (member) => { let contact = await this.client.getUserContact(member) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 9b09ea4ce..5d8e401ee 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -373,14 +373,10 @@ describe('conversations', () => { describe('newGroupConversation', () => { it('sends invites to recipients', async () => { - const context = { - conversationId: 'xmtp.org/groups/the-group-id', - metadata: { - initialMembers: [alice.address, charlie.address].join(','), - }, - } - - await bob.conversations.newGroupConversation(context) + await bob.conversations.newGroupConversation([ + alice.address, + charlie.address, + ]) let invites = await alice.listInvitations() expect(invites).toHaveLength(1) From 748720e486376536ef3e336ddba07440ad50f99c Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 11:25:09 -0700 Subject: [PATCH 012/137] Make sure creator address is in initial members and dedup --- src/conversations/Conversations.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 0495d941c..40719b777 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -454,6 +454,9 @@ export default class Conversations { }, } + initialMembers.push(this.client.address) + initialMembers = [...new Set(initialMembers)] + const timestamp = new Date() const members = await Promise.all( initialMembers.map(async (member) => { From 1746cca16a1545059ff81395320530ed1b9731d2 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 13:39:25 -0700 Subject: [PATCH 013/137] Avoid self dh --- src/conversations/Conversations.ts | 21 +++++++++++++++++---- test/conversations/Conversations.test.ts | 3 +++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 40719b777..c00633649 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -442,6 +442,10 @@ export default class Conversations { async newGroupConversation( initialMembers: string[] ): Promise { + initialMembers = [...new Set(initialMembers)].filter( + (address) => address !== this.client.address + ) + if (initialMembers.length === 0) { throw new Error('No initial members provided') } @@ -454,9 +458,6 @@ export default class Conversations { }, } - initialMembers.push(this.client.address) - initialMembers = [...new Set(initialMembers)] - const timestamp = new Date() const members = await Promise.all( initialMembers.map(async (member) => { @@ -494,7 +495,19 @@ export default class Conversations { } }) - await this.client.publishEnvelopes(envelopes) + // Copy one of the invites to use for the creator. We do this to avoid having + // to self Diffie-Hellman which is problematic, security wise. + // + // This approach works because sealed invitation decrypting is sender/recipient + // agnostic. + // + // See https://github.com/xmtp/xmtp-js/blob/829257c10947618c34a66aa3857ca3557d4b52b6/src/Invitation.ts#L148-L160 + const creatorEnvelope = { ...envelopes[0] } + creatorEnvelope.contentTopic = buildUserInviteTopic(this.client.address) + + const envelopesToPublish = [creatorEnvelope, ...envelopes] + + await this.client.publishEnvelopes(envelopesToPublish) const conversation = inviteResponses[0].conversation diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 5d8e401ee..9aebab174 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -383,6 +383,9 @@ describe('conversations', () => { invites = await charlie.listInvitations() expect(invites).toHaveLength(1) + + invites = await bob.listInvitations() + expect(invites).toHaveLength(1) }) }) }) From 8ba9854132755c79322a9edc778865f311557b24 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 19:42:36 -0700 Subject: [PATCH 014/137] Introduce group content types --- src/codecs/GroupChatMemberAdded.ts | 39 +++ src/codecs/GroupChatMemberNicknameChanged.ts | 40 +++ src/codecs/GroupChatTitleChanged.ts | 43 ++++ src/conversations/Conversations.ts | 4 +- src/conversations/GroupChat.ts | 174 +++++++++++++ src/index.ts | 13 + test/conversations/GroupChat.test.ts | 243 +++++++++++++++++++ 7 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 src/codecs/GroupChatMemberAdded.ts create mode 100644 src/codecs/GroupChatMemberNicknameChanged.ts create mode 100644 src/codecs/GroupChatTitleChanged.ts create mode 100644 src/conversations/GroupChat.ts create mode 100644 test/conversations/GroupChat.test.ts diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts new file mode 100644 index 000000000..dca6d3ed0 --- /dev/null +++ b/src/codecs/GroupChatMemberAdded.ts @@ -0,0 +1,39 @@ +import { ContentCodec, ContentTypeId, EncodedContent } from '../index' + +export const ContentTypeGroupChatMemberAdded: ContentTypeId = { + typeId: 'groupChatMemberAdded', + authorityId: 'pat.xmtp.com', + versionMajor: 1, + versionMinor: 0, + sameAs(id) { + return ( + this.typeId === id.typeId && + this.authorityId === id.authorityId && + this.versionMajor === id.versionMajor && + this.versionMinor === id.versionMinor + ) + }, +} + +export type GroupChatMemberAdded = { + member: string +} + +export class GroupChatMemberAddedCodec + implements ContentCodec +{ + contentType = ContentTypeGroupChatMemberAdded + + encode(content: GroupChatMemberAdded): EncodedContent { + return { + type: ContentTypeGroupChatMemberAdded, + parameters: {}, + content: new TextEncoder().encode(JSON.stringify(content)), + } + } + + decode(encodedContent: EncodedContent): GroupChatMemberAdded { + const json = new TextDecoder().decode(encodedContent.content) + return JSON.parse(json) + } +} diff --git a/src/codecs/GroupChatMemberNicknameChanged.ts b/src/codecs/GroupChatMemberNicknameChanged.ts new file mode 100644 index 000000000..830434084 --- /dev/null +++ b/src/codecs/GroupChatMemberNicknameChanged.ts @@ -0,0 +1,40 @@ +import { ContentCodec, ContentTypeId, EncodedContent } from '../index' + +export const ContentTypeGroupChatMemberNicknameChanged: ContentTypeId = { + typeId: 'groupChatMemberNicknameChanged', + authorityId: 'pat.xmtp.com', + versionMajor: 1, + versionMinor: 0, + sameAs(id) { + return ( + this.typeId === id.typeId && + this.authorityId === id.authorityId && + this.versionMajor === id.versionMajor && + this.versionMinor === id.versionMinor + ) + }, +} + +export type GroupChatMemberNicknameChanged = { + // The new title + newNickname: string +} + +export class GroupChatMemberNicknameChangedCodec + implements ContentCodec +{ + contentType = ContentTypeGroupChatMemberNicknameChanged + + encode(content: GroupChatMemberNicknameChanged): EncodedContent { + return { + type: ContentTypeGroupChatMemberNicknameChanged, + parameters: {}, + content: new TextEncoder().encode(JSON.stringify(content)), + } + } + + decode(encodedContent: EncodedContent): GroupChatMemberNicknameChanged { + const json = new TextDecoder().decode(encodedContent.content) + return JSON.parse(json) + } +} diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts new file mode 100644 index 000000000..f2f2f837d --- /dev/null +++ b/src/codecs/GroupChatTitleChanged.ts @@ -0,0 +1,43 @@ +import { ContentCodec, ContentTypeId, EncodedContent } from '../index' + +export const ContentTypeGroupChatTitleChanged: ContentTypeId = { + typeId: 'groupChatTitleChanged', + authorityId: 'pat.xmtp.com', + versionMajor: 1, + versionMinor: 0, + sameAs(id) { + return ( + this.typeId === id.typeId && + this.authorityId === id.authorityId && + this.versionMajor === id.versionMajor && + this.versionMinor === id.versionMinor + ) + }, +} + +export type GroupChatTitleChanged = { + // The new title + newTitle: string + + // The old title + oldTitle: string +} + +export class GroupChatTitleChangedCodec + implements ContentCodec +{ + contentType = ContentTypeGroupChatTitleChanged + + encode(content: GroupChatTitleChanged): EncodedContent { + return { + type: ContentTypeGroupChatTitleChanged, + parameters: {}, + content: new TextEncoder().encode(JSON.stringify(content)), + } + } + + decode(encodedContent: EncodedContent): GroupChatTitleChanged { + const json = new TextDecoder().decode(encodedContent.content) + return JSON.parse(json) + } +} diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index c00633649..97d2d4593 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -454,7 +454,9 @@ export default class Conversations { const context = { conversationId: `xmtp.org/groups/${groupID}`, metadata: { - initialMembers: initialMembers.join(','), + initialMembers: [this.client.address, ...new Set(initialMembers)].join( + ',' + ), }, } diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts new file mode 100644 index 000000000..7b7c0dab6 --- /dev/null +++ b/src/conversations/GroupChat.ts @@ -0,0 +1,174 @@ +import { + Client, + Conversation, + GroupConversation, + SortDirection, +} from '../index' +import { + ContentTypeGroupChatMemberAdded, + GroupChatMemberAdded, + GroupChatMemberAddedCodec, +} from '../codecs/GroupChatMemberAdded' +import { + ContentTypeGroupChatTitleChanged, + GroupChatTitleChanged, + GroupChatTitleChangedCodec, +} from '../codecs/GroupChatTitleChanged' +import { + ContentTypeGroupChatMemberNicknameChanged, + GroupChatMemberNicknameChanged, + GroupChatMemberNicknameChangedCodec, +} from '../codecs/GroupChatMemberNicknameChanged' + +type RebuildOptions = { + since: Date +} + +export class GroupChat { + static contentTypes = [ + ContentTypeGroupChatMemberAdded, + GroupChatTitleChangedCodec, + ContentTypeGroupChatMemberNicknameChanged, + ] + + static codecs = [ + new GroupChatMemberAddedCodec(), + new GroupChatTitleChangedCodec(), + new GroupChatMemberNicknameChangedCodec(), + ] + + static registerCodecs(client: Client) { + for (const codec of GroupChat.codecs) { + client.registerCodec(codec) + } + } + + title = '' + memberClient: Client + conversation: Conversation + _members: string[] = [] + _memberConversation: Conversation | undefined + _nicknames: { [member: string]: string } = {} + + get members(): string[] { + return [...new Set(this._members)] + } + + set members(members: string[]) { + this._members = [...new Set(members)] + } + + constructor(memberClient: Client, conversation: Conversation) { + this.memberClient = memberClient + this.conversation = conversation + } + + static async fromConversation( + client: Client, + conversation: Conversation + ): Promise { + const groupChat = new GroupChat(client, conversation) + await groupChat.rebuild() + + return groupChat + } + + async rebuild(opts?: RebuildOptions | undefined) { + const members = + this.conversation.context?.metadata.initialMembers.split(',') + + if (!members) { + throw new Error('Conversation is not a group chat') + } + + this._members = members + + const startTime = opts?.since + + const messages = startTime + ? await this.conversation.messages({ + startTime, + direction: SortDirection.SORT_DIRECTION_ASCENDING, + }) + : await this.conversation.messages() + + for (const message of messages) { + if (message.contentType.sameAs(ContentTypeGroupChatMemberAdded)) { + const groupChatMemberAdded = message.content as GroupChatMemberAdded + this._members.push(groupChatMemberAdded.member) + } else if (message.contentType.sameAs(ContentTypeGroupChatTitleChanged)) { + const groupChatTitleChanged = message.content as GroupChatTitleChanged + this.title = groupChatTitleChanged.newTitle + } else if ( + message.contentType.sameAs(ContentTypeGroupChatMemberNicknameChanged) + ) { + const nicknameChange = message.content as GroupChatMemberNicknameChanged + this._nicknames[message.senderAddress] = nicknameChange.newNickname + } + } + } + + get memberNickname(): string { + return this._nicknames[this.memberClient.address] || '' + } + + nicknameFor(address: string): string { + return this._nicknames[address] || address + } + + async changeNickname(newNickname: string) { + const oldNickname = + this.memberNickname === '' + ? this.memberClient.address + : this.memberNickname + const nicknameChange: GroupChatMemberNicknameChanged = { + newNickname, + } + + await this.conversation.send(nicknameChange, { + contentType: ContentTypeGroupChatMemberNicknameChanged, + contentFallback: `${oldNickname} changed their nickname to ${newNickname}`, + }) + } + + async changeTitle(newTitle: string) { + const titleChange: GroupChatTitleChanged = { + oldTitle: this.title, + newTitle, + } + + await this.conversation.send(titleChange, { + contentType: ContentTypeGroupChatTitleChanged, + contentFallback: `${this.nicknameFor( + this.memberClient.address + )} changed the group title to ${newTitle}`, + }) + } + + async addMember(newMemberAddress: string) { + const memberAdded: GroupChatMemberAdded = { + member: newMemberAddress, + } + + await this.conversation.send(memberAdded, { + contentType: ContentTypeGroupChatMemberAdded, + contentFallback: `${this.nicknameFor( + this.memberClient.address + )} added ${newMemberAddress} to the group`, + }) + + this._members.push(newMemberAddress) + + const conversation = GroupConversation.from(this.conversation, this.members) + await conversation.addMember(newMemberAddress) + } + + static async start( + creatorClient: Client, + initialMembers: string[] + ): Promise { + return await creatorClient.conversations.newGroupConversation( + initialMembers + ) + } +} diff --git a/src/index.ts b/src/index.ts index 674c1fd0a..56f463767 100644 --- a/src/index.ts +++ b/src/index.ts @@ -80,3 +80,16 @@ export { } from './keystore/persistence' export { InvitationContext, SealedInvitation } from './Invitation' export { decodeContactBundle } from './ContactBundle' +export { GroupChat } from './conversations/GroupChat' +export { + GroupChatMemberAdded, + GroupChatMemberAddedCodec, +} from './codecs/GroupChatMemberAdded' +export { + GroupChatMemberNicknameChanged, + GroupChatMemberNicknameChangedCodec, +} from './codecs/GroupChatMemberNicknameChanged' +export { + GroupChatTitleChanged, + GroupChatTitleChangedCodec, +} from './codecs/GroupChatTitleChanged' diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts new file mode 100644 index 000000000..da2992f9a --- /dev/null +++ b/test/conversations/GroupChat.test.ts @@ -0,0 +1,243 @@ +import { newLocalHostClient, sleep, waitForUserContact } from './../helpers' +import { Client, Conversation, DecodedMessage, GroupChat } from '../../src' + +describe('GroupChat', () => { + let alice: Client + let bob: Client + let charlie: Client + + beforeEach(async () => { + alice = await newLocalHostClient({ publishLegacyContact: true }) + bob = await newLocalHostClient({ publishLegacyContact: true }) + charlie = await newLocalHostClient({ publishLegacyContact: true }) + await waitForUserContact(alice, alice) + await waitForUserContact(bob, bob) + await waitForUserContact(charlie, charlie) + }) + + afterEach(async () => { + if (alice) await alice.close() + if (bob) await bob.close() + if (charlie) await charlie.close() + }) + + async function conversationFromTopic( + topic: string, + client: Client + ): Promise { + const conversations = await client.conversations.list() + return conversations.find((conversation) => { + if (conversation.topic === topic) { + return conversation + } + }) + } + + async function messages( + topic: string, + client: Client + ): Promise { + const conversation = await conversationFromTopic(topic, client) + + if (!conversation) { + throw new Error('no conversation found for topic: ' + topic) + } + + return await conversation.messages() + } + + it('can be started', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const aliceGroupChat = await GroupChat.fromConversation( + alice, + aliceConversation + ) + + expect(aliceGroupChat.members.length).toBe(3) + + const bobConversations = await bob.conversations.list() + const charlieConversations = await charlie.conversations.list() + + expect(bobConversations.length).toBe(1) + expect(charlieConversations.length).toBe(1) + }) + + it('lets people chat', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + await aliceConversation.send('hi everyone') + + const bobMessages = await messages(aliceConversation.topic, bob) + const charlieMessages = await messages(aliceConversation.topic, charlie) + + expect(bobMessages.length).toBe(1) + expect(bobMessages[0].content).toBe('hi everyone') + expect(bobMessages[0].senderAddress).toBe(alice.address) + + expect(charlieMessages.length).toBe(1) + expect(charlieMessages[0].content).toBe('hi everyone') + expect(charlieMessages[0].senderAddress).toBe(alice.address) + + const charlieConversation = await conversationFromTopic( + aliceConversation.topic, + charlie + ) + + await charlieConversation!.send('hi nice to see u all') + + const bobMessages2 = await messages(aliceConversation.topic, bob) + const aliceMessages = await messages(aliceConversation.topic, alice) + + expect(bobMessages2.length).toBe(2) + expect(bobMessages2[1].content).toBe('hi nice to see u all') + expect(bobMessages2[1].senderAddress).toBe(charlie.address) + + expect(aliceMessages.length).toBe(2) + expect(aliceMessages[1].content).toBe('hi nice to see u all') + expect(aliceMessages[1].senderAddress).toBe(charlie.address) + }) + + it('can have a title', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const aliceGroupChat = new GroupChat(alice, aliceConversation) + expect(aliceGroupChat.title).toBe('') + + await aliceGroupChat.changeTitle('the fun group') + + const bobConversation = (await conversationFromTopic( + aliceConversation.topic, + bob + ))! + + const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation) + expect(bobGroupChat.title).toBe('the fun group') + + const charlieConversation = (await conversationFromTopic( + aliceConversation.topic, + charlie + ))! + + const charlieGroupChat = await GroupChat.fromConversation( + charlie, + charlieConversation + ) + expect(charlieGroupChat.title).toBe('the fun group') + }) + + it('members can have nicknames', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const aliceGroupChat = new GroupChat(alice, aliceConversation) + expect(aliceGroupChat.title).toBe('') + + await aliceGroupChat.changeNickname('alice') + + const bobConversation = (await conversationFromTopic( + aliceConversation.topic, + bob + ))! + + const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation) + expect(bobGroupChat.nicknameFor(alice.address)).toBe('alice') + + const charlieConversation = (await conversationFromTopic( + aliceConversation.topic, + charlie + ))! + + const charlieGroupChat = await GroupChat.fromConversation( + charlie, + charlieConversation + ) + expect(charlieGroupChat.nicknameFor('alice')).toBe('alice') + }) + + it('can be rebuilt', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const aliceGroupChat = new GroupChat(alice, aliceConversation) + expect(aliceGroupChat.title).toBe('') + + await aliceGroupChat.changeNickname('alice') + await aliceGroupChat.changeTitle('the fun group') + + const unbuiltGroupChat = new GroupChat(alice, aliceConversation) + expect(unbuiltGroupChat.title).toBe('') + expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) + + await unbuiltGroupChat.rebuild() + + expect(unbuiltGroupChat.title).toBe('the fun group') + expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe('alice') + }) + + it('can be rebuilt partially', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const aliceGroupChat = new GroupChat(alice, aliceConversation) + expect(aliceGroupChat.title).toBe('') + + await aliceGroupChat.changeNickname('alice') + + await sleep(1000) + const date = new Date() + await sleep(1000) + + await aliceGroupChat.changeTitle('the fun group') + + const unbuiltGroupChat = new GroupChat(alice, aliceConversation) + expect(unbuiltGroupChat.title).toBe('') + expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) + + await unbuiltGroupChat.rebuild({ since: date }) + + // We should only get the second update because the first one happened before + // our `since` + expect(unbuiltGroupChat.title).toBe('the fun group') + expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) + }) +}) From 513c7ecfc7bd7ca2aaff36eedf9a85ae42039e25 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 19:49:40 -0700 Subject: [PATCH 015/137] Add a test for adding members --- test/conversations/GroupChat.test.ts | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts index da2992f9a..a32fd2526 100644 --- a/test/conversations/GroupChat.test.ts +++ b/test/conversations/GroupChat.test.ts @@ -5,20 +5,24 @@ describe('GroupChat', () => { let alice: Client let bob: Client let charlie: Client + let carol: Client beforeEach(async () => { alice = await newLocalHostClient({ publishLegacyContact: true }) bob = await newLocalHostClient({ publishLegacyContact: true }) charlie = await newLocalHostClient({ publishLegacyContact: true }) + carol = await newLocalHostClient({ publishLegacyContact: true }) await waitForUserContact(alice, alice) await waitForUserContact(bob, bob) await waitForUserContact(charlie, charlie) + await waitForUserContact(carol, carol) }) afterEach(async () => { if (alice) await alice.close() if (bob) await bob.close() if (charlie) await charlie.close() + if (carol) await carol.close() }) async function conversationFromTopic( @@ -182,6 +186,31 @@ describe('GroupChat', () => { expect(charlieGroupChat.nicknameFor('alice')).toBe('alice') }) + it('can add members', async () => { + GroupChat.registerCodecs(alice) + GroupChat.registerCodecs(bob) + GroupChat.registerCodecs(charlie) + + const aliceConversation = await GroupChat.start(alice, [ + bob.address, + charlie.address, + ]) + + const groupChat = await GroupChat.fromConversation(alice, aliceConversation) + await groupChat.addMember(carol.address) + + const bobConversation = await conversationFromTopic( + aliceConversation.topic, + bob + ) + + const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation!) + await bobGroupChat.rebuild() + + expect(bobGroupChat.members.length).toBe(4) + expect(bobGroupChat.members[3]).toBe(carol.address) + }) + it('can be rebuilt', async () => { GroupChat.registerCodecs(alice) GroupChat.registerCodecs(bob) From 88551086929b88af4ba6beb45dda6c1f5bf67a3d Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 19:52:50 -0700 Subject: [PATCH 016/137] Add additional assertion to make sure member adding actually works --- test/conversations/GroupChat.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts index a32fd2526..4c9460860 100644 --- a/test/conversations/GroupChat.test.ts +++ b/test/conversations/GroupChat.test.ts @@ -209,6 +209,11 @@ describe('GroupChat', () => { expect(bobGroupChat.members.length).toBe(4) expect(bobGroupChat.members[3]).toBe(carol.address) + + await bobConversation!.send('hey carol') + + const carolMessages = await messages(aliceConversation.topic, carol) + expect(carolMessages[carolMessages.length - 1].content).toBe('hey carol') }) it('can be rebuilt', async () => { From 6f5d86046cabb3f57b89bce727c0e31a32643293 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 19:56:02 -0700 Subject: [PATCH 017/137] Update authority id --- src/codecs/GroupChatMemberAdded.ts | 2 +- src/codecs/GroupChatMemberNicknameChanged.ts | 2 +- src/codecs/GroupChatTitleChanged.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts index dca6d3ed0..b52f16c89 100644 --- a/src/codecs/GroupChatMemberAdded.ts +++ b/src/codecs/GroupChatMemberAdded.ts @@ -2,7 +2,7 @@ import { ContentCodec, ContentTypeId, EncodedContent } from '../index' export const ContentTypeGroupChatMemberAdded: ContentTypeId = { typeId: 'groupChatMemberAdded', - authorityId: 'pat.xmtp.com', + authorityId: 'xmtp.org', versionMajor: 1, versionMinor: 0, sameAs(id) { diff --git a/src/codecs/GroupChatMemberNicknameChanged.ts b/src/codecs/GroupChatMemberNicknameChanged.ts index 830434084..d91ffc180 100644 --- a/src/codecs/GroupChatMemberNicknameChanged.ts +++ b/src/codecs/GroupChatMemberNicknameChanged.ts @@ -2,7 +2,7 @@ import { ContentCodec, ContentTypeId, EncodedContent } from '../index' export const ContentTypeGroupChatMemberNicknameChanged: ContentTypeId = { typeId: 'groupChatMemberNicknameChanged', - authorityId: 'pat.xmtp.com', + authorityId: 'xmtp.org', versionMajor: 1, versionMinor: 0, sameAs(id) { diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index f2f2f837d..e679dad29 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -2,7 +2,7 @@ import { ContentCodec, ContentTypeId, EncodedContent } from '../index' export const ContentTypeGroupChatTitleChanged: ContentTypeId = { typeId: 'groupChatTitleChanged', - authorityId: 'pat.xmtp.com', + authorityId: 'xmtp.org', versionMajor: 1, versionMinor: 0, sameAs(id) { From 0805413b0ec81ca456c1fa83b578ad327c0a2768 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 19:57:53 -0700 Subject: [PATCH 018/137] remove unnecessary wrapper around newGroupConversation --- src/conversations/GroupChat.ts | 9 --------- test/conversations/GroupChat.test.ts | 14 +++++++------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts index 7b7c0dab6..ebdb66a5a 100644 --- a/src/conversations/GroupChat.ts +++ b/src/conversations/GroupChat.ts @@ -162,13 +162,4 @@ export class GroupChat { const conversation = GroupConversation.from(this.conversation, this.members) await conversation.addMember(newMemberAddress) } - - static async start( - creatorClient: Client, - initialMembers: string[] - ): Promise { - return await creatorClient.conversations.newGroupConversation( - initialMembers - ) - } } diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts index 4c9460860..8ad05d8af 100644 --- a/test/conversations/GroupChat.test.ts +++ b/test/conversations/GroupChat.test.ts @@ -55,7 +55,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -79,7 +79,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -121,7 +121,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -156,7 +156,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -191,7 +191,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -221,7 +221,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) @@ -247,7 +247,7 @@ describe('GroupChat', () => { GroupChat.registerCodecs(bob) GroupChat.registerCodecs(charlie) - const aliceConversation = await GroupChat.start(alice, [ + const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, charlie.address, ]) From 2fc86b9b2fc6b85908008d96353f4089135de323 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 24 May 2023 20:47:57 -0700 Subject: [PATCH 019/137] punt on nicknames --- src/codecs/GroupChatMemberNicknameChanged.ts | 40 ---------------- src/conversations/GroupChat.ts | 49 +------------------- src/index.ts | 4 -- test/conversations/GroupChat.test.ts | 46 ++---------------- 4 files changed, 7 insertions(+), 132 deletions(-) delete mode 100644 src/codecs/GroupChatMemberNicknameChanged.ts diff --git a/src/codecs/GroupChatMemberNicknameChanged.ts b/src/codecs/GroupChatMemberNicknameChanged.ts deleted file mode 100644 index d91ffc180..000000000 --- a/src/codecs/GroupChatMemberNicknameChanged.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ContentCodec, ContentTypeId, EncodedContent } from '../index' - -export const ContentTypeGroupChatMemberNicknameChanged: ContentTypeId = { - typeId: 'groupChatMemberNicknameChanged', - authorityId: 'xmtp.org', - versionMajor: 1, - versionMinor: 0, - sameAs(id) { - return ( - this.typeId === id.typeId && - this.authorityId === id.authorityId && - this.versionMajor === id.versionMajor && - this.versionMinor === id.versionMinor - ) - }, -} - -export type GroupChatMemberNicknameChanged = { - // The new title - newNickname: string -} - -export class GroupChatMemberNicknameChangedCodec - implements ContentCodec -{ - contentType = ContentTypeGroupChatMemberNicknameChanged - - encode(content: GroupChatMemberNicknameChanged): EncodedContent { - return { - type: ContentTypeGroupChatMemberNicknameChanged, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - } - } - - decode(encodedContent: EncodedContent): GroupChatMemberNicknameChanged { - const json = new TextDecoder().decode(encodedContent.content) - return JSON.parse(json) - } -} diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts index ebdb66a5a..b309daf72 100644 --- a/src/conversations/GroupChat.ts +++ b/src/conversations/GroupChat.ts @@ -14,27 +14,15 @@ import { GroupChatTitleChanged, GroupChatTitleChangedCodec, } from '../codecs/GroupChatTitleChanged' -import { - ContentTypeGroupChatMemberNicknameChanged, - GroupChatMemberNicknameChanged, - GroupChatMemberNicknameChangedCodec, -} from '../codecs/GroupChatMemberNicknameChanged' type RebuildOptions = { since: Date } export class GroupChat { - static contentTypes = [ - ContentTypeGroupChatMemberAdded, - GroupChatTitleChangedCodec, - ContentTypeGroupChatMemberNicknameChanged, - ] - static codecs = [ new GroupChatMemberAddedCodec(), new GroupChatTitleChangedCodec(), - new GroupChatMemberNicknameChangedCodec(), ] static registerCodecs(client: Client) { @@ -48,7 +36,6 @@ export class GroupChat { conversation: Conversation _members: string[] = [] _memberConversation: Conversation | undefined - _nicknames: { [member: string]: string } = {} get members(): string[] { return [...new Set(this._members)] @@ -99,38 +86,10 @@ export class GroupChat { } else if (message.contentType.sameAs(ContentTypeGroupChatTitleChanged)) { const groupChatTitleChanged = message.content as GroupChatTitleChanged this.title = groupChatTitleChanged.newTitle - } else if ( - message.contentType.sameAs(ContentTypeGroupChatMemberNicknameChanged) - ) { - const nicknameChange = message.content as GroupChatMemberNicknameChanged - this._nicknames[message.senderAddress] = nicknameChange.newNickname } } } - get memberNickname(): string { - return this._nicknames[this.memberClient.address] || '' - } - - nicknameFor(address: string): string { - return this._nicknames[address] || address - } - - async changeNickname(newNickname: string) { - const oldNickname = - this.memberNickname === '' - ? this.memberClient.address - : this.memberNickname - const nicknameChange: GroupChatMemberNicknameChanged = { - newNickname, - } - - await this.conversation.send(nicknameChange, { - contentType: ContentTypeGroupChatMemberNicknameChanged, - contentFallback: `${oldNickname} changed their nickname to ${newNickname}`, - }) - } - async changeTitle(newTitle: string) { const titleChange: GroupChatTitleChanged = { oldTitle: this.title, @@ -139,9 +98,7 @@ export class GroupChat { await this.conversation.send(titleChange, { contentType: ContentTypeGroupChatTitleChanged, - contentFallback: `${this.nicknameFor( - this.memberClient.address - )} changed the group title to ${newTitle}`, + contentFallback: `${this.memberClient.address} changed the group title to ${newTitle}`, }) } @@ -152,9 +109,7 @@ export class GroupChat { await this.conversation.send(memberAdded, { contentType: ContentTypeGroupChatMemberAdded, - contentFallback: `${this.nicknameFor( - this.memberClient.address - )} added ${newMemberAddress} to the group`, + contentFallback: `${this.memberClient.address} added ${newMemberAddress} to the group`, }) this._members.push(newMemberAddress) diff --git a/src/index.ts b/src/index.ts index 56f463767..3c7524253 100644 --- a/src/index.ts +++ b/src/index.ts @@ -85,10 +85,6 @@ export { GroupChatMemberAdded, GroupChatMemberAddedCodec, } from './codecs/GroupChatMemberAdded' -export { - GroupChatMemberNicknameChanged, - GroupChatMemberNicknameChangedCodec, -} from './codecs/GroupChatMemberNicknameChanged' export { GroupChatTitleChanged, GroupChatTitleChangedCodec, diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts index 8ad05d8af..2d93fb7c3 100644 --- a/test/conversations/GroupChat.test.ts +++ b/test/conversations/GroupChat.test.ts @@ -151,41 +151,6 @@ describe('GroupChat', () => { expect(charlieGroupChat.title).toBe('the fun group') }) - it('members can have nicknames', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const aliceGroupChat = new GroupChat(alice, aliceConversation) - expect(aliceGroupChat.title).toBe('') - - await aliceGroupChat.changeNickname('alice') - - const bobConversation = (await conversationFromTopic( - aliceConversation.topic, - bob - ))! - - const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation) - expect(bobGroupChat.nicknameFor(alice.address)).toBe('alice') - - const charlieConversation = (await conversationFromTopic( - aliceConversation.topic, - charlie - ))! - - const charlieGroupChat = await GroupChat.fromConversation( - charlie, - charlieConversation - ) - expect(charlieGroupChat.nicknameFor('alice')).toBe('alice') - }) - it('can add members', async () => { GroupChat.registerCodecs(alice) GroupChat.registerCodecs(bob) @@ -229,17 +194,17 @@ describe('GroupChat', () => { const aliceGroupChat = new GroupChat(alice, aliceConversation) expect(aliceGroupChat.title).toBe('') - await aliceGroupChat.changeNickname('alice') + await aliceGroupChat.addMember(carol.address) await aliceGroupChat.changeTitle('the fun group') const unbuiltGroupChat = new GroupChat(alice, aliceConversation) expect(unbuiltGroupChat.title).toBe('') - expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) + expect(unbuiltGroupChat.members.length).toBe(0) await unbuiltGroupChat.rebuild() expect(unbuiltGroupChat.title).toBe('the fun group') - expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe('alice') + expect(unbuiltGroupChat.members.length).toBe(4) }) it('can be rebuilt partially', async () => { @@ -255,7 +220,7 @@ describe('GroupChat', () => { const aliceGroupChat = new GroupChat(alice, aliceConversation) expect(aliceGroupChat.title).toBe('') - await aliceGroupChat.changeNickname('alice') + await aliceGroupChat.addMember(carol.address) await sleep(1000) const date = new Date() @@ -265,13 +230,12 @@ describe('GroupChat', () => { const unbuiltGroupChat = new GroupChat(alice, aliceConversation) expect(unbuiltGroupChat.title).toBe('') - expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) await unbuiltGroupChat.rebuild({ since: date }) // We should only get the second update because the first one happened before // our `since` expect(unbuiltGroupChat.title).toBe('the fun group') - expect(unbuiltGroupChat.nicknameFor(alice.address)).toBe(alice.address) + expect(unbuiltGroupChat.members.length).toBe(3) }) }) From 1bb882f5a588bb0ec9c5f72f71d0bbe1f4873c75 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 25 May 2023 09:25:59 -0700 Subject: [PATCH 020/137] fix: no need for this change --- src/conversations/Conversations.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 97d2d4593..4a445cd10 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -185,15 +185,7 @@ export default class Conversations { const out: ConversationV2[] = [] for (const response of responses) { try { - let convo = this.saveInviteResponseToConversation(response) - - const initialMembers = convo.context?.metadata.initialMembers.split(',') - - if (initialMembers && initialMembers.length > 0) { - convo = GroupConversation.from(convo, initialMembers) - } - - out.push(convo) + out.push(this.saveInviteResponseToConversation(response)) } catch (e) { console.warn('Error saving invite response to conversation: ', e) if (shouldThrow) { From 9884c6f5d6da8b848ada50e65210331e32811248 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 25 May 2023 09:26:21 -0700 Subject: [PATCH 021/137] fix: no need for this change --- src/conversations/Conversations.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index c00633649..4a445cd10 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -185,15 +185,7 @@ export default class Conversations { const out: ConversationV2[] = [] for (const response of responses) { try { - let convo = this.saveInviteResponseToConversation(response) - - const initialMembers = convo.context?.metadata.initialMembers.split(',') - - if (initialMembers && initialMembers.length > 0) { - convo = GroupConversation.from(convo, initialMembers) - } - - out.push(convo) + out.push(this.saveInviteResponseToConversation(response)) } catch (e) { console.warn('Error saving invite response to conversation: ', e) if (shouldThrow) { @@ -454,7 +446,9 @@ export default class Conversations { const context = { conversationId: `xmtp.org/groups/${groupID}`, metadata: { - initialMembers: initialMembers.join(','), + initialMembers: [this.client.address, ...new Set(initialMembers)].join( + ',' + ), }, } From 2a6229dd0a03b27533a7df0f6cc4c5ce692a1a44 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 25 May 2023 09:31:51 -0700 Subject: [PATCH 022/137] fix: crypto import --- src/conversations/Conversations.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 4a445cd10..efb056698 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -20,6 +20,7 @@ import Long from 'long' import { toSignedPublicKeyBundle } from '../keystore/utils' import { GroupConversation } from './GroupConversation' import { bytesToHex } from '../crypto/utils' +import crypto from '../crypto/crypto' const CLOCK_SKEW_OFFSET_MS = 10000 From e2503ffbaaded5252b4c7449d728b16694265961 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 25 May 2023 09:31:51 -0700 Subject: [PATCH 023/137] fix: crypto import --- src/conversations/Conversations.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 4a445cd10..efb056698 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -20,6 +20,7 @@ import Long from 'long' import { toSignedPublicKeyBundle } from '../keystore/utils' import { GroupConversation } from './GroupConversation' import { bytesToHex } from '../crypto/utils' +import crypto from '../crypto/crypto' const CLOCK_SKEW_OFFSET_MS = 10000 From 690349583104d14399dc024fbf90c44fe2b771bb Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 10:40:29 -0700 Subject: [PATCH 024/137] feat: introduce dedicated group chat invitation topic --- src/Client.ts | 22 ++++++++++++ src/conversations/Conversations.ts | 45 +++++++++++++++++++++--- src/keystore/InMemoryKeystore.ts | 13 +++++++ src/keystore/interfaces.ts | 6 ++++ src/utils/topic.ts | 4 +++ test/conversations/Conversations.test.ts | 6 ++-- test/conversations/GroupChat.test.ts | 36 +++++++++---------- 7 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index ebd6de1aa..a80787b38 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -5,6 +5,7 @@ import { mapPaginatedStream, EnvelopeMapper, buildUserInviteTopic, + buildUserGroupInviteTopic, } from './utils' import { utils } from 'ethers' import { Signer } from './types/Signer' @@ -27,6 +28,7 @@ import { NetworkKeystoreProvider, StaticKeystoreProvider, } from './keystore/providers' +import { GroupChat } from './conversations/GroupChat' const { Compression } = proto const { b64Decode } = fetcher @@ -216,6 +218,7 @@ export default class Client { // eslint-disable-next-line @typescript-eslint/no-explicit-any private _codecs: Map> private _maxContentSize: number + private _isGroupChatEnabled = false constructor( publicKeyBundle: PublicKeyBundle, @@ -239,6 +242,10 @@ export default class Client { this._backupClient = backupClient } + get isGroupChatEnabled(): boolean { + return this._isGroupChatEnabled + } + /** * @type {Conversations} */ @@ -325,6 +332,11 @@ export default class Client { } } + enableGroupChat() { + GroupChat.registerCodecs(this) + this._isGroupChatEnabled = true + } + // gracefully shut down the client async close(): Promise { return undefined @@ -599,6 +611,16 @@ export default class Client { ) } + listGroupInvitations( + opts?: ListMessagesOptions + ): Promise { + return this.listEnvelopes( + buildUserGroupInviteTopic(this.address), + async (env) => env, + opts + ) + } + /** * List stored messages from the specified topic. * diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index efb056698..fbaa946fe 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -9,6 +9,7 @@ import Stream from '../Stream' import Client from '../Client' import { b64Decode, + buildUserGroupInviteTopic, buildUserIntroTopic, buildUserInviteTopic, dateToNs, @@ -20,7 +21,6 @@ import Long from 'long' import { toSignedPublicKeyBundle } from '../keystore/utils' import { GroupConversation } from './GroupConversation' import { bytesToHex } from '../crypto/utils' -import crypto from '../crypto/crypto' const CLOCK_SKEW_OFFSET_MS = 10000 @@ -121,7 +121,14 @@ export default class Conversations { private async listV2Conversations(): Promise { return this.v2Mutex.runExclusive(async () => { // Get all conversations already in the KeyStore - const existing = await this.getV2ConversationsFromKeystore() + let existing = await this.getV2ConversationsFromKeystore() + + if (this.client.isGroupChatEnabled) { + existing = existing.concat( + await this.getGroupConversationsFromKeystore() + ) + } + const latestConversation = existing.reduce( (memo: ConversationV2 | undefined, curr: ConversationV2) => { if (!memo || +curr.createdAt > +memo.createdAt) { @@ -133,10 +140,16 @@ export default class Conversations { ) // Load all conversations started after the newest conversation found - const newConversations = await this.updateV2Conversations( + let newConversations = await this.updateV2Conversations( latestConversation?.createdAt ) + if (this.client.isGroupChatEnabled) { + newConversations = newConversations.concat( + await this.updateGroupConversations(latestConversation?.createdAt) + ) + } + // Create a Set of all the existing topics to ensure no duplicates are added const existingTopics = new Set(existing.map((c) => c.topic)) // Add all new conversations to the existing list @@ -171,6 +184,24 @@ export default class Conversations { return this.decodeInvites(envelopes) } + private async getGroupConversationsFromKeystore(): Promise { + return (await this.client.keystore.getGroupConversations()).map( + this.conversationReferenceToV2.bind(this) + ) + } + + // Called in listV2Conversations and in newConversation + async updateGroupConversations(startTime?: Date): Promise { + const envelopes = await this.client.listGroupInvitations({ + startTime: startTime + ? new Date(+startTime - CLOCK_SKEW_OFFSET_MS) + : undefined, + direction: SortDirection.SORT_DIRECTION_ASCENDING, + }) + + return this.decodeInvites(envelopes) + } + private async decodeInvites( envelopes: messageApi.Envelope[], shouldThrow = false @@ -484,7 +515,9 @@ export default class Conversations { } return { - contentTopic: buildUserInviteTopic(response.conversation?.peerAddress), + contentTopic: buildUserGroupInviteTopic( + response.conversation?.peerAddress + ), message: response.payload, timestamp, } @@ -498,7 +531,9 @@ export default class Conversations { // // See https://github.com/xmtp/xmtp-js/blob/829257c10947618c34a66aa3857ca3557d4b52b6/src/Invitation.ts#L148-L160 const creatorEnvelope = { ...envelopes[0] } - creatorEnvelope.contentTopic = buildUserInviteTopic(this.client.address) + creatorEnvelope.contentTopic = buildUserGroupInviteTopic( + this.client.address + ) const envelopesToPublish = [creatorEnvelope, ...envelopes] diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 04eb56d55..16efd9a66 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -486,6 +486,19 @@ export default class InMemoryKeystore implements Keystore { return convos } + async getGroupConversations(): Promise< + conversationReference.ConversationReference[] + > { + const convos = this.inviteStore.topics.map((invite) => + topicDataToConversationReference(invite) + ) + + convos.sort((a, b) => + a.createdNs.div(1_000_000).sub(b.createdNs.div(1_000_000)).toNumber() + ) + return convos + } + async getPublicKeyBundle(): Promise { return this.v1Keys.getPublicKeyBundle() } diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index a8abe4a5f..35198f632 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -68,6 +68,12 @@ export interface Keystore { * Get a list of V2 conversations */ getV2Conversations(): Promise + /** + * Get a list of group conversations + */ + getGroupConversations(): Promise< + conversationReference.ConversationReference[] + > /** * Get the `PublicKeyBundle` associated with the Keystore's private keys */ diff --git a/src/utils/topic.ts b/src/utils/topic.ts index 5290cbf51..4a985f3ee 100644 --- a/src/utils/topic.ts +++ b/src/utils/topic.ts @@ -27,6 +27,10 @@ export const buildUserIntroTopic = (walletAddr: string): string => { return buildContentTopic(`intro-${utils.getAddress(walletAddr)}`) } +export const buildUserGroupInviteTopic = (walletAddr: string): string => { + return buildContentTopic(`group-invite-${utils.getAddress(walletAddr)}`) +} + export const buildUserInviteTopic = (walletAddr: string): string => { // EIP55 normalize the address case. return buildContentTopic(`invite-${utils.getAddress(walletAddr)}`) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 9aebab174..4fa034ba1 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -378,13 +378,13 @@ describe('conversations', () => { charlie.address, ]) - let invites = await alice.listInvitations() + let invites = await alice.listGroupInvitations() expect(invites).toHaveLength(1) - invites = await charlie.listInvitations() + invites = await charlie.listGroupInvitations() expect(invites).toHaveLength(1) - invites = await bob.listInvitations() + invites = await bob.listGroupInvitations() expect(invites).toHaveLength(1) }) }) diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts index 2d93fb7c3..6cdc13c05 100644 --- a/test/conversations/GroupChat.test.ts +++ b/test/conversations/GroupChat.test.ts @@ -51,9 +51,9 @@ describe('GroupChat', () => { } it('can be started', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, @@ -75,9 +75,9 @@ describe('GroupChat', () => { }) it('lets people chat', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, @@ -117,9 +117,9 @@ describe('GroupChat', () => { }) it('can have a title', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, @@ -152,9 +152,9 @@ describe('GroupChat', () => { }) it('can add members', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, @@ -182,9 +182,9 @@ describe('GroupChat', () => { }) it('can be rebuilt', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, @@ -208,9 +208,9 @@ describe('GroupChat', () => { }) it('can be rebuilt partially', async () => { - GroupChat.registerCodecs(alice) - GroupChat.registerCodecs(bob) - GroupChat.registerCodecs(charlie) + alice.enableGroupChat() + bob.enableGroupChat() + charlie.enableGroupChat() const aliceConversation = await alice.conversations.newGroupConversation([ bob.address, From 94e9c2d1ac52abacd0a88c191e007965f63b6c71 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 10:46:34 -0700 Subject: [PATCH 025/137] fix: topic prefixes can't have dashes --- src/utils/topic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/topic.ts b/src/utils/topic.ts index 4a985f3ee..9f2c174a4 100644 --- a/src/utils/topic.ts +++ b/src/utils/topic.ts @@ -28,7 +28,7 @@ export const buildUserIntroTopic = (walletAddr: string): string => { } export const buildUserGroupInviteTopic = (walletAddr: string): string => { - return buildContentTopic(`group-invite-${utils.getAddress(walletAddr)}`) + return buildContentTopic(`groupInvite-${utils.getAddress(walletAddr)}`) } export const buildUserInviteTopic = (walletAddr: string): string => { From 786f8e65cb631ef74f4595690785ab83f7bb60f2 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 11:32:38 -0700 Subject: [PATCH 026/137] Update src/conversations/Conversations.ts Co-authored-by: Nicholas Molnar <65710+neekolas@users.noreply.github.com> --- src/conversations/Conversations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index fbaa946fe..3929211b2 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -478,7 +478,7 @@ export default class Conversations { const context = { conversationId: `xmtp.org/groups/${groupID}`, metadata: { - initialMembers: [this.client.address, ...new Set(initialMembers)].join( + initialMembers: [...new Set(initialMembers.concat(this.client.address))].join( ',' ), }, From 6a29c2d938e901c6255fd2ebbc89789b40dc78fd Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 11:59:59 -0700 Subject: [PATCH 027/137] fix: add runtime validation --- src/codecs/GroupChatMemberAdded.ts | 4 ++++ src/codecs/GroupChatTitleChanged.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts index b52f16c89..b8dbe4d20 100644 --- a/src/codecs/GroupChatMemberAdded.ts +++ b/src/codecs/GroupChatMemberAdded.ts @@ -25,6 +25,10 @@ export class GroupChatMemberAddedCodec contentType = ContentTypeGroupChatMemberAdded encode(content: GroupChatMemberAdded): EncodedContent { + if (content.member.length !== 42) { + throw new Error('Invalid member address') + } + return { type: ContentTypeGroupChatMemberAdded, parameters: {}, diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index e679dad29..19209c262 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -29,6 +29,10 @@ export class GroupChatTitleChangedCodec contentType = ContentTypeGroupChatTitleChanged encode(content: GroupChatTitleChanged): EncodedContent { + if (content.newTitle.length === 0) { + throw new Error('Invalid newTitle') + } + return { type: ContentTypeGroupChatTitleChanged, parameters: {}, From a4cd52b5b9bc447c086d741989d7885476e8e28f Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 12:00:33 -0700 Subject: [PATCH 028/137] fix: add upper bound to title --- src/codecs/GroupChatTitleChanged.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index 19209c262..99c963c93 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -29,7 +29,7 @@ export class GroupChatTitleChangedCodec contentType = ContentTypeGroupChatTitleChanged encode(content: GroupChatTitleChanged): EncodedContent { - if (content.newTitle.length === 0) { + if (content.newTitle.length === 0 || content.newTitle.length > 256) { throw new Error('Invalid newTitle') } From 8b2c3f664b2abc82dcb433d5764be50aaeef05d8 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 12:01:27 -0700 Subject: [PATCH 029/137] fix: flip order --- src/conversations/GroupChat.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts index b309daf72..bc82944cf 100644 --- a/src/conversations/GroupChat.ts +++ b/src/conversations/GroupChat.ts @@ -107,14 +107,14 @@ export class GroupChat { member: newMemberAddress, } - await this.conversation.send(memberAdded, { - contentType: ContentTypeGroupChatMemberAdded, - contentFallback: `${this.memberClient.address} added ${newMemberAddress} to the group`, - }) - this._members.push(newMemberAddress) const conversation = GroupConversation.from(this.conversation, this.members) await conversation.addMember(newMemberAddress) + + await this.conversation.send(memberAdded, { + contentType: ContentTypeGroupChatMemberAdded, + contentFallback: `${this.memberClient.address} added ${newMemberAddress} to the group`, + }) } } From 7dba17cd989da9b840821d7c2f2f8db4648ac883 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 12:02:28 -0700 Subject: [PATCH 030/137] fix: remove unnecessary property --- src/codecs/GroupChatTitleChanged.ts | 4 ---- src/conversations/GroupChat.ts | 1 - 2 files changed, 5 deletions(-) diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index 99c963c93..6452a2893 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -16,11 +16,7 @@ export const ContentTypeGroupChatTitleChanged: ContentTypeId = { } export type GroupChatTitleChanged = { - // The new title newTitle: string - - // The old title - oldTitle: string } export class GroupChatTitleChangedCodec diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts index bc82944cf..1c83ffa5e 100644 --- a/src/conversations/GroupChat.ts +++ b/src/conversations/GroupChat.ts @@ -92,7 +92,6 @@ export class GroupChat { async changeTitle(newTitle: string) { const titleChange: GroupChatTitleChanged = { - oldTitle: this.title, newTitle, } From ff2a15b4c06786e515d455655f888f8ff1e25343 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 12:08:41 -0700 Subject: [PATCH 031/137] fix: lint --- src/conversations/Conversations.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 906dc87cb..bf961f4ea 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -479,9 +479,9 @@ export default class Conversations { const context = { conversationId: `xmtp.org/groups/${groupID}`, metadata: { - initialMembers: [...new Set(initialMembers.concat(this.client.address))].join( - ',' - ), + initialMembers: [ + ...new Set(initialMembers.concat(this.client.address)), + ].join(','), }, } From 828b3dca945d5a907c45c25c85e489c703f000bb Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 17:35:34 -0700 Subject: [PATCH 032/137] fix: handle case where group chat is enabled after initial convo loading --- src/conversations/Conversations.ts | 28 +++++++---- src/keystore/InMemoryKeystore.ts | 2 +- src/keystore/InviteStore.ts | 7 +++ test/conversations/Conversations.test.ts | 59 ++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index bf961f4ea..054340739 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -122,13 +122,7 @@ export default class Conversations { private async listV2Conversations(): Promise { return this.v2Mutex.runExclusive(async () => { // Get all conversations already in the KeyStore - let existing = await this.getV2ConversationsFromKeystore() - - if (this.client.isGroupChatEnabled) { - existing = existing.concat( - await this.getGroupConversationsFromKeystore() - ) - } + const existing = await this.getV2ConversationsFromKeystore() const latestConversation = existing.reduce( (memo: ConversationV2 | undefined, curr: ConversationV2) => { @@ -146,8 +140,22 @@ export default class Conversations { ) if (this.client.isGroupChatEnabled) { + const groupConversations = + await this.getGroupConversationsFromKeystore() + const latestGroupConversation = groupConversations.reduce( + (memo: ConversationV2 | undefined, curr: ConversationV2) => { + if (!memo || +curr.createdAt > +memo.createdAt) { + return curr + } + return memo + }, + undefined + ) + newConversations = newConversations.concat( - await this.updateGroupConversations(latestConversation?.createdAt) + await this.updateGroupConversations( + latestGroupConversation?.createdAt + ) ) } @@ -467,6 +475,10 @@ export default class Conversations { async newGroupConversation( initialMembers: string[] ): Promise { + if (!this.client.isGroupChatEnabled) { + throw new Error('Group chat is not enabled for client') + } + initialMembers = [...new Set(initialMembers)].filter( (address) => address !== this.client.address ) diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 16efd9a66..0ef9cd404 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -489,7 +489,7 @@ export default class InMemoryKeystore implements Keystore { async getGroupConversations(): Promise< conversationReference.ConversationReference[] > { - const convos = this.inviteStore.topics.map((invite) => + const convos = this.inviteStore.groupTopics.map((invite) => topicDataToConversationReference(invite) ) diff --git a/src/keystore/InviteStore.ts b/src/keystore/InviteStore.ts index 4176ee277..09397b1cd 100644 --- a/src/keystore/InviteStore.ts +++ b/src/keystore/InviteStore.ts @@ -60,6 +60,13 @@ export default class InviteStore { }) } + get groupTopics(): TopicData[] { + return this.topics.filter( + (topic) => + topic.invitation.context?.metadata?.initialMembers !== undefined + ) + } + get topics(): TopicData[] { return [...this.topicMap.values()] } diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 4fa034ba1..7f0d98421 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -75,6 +75,63 @@ describe('conversations', () => { expect(aliceConversations3).toHaveLength(2) }) + it('loads group chats when group chat is enabled after first load', async () => { + const aliceConversations1 = await alice.conversations.list() + expect(aliceConversations1).toHaveLength(0) + alice.enableGroupChat() + + const groupConvo = await alice.conversations.newGroupConversation([ + bob.address, + ]) + await sleep(100) + const bobConversations = await bob.conversations.list() + + // Group Chat isn't enabled for this client so we're not checking the group chat + // topic. As a result this should be empty. + expect(bobConversations).toHaveLength(0) + + // Make sure bob doesn't have group chat enabled + expect(bob.isGroupChatEnabled).toBeFalsy() + // Make sure creating a group chat from a client without it enabled fails + expect( + bob.conversations.newGroupConversation([ + '0x0000000000000000000000000000000000000000', + ]) + ).rejects.toThrow('Group chat is not enabled for client') + + // Create a 1:1 convo for bob + const conversation = await bob.conversations.newConversation( + alice.address, + { + conversationId: 'foo', + metadata: {}, + } + ) + await sleep(100) + const bobConversations2 = await bob.conversations.list() + expect(bobConversations2).toHaveLength(1) + expect(bobConversations2[0].topic).toBe(conversation.topic) + + // Enable group chat for bob + bob.enableGroupChat() + + // Make sure group chat loads for bob + const bobConversations3 = await bob.conversations.list() + expect(bobConversations3).toHaveLength(2) + expect(bobConversations3[0].topic).toBe(groupConvo.topic) + + // await alice.conversations.newConversation(bob.address, { + // conversationId: 'bar', + // metadata: {}, + // }) + // await sleep(100) + // const fromKeystore = await alice.keystore.getV2Conversations() + // expect(fromKeystore[1].context?.conversationId).toBe('bar') + + // const aliceConversations3 = await alice.conversations.list() + // expect(aliceConversations3).toHaveLength(2) + }) + it('caches results and updates the latestSeen date', async () => { const cache = new ConversationCache() const convoDate = new Date() @@ -373,6 +430,8 @@ describe('conversations', () => { describe('newGroupConversation', () => { it('sends invites to recipients', async () => { + bob.enableGroupChat() + await bob.conversations.newGroupConversation([ alice.address, charlie.address, From a9409b1ab20dfed4cff0086d840921006eac6afd Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Wed, 31 May 2023 00:14:30 +0000 Subject: [PATCH 033/137] fix: topics must be ascii without this change, topics were being stored as mangled utf8 --- src/keystore/InMemoryKeystore.ts | 5 +++-- test/keystore/InMemoryKeystore.test.ts | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 0ef9cd404..92b1bb2fa 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -30,6 +30,7 @@ import LocalAuthenticator from '../authn/LocalAuthenticator' import Long from 'long' import { hmacSha256Sign } from '../crypto/ecies' import crypto from '../crypto/crypto' +import { bytesToHex } from '../crypto/utils' const { ErrorCode } = keystore // Constant, 32 byte salt @@ -290,9 +291,9 @@ export default class InMemoryKeystore implements Keystore { const msgBytes = new TextEncoder().encode(msgString) - const topic = ( + const topic = bytesToHex( await hmacSha256Sign(Buffer.from(secret), Buffer.from(msgBytes)) - ).toString() + ) const infoString = [ '0', // sequence number diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index e4e49b4e0..5ad23ce8d 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -510,6 +510,8 @@ describe('InMemoryKeystore', () => { const firstResponse: CreateInviteResponse = responses[0] const topicName = firstResponse.conversation!.topic + expect(topicName).toMatch(/^[\x00-\x7F]+$/) + expect( responses.filter((response, index, array) => { return response.conversation!.topic === topicName From 8718e990bc91b86409eef5f688b08f30268fd330 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Tue, 30 May 2023 17:37:21 -0700 Subject: [PATCH 034/137] fix: remove commented code --- test/conversations/Conversations.test.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 7f0d98421..f5e25baf3 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -119,17 +119,6 @@ describe('conversations', () => { const bobConversations3 = await bob.conversations.list() expect(bobConversations3).toHaveLength(2) expect(bobConversations3[0].topic).toBe(groupConvo.topic) - - // await alice.conversations.newConversation(bob.address, { - // conversationId: 'bar', - // metadata: {}, - // }) - // await sleep(100) - // const fromKeystore = await alice.keystore.getV2Conversations() - // expect(fromKeystore[1].context?.conversationId).toBe('bar') - - // const aliceConversations3 = await alice.conversations.list() - // expect(aliceConversations3).toHaveLength(2) }) it('caches results and updates the latestSeen date', async () => { From bde44e67518a642b17d006a70e46c784569fa890 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 1 Jun 2023 10:44:11 -0700 Subject: [PATCH 035/137] feat: add isGroup to Conversation interface --- src/conversations/Conversation.ts | 8 ++++++++ src/conversations/Conversations.ts | 25 +++++++++++++----------- src/conversations/GroupConversation.ts | 12 +++++++++++- test/conversations/Conversations.test.ts | 1 + 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 8b343f983..d88d3c7b5 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -59,6 +59,12 @@ export interface Conversation { * Timestamp the conversation was created at */ createdAt: Date + + /** + * Is this conversation a group chat + */ + isGroup: boolean + /** * Optional field containing the `conversationId` and `metadata` for V2 conversations. * Will always be undefined on V1 conversations @@ -148,6 +154,7 @@ export class ConversationV1 implements Conversation { peerAddress: string createdAt: Date context = undefined + isGroup = false private client: Client constructor(client: Client, address: string, createdAt: Date) { @@ -423,6 +430,7 @@ export class ConversationV2 implements Conversation { peerAddress: string createdAt: Date context?: InvitationContext + isGroup = false constructor( client: Client, diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 054340739..495db8aed 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -143,7 +143,7 @@ export default class Conversations { const groupConversations = await this.getGroupConversationsFromKeystore() const latestGroupConversation = groupConversations.reduce( - (memo: ConversationV2 | undefined, curr: ConversationV2) => { + (memo: GroupConversation | undefined, curr: GroupConversation) => { if (!memo || +curr.createdAt > +memo.createdAt) { return curr } @@ -193,14 +193,18 @@ export default class Conversations { return this.decodeInvites(envelopes) } - private async getGroupConversationsFromKeystore(): Promise { - return (await this.client.keystore.getGroupConversations()).map( - this.conversationReferenceToV2.bind(this) - ) + private async getGroupConversationsFromKeystore(): Promise< + GroupConversation[] + > { + return (await this.client.keystore.getGroupConversations()).map((ref) => { + return GroupConversation.from(this.conversationReferenceToV2(ref)) + }) } // Called in listV2Conversations and in newConversation - async updateGroupConversations(startTime?: Date): Promise { + async updateGroupConversations( + startTime?: Date + ): Promise { const envelopes = await this.client.listGroupInvitations({ startTime: startTime ? new Date(+startTime - CLOCK_SKEW_OFFSET_MS) @@ -208,7 +212,9 @@ export default class Conversations { direction: SortDirection.SORT_DIRECTION_ASCENDING, }) - return this.decodeInvites(envelopes) + return (await this.decodeInvites(envelopes)).map((conversation) => + GroupConversation.from(conversation) + ) } private async decodeInvites( @@ -558,10 +564,7 @@ export default class Conversations { throw new Error('no conversation for response') } - return GroupConversation.from( - this.conversationReferenceToV2(conversation), - initialMembers - ) + return GroupConversation.from(this.conversationReferenceToV2(conversation)) } /** diff --git a/src/conversations/GroupConversation.ts b/src/conversations/GroupConversation.ts index ff9da2ce6..fa7f11be5 100644 --- a/src/conversations/GroupConversation.ts +++ b/src/conversations/GroupConversation.ts @@ -11,6 +11,7 @@ export class GroupConversation extends ConversationV2 implements Conversation { topic: string createdAt: Date memberAddresses: string[] = [] + isGroup = true constructor( client: Client, @@ -31,12 +32,21 @@ export class GroupConversation extends ConversationV2 implements Conversation { static from( conversation: Conversation, - memberAddresses: string[] + members?: string[] ): GroupConversation { if (!(conversation instanceof ConversationV2)) { throw new Error('Conversation is not a V2 conversation') } + const memberAddresses = + members || + conversation.context?.metadata?.initialMembers?.split(',') || + [] + + if (memberAddresses.length === 0) { + throw new Error('Conversation has no member addresses') + } + return new GroupConversation( conversation.client, conversation.topic, diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index f5e25baf3..bb0009b06 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -119,6 +119,7 @@ describe('conversations', () => { const bobConversations3 = await bob.conversations.list() expect(bobConversations3).toHaveLength(2) expect(bobConversations3[0].topic).toBe(groupConvo.topic) + expect(bobConversations3[0].isGroup).toBe(true) }) it('caches results and updates the latestSeen date', async () => { From fa3f75374dd31f62091d60c6f0ca962a6486e75b Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 1 Jun 2023 14:38:22 -0700 Subject: [PATCH 036/137] fix: export group chat content types --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 3c7524253..45b9e31f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -84,8 +84,10 @@ export { GroupChat } from './conversations/GroupChat' export { GroupChatMemberAdded, GroupChatMemberAddedCodec, + ContentTypeGroupChatMemberAdded, } from './codecs/GroupChatMemberAdded' export { GroupChatTitleChanged, GroupChatTitleChangedCodec, + ContentTypeGroupChatTitleChanged, } from './codecs/GroupChatTitleChanged' From 1f4bfb9a4c101ebb9923d7f2574edad7754bb0a5 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 1 Jun 2023 15:02:00 -0700 Subject: [PATCH 037/137] fix: include group conversations in conversations.stream() --- src/conversations/Conversations.ts | 14 ++++++++++-- test/conversations/Conversations.test.ts | 27 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 495db8aed..5b2d7b404 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -274,6 +274,7 @@ export default class Conversations { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) + const groupInviteTopic = buildUserGroupInviteTopic(this.client.address) const newPeer = (peerAddress: string): boolean => { // Check if we have seen the peer already in this stream @@ -295,7 +296,10 @@ export default class Conversations { await msg.decrypt(this.client.keystore, this.client.publicKeyBundle) return new ConversationV1(this.client, peerAddress, msg.sent) } - if (env.contentTopic === inviteTopic) { + if ( + env.contentTopic === inviteTopic || + env.contentTopic === groupInviteTopic + ) { const results = await this.decodeInvites([env], true) if (results.length) { return results[0] @@ -304,9 +308,15 @@ export default class Conversations { throw new Error('unrecognized invite topic') } + const topics = [introTopic, inviteTopic] + + if (this.client.isGroupChatEnabled) { + topics.push(groupInviteTopic) + } + return Stream.create( this.client, - [inviteTopic, introTopic], + topics, decodeConversation.bind(this) ) } diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index bb0009b06..085dcd188 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -185,6 +185,33 @@ describe('conversations', () => { await stream.return() }) + it('streams group conversations', async () => { + alice.enableGroupChat() + bob.enableGroupChat() + + const stream = await alice.conversations.stream() + + // make sure it works with 1:1 convo + await alice.conversations.newConversation(bob.address, { + conversationId: 'foo', + metadata: {}, + }) + + const conversation = await alice.conversations.newGroupConversation([ + bob.address, + ]) + await conversation.send('hi bob') + + let numConversations = 0 + for await (const conversation of stream) { + numConversations++ + expect(conversation.peerAddress).toBe(bob.address) + if (numConversations == 2) break + } + expect(numConversations).toBe(2) + await stream.return() + }) + it('streams all conversation messages from empty state', async () => { const aliceCharlie = await alice.conversations.newConversation( charlie.address From 23c96b682390884ffc1fb1f9c9807eb00db61990 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 1 Jun 2023 15:36:57 -0700 Subject: [PATCH 038/137] fix: stream group chat messages in streamAllMessages --- src/conversations/Conversations.ts | 7 ++++++ test/conversations/Conversations.test.ts | 32 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 5b2d7b404..08868924e 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -331,7 +331,14 @@ export default class Conversations { async streamAllMessages(): Promise> { const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) + const groupInviteTopic = buildUserGroupInviteTopic(this.client.address) + const topics = new Set([introTopic, inviteTopic]) + + if (this.client.isGroupChatEnabled) { + topics.add(groupInviteTopic) + } + const convoMap = new Map() for (const conversation of await this.list()) { diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 085dcd188..7ac047bfa 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -287,6 +287,38 @@ describe('conversations', () => { await stream.return(undefined) }) + it('streams all conversation messages from group conversations', async () => { + alice.enableGroupChat() + charlie.enableGroupChat() + + const aliceCharlie = await alice.conversations.newGroupConversation([ + charlie.address, + ]) + const bobAlice = await bob.conversations.newConversation(alice.address) + + const stream = await alice.conversations.streamAllMessages() + await aliceCharlie.send('gm alice -charlie') + + let numMessages = 0 + for await (const message of stream) { + numMessages++ + if (numMessages == 1) { + expect(message.content).toBe('gm alice -charlie') + await bobAlice.send('gm alice -bob') + } + if (numMessages == 2) { + expect(message.content).toBe('gm alice -bob') + await aliceCharlie.send('gm charlie -alice') + } + if (numMessages == 3) { + expect(message.content).toBe('gm charlie -alice') + break + } + } + expect(numMessages).toBe(3) + await stream.return(undefined) + }) + it('dedupes conversations when multiple messages are in the introduction topic', async () => { const aliceConversation = await alice.conversations.newConversation( bob.address From 2063235f5b660851bef7cdc55df9332f33c7e64a Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 15 Jun 2023 16:46:21 -0700 Subject: [PATCH 039/137] fix: use proper contenttypeid definition for group chat types --- src/codecs/GroupChatMemberAdded.ts | 12 ++---------- src/codecs/GroupChatTitleChanged.ts | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts index b8dbe4d20..89ff82d19 100644 --- a/src/codecs/GroupChatMemberAdded.ts +++ b/src/codecs/GroupChatMemberAdded.ts @@ -1,19 +1,11 @@ import { ContentCodec, ContentTypeId, EncodedContent } from '../index' -export const ContentTypeGroupChatMemberAdded: ContentTypeId = { +export const ContentTypeGroupChatMemberAdded = new ContentTypeId({ typeId: 'groupChatMemberAdded', authorityId: 'xmtp.org', versionMajor: 1, versionMinor: 0, - sameAs(id) { - return ( - this.typeId === id.typeId && - this.authorityId === id.authorityId && - this.versionMajor === id.versionMajor && - this.versionMinor === id.versionMinor - ) - }, -} +}) export type GroupChatMemberAdded = { member: string diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index 6452a2893..1812406b4 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -1,19 +1,11 @@ import { ContentCodec, ContentTypeId, EncodedContent } from '../index' -export const ContentTypeGroupChatTitleChanged: ContentTypeId = { +export const ContentTypeGroupChatTitleChanged = new ContentTypeId({ typeId: 'groupChatTitleChanged', authorityId: 'xmtp.org', versionMajor: 1, versionMinor: 0, - sameAs(id) { - return ( - this.typeId === id.typeId && - this.authorityId === id.authorityId && - this.versionMajor === id.versionMajor && - this.versionMinor === id.versionMinor - ) - }, -} +}) export type GroupChatTitleChanged = { newTitle: string From e96a54f4fc2cb73d791978936264f69f6dc87d65 Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 15 Jun 2023 16:51:19 -0700 Subject: [PATCH 040/137] fix: group conversations coming from stream should be marked isGroup --- src/conversations/Conversations.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 495db8aed..881a83278 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -274,6 +274,7 @@ export default class Conversations { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) + const groupInviteTopic = buildUserGroupInviteTopic(this.client.address) const newPeer = (peerAddress: string): boolean => { // Check if we have seen the peer already in this stream @@ -301,12 +302,26 @@ export default class Conversations { return results[0] } } + if (env.contentTopic === groupInviteTopic) { + const results = await this.decodeInvites([env], true) + if (results.length) { + const result = results[0] + result.isGroup = true + return result + } + } throw new Error('unrecognized invite topic') } + const topics = [introTopic, inviteTopic] + + if (this.client.isGroupChatEnabled) { + topics.push(groupInviteTopic) + } + return Stream.create( this.client, - [inviteTopic, introTopic], + topics, decodeConversation.bind(this) ) } From 127694ad09b0a9c6b0a5e9c18eeb64d6a86c8fbb Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Thu, 15 Jun 2023 17:04:21 -0700 Subject: [PATCH 041/137] fix: imports --- src/codecs/GroupChatMemberAdded.ts | 2 +- src/codecs/GroupChatTitleChanged.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts index 89ff82d19..758faf89e 100644 --- a/src/codecs/GroupChatMemberAdded.ts +++ b/src/codecs/GroupChatMemberAdded.ts @@ -1,4 +1,4 @@ -import { ContentCodec, ContentTypeId, EncodedContent } from '../index' +import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' export const ContentTypeGroupChatMemberAdded = new ContentTypeId({ typeId: 'groupChatMemberAdded', diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts index 1812406b4..a4baa68ff 100644 --- a/src/codecs/GroupChatTitleChanged.ts +++ b/src/codecs/GroupChatTitleChanged.ts @@ -1,4 +1,4 @@ -import { ContentCodec, ContentTypeId, EncodedContent } from '../index' +import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' export const ContentTypeGroupChatTitleChanged = new ContentTypeId({ typeId: 'groupChatTitleChanged', From 87f9636b98dcbbf60f32c7938461768e43409d2a Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Mon, 26 Jun 2023 12:09:12 -0700 Subject: [PATCH 042/137] docs: update README for group chat (#388) * docs: update README for group chat * docs: copyedits * docs: a few more edits * docs: update status --------- Co-authored-by: Jennifer Hasegawa <5481259+jhaaaa@users.noreply.github.com> --- README.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/README.md b/README.md index 3f1fb420b..b7732ad3d 100644 --- a/README.md +++ b/README.md @@ -438,6 +438,129 @@ const clientWithNoCache = await Client.create(wallet, { }) ``` +## Group chat + +![Status](https://img.shields.io/badge/Feature_Status-Alpha-red) + +> **Important:** +> This feature is in **alpha** status and ready for you to start experimenting with. We do **not** recommend using alpha features in production apps. Software in this status will change as we iterate based on feedback. + +Use the information in this section to **experiment** with providing group chat in your app. + +This section refers to both `GroupConversation` and `GroupChat`: + +- `GroupConversation` is similar to `ConversationV1` or `ConversationV2` provided by the SDK. These conversations are just a way to send and receive messages. +- `GroupChat` is a wrapper around `GroupConversation` that knows about things like group chat titles, keeping the group chat member list in sync, and basically handling any richer features beyond just sending and receiving messages. + +### Enable group chat for your Client + +The first step is to enable group chat for your Client: + +```ts +const creatorClient = await Client.create(yourSigner) +creatorClient.enableGroupChat() +``` + +This enables the following capabilities required for group chat: + +- The client will be able to create group chats +- Group chats will be present in `client.conversations.list()` +- The client will understand group chat codecs such as `GroupChatMemberAdded` and `GroupChatTitleChanged` + +### Create a group chat + +Enable a user to create a group chat using `newGroupConversation` and adding member addresses to it: + +```ts +const memberAddresses = [ + '0x194c31cAe1418D5256E8c58e0d08Aee1046C6Ed0', + '0x937C0d4a6294cdfa575de17382c7076b579DC176', +] +const groupConversation = + creatorClient.conversations.newGroupConversation(memberAddresses) +``` + +Assuming the other members of the group chat have clients with group chat enabled, they'll see the group chat in their conversation list. + +### Send a message to a group chat + +Enable a user to send a message to a group chat the same way you send messages to a 1:1 conversation: + +```ts +await groupConversation.send('hello everyone') +``` + +### Load group chats + +When you enabled group chat for your Client, you enabled group chats to be returned in `conversations.list()`: + +```ts +const conversations = await creatorClient.conversations.list() +const conversation = conversations[0] + +console.log(conversation.isGroup) // => true when it's a group conversation +``` + +### Enable a member to change the group chat title + +Enable a member of a group chat to change the group chat title by sending a message with the `GroupChatTitleChanged` content type: + +```ts +import { ContentTypeGroupChatTitleChanged } from '@xmtp/xmtp-js' +import type { GroupChatTitleChanged } from '@xmtp/xmtp-js' + +const +``` + +### Manage group state with the `GroupChat` class + +Use the `GroupChat` class to keep track of group state, such as the group chat title and member list: + +```ts +const conversations = await creatorClient.conversations.list() +const conversation = conversations[0] // assume this conversation is a group conversation + +const groupChat = new GroupChat(creatorClient, conversation) +``` + +You can also use the `GroupChat` class to change the group chat title and member list. + +#### Change a group chat title + +To change a group chat title, call `changeTitle` on a `GroupChat` instance: + +```ts +await groupChat.changeTitle('The fun group') +``` + +This sends a message with the `GroupChatTitleChanged` content type to the group chat that clients can display. Clients can also use the message to update the group chat title on their end. + +#### Add a group chat member + +To add a group chat member, call `addMember` on a `GroupChat` instance: + +```ts +await groupChat.addMember('0x194c31cAe1418D5256E8c58e0d08Aee1046C6Ed0') +``` + +This sends an invitation to the recipient address. It also sends a `GroupChatMemberAdded` message to the group chat that clients can display and use to update their group chat member lists. + +#### Rebuild the group state + +To rebuild the group state by replaying all messages in a group chat, call `rebuild()` on an instance of `GroupChat`: + +```ts +const rebuiltAt = new Date() +await groupChat.rebuild() + +// You can pass a date to rebuild to only rebuild state since that time +await groupChat.rebuild({ since: rebuiltAt }) +``` + +For example, you'd do this the first time you load the group chat to make sure everything is up to date. + +Group state update messages, like `GroupChatTitleChanged` and `GroupChatMemberAdded`, are sent alongside the actual messages sent by group members. This means that to load the current group state, you must traverse the entire group chat history at least once. This is one of the reasons why persisting messages locally is a performance best practice. + ## 🏗 Breaking revisions Because `xmtp-js` is in active development, you should expect breaking revisions that might require you to adopt the latest SDK release to enable your app to continue working as expected. From b087b044b888b0e67032dff3450071e438f5d1d6 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 28 Jun 2023 11:49:51 +0200 Subject: [PATCH 043/137] feat: initial snap provider --- package-lock.json | 190 +++++++++++++++++++++++++ package.json | 1 + src/index.ts | 2 + src/keystore/SnapKeystore.ts | 134 +++++++++++++++++ src/keystore/index.ts | 1 + src/keystore/providers/SnapProvider.ts | 88 ++++++++++++ src/types/metamask.ts | 12 ++ 7 files changed, 428 insertions(+) create mode 100644 src/keystore/SnapKeystore.ts create mode 100644 src/keystore/providers/SnapProvider.ts create mode 100644 src/types/metamask.ts diff --git a/package-lock.json b/package-lock.json index b5ae0ddc4..09bf30ad9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "devDependencies": { "@commitlint/cli": "^16.1.0", "@commitlint/config-conventional": "^16.0.0", + "@metamask/providers": "^11.1.0", "@types/benchmark": "^2.1.2", "@types/bl": "^5.0.2", "@types/callback-to-async-iterator": "^1.1.4", @@ -2361,6 +2362,81 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "node_modules/@metamask/object-multiplex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz", + "integrity": "sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "readable-stream": "^2.3.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@metamask/providers": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.0.tgz", + "integrity": "sha512-ujlClbsa1LbjYmGAK2bwN+7TbQr8mjLASAWR8xRDIiTK+vmCux+5afuVnXvK+fMZfA3GbAaI3Rkq9KFwNMYt+g==", + "dev": true, + "dependencies": { + "@metamask/object-multiplex": "^1.1.0", + "@metamask/safe-event-emitter": "^3.0.0", + "detect-browser": "^5.2.0", + "eth-rpc-errors": "^4.0.2", + "extension-port-stream": "^2.0.1", + "fast-deep-equal": "^2.0.1", + "is-stream": "^2.0.0", + "json-rpc-engine": "^6.1.0", + "json-rpc-middleware-stream": "^4.2.1", + "pump": "^3.0.0", + "webextension-polyfill": "^0.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/providers/node_modules/fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", + "dev": true + }, + "node_modules/@metamask/safe-event-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz", + "integrity": "sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@noble/secp256k1": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.2.tgz", @@ -4673,6 +4749,12 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "dev": true + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -4840,6 +4922,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/env-ci": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.5.0.tgz", @@ -5765,6 +5856,15 @@ "node": ">=0.10.0" } }, + "node_modules/eth-rpc-errors": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", + "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "dev": true, + "dependencies": { + "fast-safe-stringify": "^2.0.6" + } + }, "node_modules/ethers": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.3.tgz", @@ -5860,6 +5960,18 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/extension-port-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-2.1.1.tgz", + "integrity": "sha512-qknp5o5rj2J9CRKfVB8KJr+uXQlrojNZzdESUPhKYLXf97TPcGf6qWWKmpsNNtUyOdzFhab1ON0jzouNxHHvow==", + "dev": true, + "dependencies": { + "webextension-polyfill": ">=0.10.0 <1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5900,6 +6012,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -8066,6 +8184,62 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-rpc-engine": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", + "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", + "dev": true, + "dependencies": { + "@metamask/safe-event-emitter": "^2.0.0", + "eth-rpc-errors": "^4.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", + "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", + "dev": true + }, + "node_modules/json-rpc-middleware-stream": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/json-rpc-middleware-stream/-/json-rpc-middleware-stream-4.2.2.tgz", + "integrity": "sha512-tmTQCI/R8wKMTWB50xlzkyh90JR5VuKiDVlWlmG7DjeKfdDtbLL/4vYCRlG5HnSSKkhrkVPI0TrHQz1Dethl7A==", + "dev": true, + "dependencies": { + "@metamask/safe-event-emitter": "^3.0.0", + "readable-stream": "^2.3.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/json-rpc-middleware-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/json-rpc-middleware-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -12067,6 +12241,16 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -13976,6 +14160,12 @@ "makeerror": "1.0.12" } }, + "node_modules/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", + "dev": true + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 738c66a3f..4de8650a9 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "devDependencies": { "@commitlint/cli": "^16.1.0", "@commitlint/config-conventional": "^16.0.0", + "@metamask/providers": "^11.1.0", "@types/benchmark": "^2.1.2", "@types/bl": "^5.0.2", "@types/callback-to-async-iterator": "^1.1.4", diff --git a/src/index.ts b/src/index.ts index 45b9e31f6..0dd637a96 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,8 @@ export { SignedPublicKeyBundle, PrivateKey, PrivateKeyBundle, + PrivateKeyBundleV1, + PrivateKeyBundleV2, Signature, encrypt, decrypt, diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts new file mode 100644 index 000000000..e561dfe03 --- /dev/null +++ b/src/keystore/SnapKeystore.ts @@ -0,0 +1,134 @@ +import { Keystore } from './interfaces' +import { + fetcher, + conversationReference, + keystore, + authn, + publicKey, + signature, +} from '@xmtp/proto' +import { Reader, Writer } from 'protobufjs/minimal' +const { b64Encode, b64Decode } = fetcher +const ethereum = window.ethereum + +type Codec = { + decode(input: Reader | Uint8Array, length?: number): T + encode(message: T, writer?: Writer): Writer +} +type ApiDefs = { + [k: string]: { + req: Codec | null + res: Codec + } +} + +export const defaultSnapOrigin = `local:http://localhost:8080` + +export const apiDefs: ApiDefs = { + decryptV1: { + req: keystore.DecryptV1Request, + res: keystore.DecryptResponse, + }, + encryptV1: { + req: keystore.EncryptV1Request, + res: keystore.EncryptResponse, + }, + encryptV2: { + req: keystore.EncryptV2Request, + res: keystore.EncryptResponse, + }, + decryptV2: { + req: keystore.DecryptV2Request, + res: keystore.DecryptResponse, + }, + saveInvites: { + req: keystore.SaveInvitesRequest, + res: keystore.SaveInvitesResponse, + }, + createInvite: { + req: keystore.CreateInviteRequest, + res: keystore.CreateInviteResponse, + }, + createAuthToken: { + req: keystore.CreateAuthTokenRequest, + res: authn.Token, + }, + signDigest: { + req: keystore.SignDigestRequest, + res: signature.Signature, + }, + getPublicKeyBundle: { + req: null, + res: publicKey.PublicKeyBundle, + }, +} as const + +export function SnapKeystore(): Keystore { + const generatedMethods: any = {} + + for (const [method, apiDef] of Object.entries(apiDefs)) { + generatedMethods[method] = async (req: any) => { + if (!apiDef.req) { + return getResponse(method as keyof Keystore, null, apiDef.res) + } + + const reqBytes = apiDef.req.encode(req).finish() + return getResponse(method as keyof Keystore, reqBytes, apiDef.res) + } + } + + return { + ...generatedMethods, + async getV2Conversations() { + const rawResponse = await ethereumRequest('getV2Conversations', null) + if (Array.isArray(rawResponse)) { + return rawResponse.map((r) => + conversationReference.ConversationReference.decode( + fetcher.b64Decode(r) + ) + ) + } + }, + async getAccountAddress() { + const rawResponse = await ethereumRequest('getAccountAddress', null) + if (Array.isArray(rawResponse)) { + throw new Error('Unexpected array response') + } + return rawResponse + }, + } +} + +async function ethereumRequest( + method: T, + req: Uint8Array | null +): Promise { + const response = await ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: defaultSnapOrigin, + request: { + method, + params: { req: req ? b64Encode(req, 0, req.length) : null }, + }, + }, + }) + + if (!response || typeof response !== 'object') { + throw new Error('No response value') + } + + return (response as any).res as unknown as string | string[] +} + +async function getResponse( + method: T, + req: Uint8Array | null, + resDecoder: typeof apiDefs[T]['res'] +): Promise { + const responseString = await ethereumRequest(method, req) + if (Array.isArray(responseString)) { + throw new Error('Unexpected array response') + } + return resDecoder.decode(b64Decode(responseString)) +} diff --git a/src/keystore/index.ts b/src/keystore/index.ts index 8d26f995e..6219fa15a 100644 --- a/src/keystore/index.ts +++ b/src/keystore/index.ts @@ -1,5 +1,6 @@ export { default as InMemoryKeystore } from './InMemoryKeystore' export { default as InviteStore } from './InviteStore' +export { SnapKeystore } from './SnapKeystore' export * from './encryption' export * from './errors' export * from './interfaces' diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts new file mode 100644 index 000000000..2476e0bd3 --- /dev/null +++ b/src/keystore/providers/SnapProvider.ts @@ -0,0 +1,88 @@ +import { KeystoreProviderUnavailableError } from './errors' +import { Keystore } from '../interfaces' +import { KeystoreProvider, KeystoreProviderOptions } from './interfaces' +import { defaultSnapOrigin, SnapKeystore } from '../SnapKeystore' + +export type Snap = { + permissionName: string + id: string + version: string + initialPermissions: Record +} + +export type GetSnapsResponse = Record + +const isFlask = async () => { + const provider = window.ethereum + + try { + const clientVersion = await provider?.request({ + method: 'web3_clientVersion', + }) + + const isFlaskDetected = (clientVersion as string[])?.includes('flask') + + return Boolean(provider && isFlaskDetected) + } catch { + return false + } +} + +const getSnaps = async (): Promise => { + return (await window.ethereum.request({ + method: 'wallet_getSnaps', + })) as unknown as GetSnapsResponse +} + +const getSnap = async (version?: string): Promise => { + try { + const snaps = await getSnaps() + + return Object.values(snaps).find( + (snap) => + snap.id === defaultSnapOrigin && (!version || snap.version === version) + ) + } catch (e) { + console.warn('Failed to obtain installed snap', e) + return undefined + } +} + +const initSnap = async () => { + await window.ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: defaultSnapOrigin, + request: { + method: 'init', + }, + }, + }) +} + +const connectSnap = async ( + snapId: string = defaultSnapOrigin, + params: Record<'version' | string, unknown> = {} +) => { + await window.ethereum.request({ + method: 'wallet_requestSnaps', + params: { + [snapId]: params, + }, + }) +} + +export default class SnapKeystoreProvider implements KeystoreProvider { + async newKeystore(opts: KeystoreProviderOptions): Promise { + if (!isFlask()) { + throw new KeystoreProviderUnavailableError('Flask not detected') + } + const hasSnap = await getSnap() + if (!hasSnap) { + await connectSnap() + } + await initSnap() + + return SnapKeystore() + } +} diff --git a/src/types/metamask.ts b/src/types/metamask.ts new file mode 100644 index 000000000..911d2ffac --- /dev/null +++ b/src/types/metamask.ts @@ -0,0 +1,12 @@ +/* eslint-disable*/ + +import { MetaMaskInpageProvider } from '@metamask/providers' +/* + * Window type extension to support ethereum + */ + +declare global { + interface Window { + ethereum: MetaMaskInpageProvider + } +} From dbbe5799d9aa7f054b1044e519a79837e3e656d5 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 29 Jun 2023 16:02:51 +0200 Subject: [PATCH 044/137] feat: update keystore provider --- package-lock.json | 112 ++++++++++----------- src/keystore/SnapKeystore.ts | 66 ++++--------- src/keystore/providers/SnapProvider.ts | 90 ++++------------- src/keystore/providers/index.ts | 1 + src/keystore/snapHelpers.ts | 132 +++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 174 deletions(-) create mode 100644 src/keystore/snapHelpers.ts diff --git a/package-lock.json b/package-lock.json index 09bf30ad9..f032a7d33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -295,9 +295,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -2438,9 +2438,9 @@ } }, "node_modules/@noble/secp256k1": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.2.tgz", - "integrity": "sha512-5mzA40W2q55VCRuC9XzmkiEnODdY0c5a7qsK2QcOfI5/MuVQyBaWGQyE6YOEF7kDwp+tDVWGsCDVJUME+wsWWw==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", "funding": [ { "type": "individual", @@ -2612,48 +2612,6 @@ "node": ">=0.10.0" } }, - "node_modules/@octokit/request/node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/@octokit/request/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/@octokit/request/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/@octokit/request/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/@octokit/rest": { "version": "18.12.0", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", @@ -6738,9 +6696,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { "agent-base": "6", @@ -9008,6 +8966,48 @@ "lodash": "^4.17.21" } }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-gyp-build": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", @@ -11913,13 +11913,13 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.0.tgz", + "integrity": "sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g==", "dev": true, "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index e561dfe03..b024b9e7b 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -8,21 +8,28 @@ import { signature, } from '@xmtp/proto' import { Reader, Writer } from 'protobufjs/minimal' -const { b64Encode, b64Decode } = fetcher -const ethereum = window.ethereum +import { snapRPC, snapRequest } from './snapHelpers' type Codec = { decode(input: Reader | Uint8Array, length?: number): T encode(message: T, writer?: Writer): Writer } + +export type SnapRPC = { + req: Codec | null + res: Codec +} + type ApiDefs = { - [k: string]: { - req: Codec | null - res: Codec - } + [k: string]: SnapRPC } -export const defaultSnapOrigin = `local:http://localhost:8080` +async function getResponse( + method: T, + req: Uint8Array | null +): Promise { + return snapRPC(method, apiDefs[method], req) +} export const apiDefs: ApiDefs = { decryptV1: { @@ -64,23 +71,24 @@ export const apiDefs: ApiDefs = { } as const export function SnapKeystore(): Keystore { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const generatedMethods: any = {} for (const [method, apiDef] of Object.entries(apiDefs)) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any generatedMethods[method] = async (req: any) => { if (!apiDef.req) { - return getResponse(method as keyof Keystore, null, apiDef.res) + return getResponse(method as keyof Keystore, null) } - const reqBytes = apiDef.req.encode(req).finish() - return getResponse(method as keyof Keystore, reqBytes, apiDef.res) + return getResponse(method as keyof Keystore, req) } } return { ...generatedMethods, async getV2Conversations() { - const rawResponse = await ethereumRequest('getV2Conversations', null) + const rawResponse = await snapRequest('getV2Conversations', null) if (Array.isArray(rawResponse)) { return rawResponse.map((r) => conversationReference.ConversationReference.decode( @@ -90,7 +98,7 @@ export function SnapKeystore(): Keystore { } }, async getAccountAddress() { - const rawResponse = await ethereumRequest('getAccountAddress', null) + const rawResponse = await snapRequest('getAccountAddress', null) if (Array.isArray(rawResponse)) { throw new Error('Unexpected array response') } @@ -98,37 +106,3 @@ export function SnapKeystore(): Keystore { }, } } - -async function ethereumRequest( - method: T, - req: Uint8Array | null -): Promise { - const response = await ethereum.request({ - method: 'wallet_invokeSnap', - params: { - snapId: defaultSnapOrigin, - request: { - method, - params: { req: req ? b64Encode(req, 0, req.length) : null }, - }, - }, - }) - - if (!response || typeof response !== 'object') { - throw new Error('No response value') - } - - return (response as any).res as unknown as string | string[] -} - -async function getResponse( - method: T, - req: Uint8Array | null, - resDecoder: typeof apiDefs[T]['res'] -): Promise { - const responseString = await ethereumRequest(method, req) - if (Array.isArray(responseString)) { - throw new Error('Unexpected array response') - } - return resDecoder.decode(b64Decode(responseString)) -} diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 2476e0bd3..36592d62d 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -1,79 +1,18 @@ import { KeystoreProviderUnavailableError } from './errors' import { Keystore } from '../interfaces' import { KeystoreProvider, KeystoreProviderOptions } from './interfaces' -import { defaultSnapOrigin, SnapKeystore } from '../SnapKeystore' - -export type Snap = { - permissionName: string - id: string - version: string - initialPermissions: Record -} - -export type GetSnapsResponse = Record - -const isFlask = async () => { - const provider = window.ethereum - - try { - const clientVersion = await provider?.request({ - method: 'web3_clientVersion', - }) - - const isFlaskDetected = (clientVersion as string[])?.includes('flask') - - return Boolean(provider && isFlaskDetected) - } catch { - return false - } -} - -const getSnaps = async (): Promise => { - return (await window.ethereum.request({ - method: 'wallet_getSnaps', - })) as unknown as GetSnapsResponse -} - -const getSnap = async (version?: string): Promise => { - try { - const snaps = await getSnaps() - - return Object.values(snaps).find( - (snap) => - snap.id === defaultSnapOrigin && (!version || snap.version === version) - ) - } catch (e) { - console.warn('Failed to obtain installed snap', e) - return undefined - } -} - -const initSnap = async () => { - await window.ethereum.request({ - method: 'wallet_invokeSnap', - params: { - snapId: defaultSnapOrigin, - request: { - method: 'init', - }, - }, - }) -} - -const connectSnap = async ( - snapId: string = defaultSnapOrigin, - params: Record<'version' | string, unknown> = {} -) => { - await window.ethereum.request({ - method: 'wallet_requestSnaps', - params: { - [snapId]: params, - }, - }) -} +import { SnapKeystore } from '../SnapKeystore' +import { connectSnap, getSnap, getWalletStatus, isFlask } from '../snapHelpers' +import { GetKeystoreStatusResponse_KeystoreStatus as KeystoreStatus } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' +import { Signer } from '../../types/Signer' +import ApiClient from '../../ApiClient' export default class SnapKeystoreProvider implements KeystoreProvider { - async newKeystore(opts: KeystoreProviderOptions): Promise { + async newKeystore( + opts: KeystoreProviderOptions, + apiClient: ApiClient, + wallet: Signer + ): Promise { if (!isFlask()) { throw new KeystoreProviderUnavailableError('Flask not detected') } @@ -81,8 +20,15 @@ export default class SnapKeystoreProvider implements KeystoreProvider { if (!hasSnap) { await connectSnap() } - await initSnap() + await initSnap(wallet) return SnapKeystore() } } + +async function initSnap(wallet: Signer) { + const status = await getWalletStatus(await wallet.getAddress()) + if (status === KeystoreStatus.KEYSTORE_STATUS_UNINITIALIZED) { + const bundle = await getBundle(wallet) + } +} diff --git a/src/keystore/providers/index.ts b/src/keystore/providers/index.ts index b81275548..4ca535171 100644 --- a/src/keystore/providers/index.ts +++ b/src/keystore/providers/index.ts @@ -3,3 +3,4 @@ export * from './interfaces' export { default as KeyGeneratorKeystoreProvider } from './KeyGeneratorKeystoreProvider' export { default as NetworkKeystoreProvider } from './NetworkKeystoreProvider' export { default as StaticKeystoreProvider } from './StaticKeystoreProvider' +export { default as SnapProvider } from './SnapProvider' diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts new file mode 100644 index 000000000..1a4270e5c --- /dev/null +++ b/src/keystore/snapHelpers.ts @@ -0,0 +1,132 @@ +import { fetcher, keystore as keystoreProto } from '@xmtp/proto' +import type { SnapRPC } from './SnapKeystore' +import { b64Decode } from '../utils/bytes' +const { + GetKeystoreStatusRequest, + GetKeystoreStatusResponse, + GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, +} = keystoreProto + +const { b64Encode } = fetcher + +const ethereum = window.ethereum +// TODO: Replace with npm package once released +export const defaultSnapOrigin = `local:http://localhost:8080` + +export async function snapRPC( + method: string, + codecs: SnapRPC, + req: Req +): Promise { + let reqParam = null + if (codecs.req) { + const reqBytes = codecs.req.encode(req).finish() + reqParam = b64Encode(reqBytes, 0, reqBytes.length) + } + + const responseString = await snapRequest(method, reqParam) + if (Array.isArray(responseString)) { + throw new Error('Unexpected array response') + } + + return codecs.res.decode(b64Decode(responseString)) +} + +export async function snapRequest( + method: string, + req: string | null +): Promise { + const response = await ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: defaultSnapOrigin, + request: { + method, + params: { req }, + }, + }, + }) + + if (!response || typeof response !== 'object') { + throw new Error('No response value') + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (response as any).res as unknown as string +} + +export type Snap = { + permissionName: string + id: string + version: string + initialPermissions: Record +} + +export type GetSnapsResponse = Record + +export async function isFlask() { + try { + const clientVersion = await ethereum?.request({ + method: 'web3_clientVersion', + }) + + const isFlaskDetected = (clientVersion as string[])?.includes('flask') + + return Boolean(ethereum && isFlaskDetected) + } catch { + return false + } +} + +export async function getSnaps(): Promise { + return (await ethereum.request({ + method: 'wallet_getSnaps', + })) as unknown as GetSnapsResponse +} + +export async function getSnap(version?: string): Promise { + try { + const snaps = await getSnaps() + + return Object.values(snaps).find( + (snap) => + snap.id === defaultSnapOrigin && (!version || snap.version === version) + ) + } catch (e) { + console.warn('Failed to obtain installed snap', e) + return undefined + } +} + +export async function connectSnap( + snapId: string = defaultSnapOrigin, + params: Record<'version' | string, unknown> = {} +) { + await ethereum.request({ + method: 'wallet_requestSnaps', + params: { + [snapId]: params, + }, + }) +} + +const getWalletStatusCodec = { + req: GetKeystoreStatusRequest, + res: GetKeystoreStatusResponse, +} +export async function getWalletStatus(walletAddress: string) { + const response = await snapRPC('getKeystoreStatus', getWalletStatusCodec, { + walletAddress, + }) + + if ( + [ + KeystoreStatus.KEYSTORE_STATUS_UNSPECIFIED, + KeystoreStatus.UNRECOGNIZED, + ].includes(response.status) + ) { + throw new Error('No status specified in response') + } + + return response.status +} From 72003668b60a56c323e4d8a3d6546fcc9f1e72e9 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 29 Jun 2023 16:44:20 +0200 Subject: [PATCH 045/137] feat: add new keystore methods --- src/keystore/providers/SnapProvider.ts | 57 +++++++++++++++++++++++--- src/keystore/snapHelpers.ts | 19 ++++++++- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 36592d62d..05ea35c20 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -2,10 +2,19 @@ import { KeystoreProviderUnavailableError } from './errors' import { Keystore } from '../interfaces' import { KeystoreProvider, KeystoreProviderOptions } from './interfaces' import { SnapKeystore } from '../SnapKeystore' -import { connectSnap, getSnap, getWalletStatus, isFlask } from '../snapHelpers' +import { + connectSnap, + getSnap, + getWalletStatus, + initSnap, + isFlask, +} from '../snapHelpers' import { GetKeystoreStatusResponse_KeystoreStatus as KeystoreStatus } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' import { Signer } from '../../types/Signer' import ApiClient from '../../ApiClient' +import NetworkKeystoreProvider from './NetworkKeystoreProvider' +import { PrivateKeyBundleV1 } from '../../crypto' +import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' export default class SnapKeystoreProvider implements KeystoreProvider { async newKeystore( @@ -20,15 +29,51 @@ export default class SnapKeystoreProvider implements KeystoreProvider { if (!hasSnap) { await connectSnap() } - await initSnap(wallet) + + if (!(await checkSnapLoaded(await wallet.getAddress()))) { + const bundle = await getBundle(opts, apiClient, wallet) + await initSnap(bundle) + } return SnapKeystore() } } -async function initSnap(wallet: Signer) { - const status = await getWalletStatus(await wallet.getAddress()) - if (status === KeystoreStatus.KEYSTORE_STATUS_UNINITIALIZED) { - const bundle = await getBundle(wallet) +async function createBundle( + opts: KeystoreProviderOptions, + apiClient: ApiClient, + wallet: Signer +) { + const tmpProvider = new KeyGeneratorKeystoreProvider() + const tmpKeystore = await tmpProvider.newKeystore(opts, apiClient, wallet) + return new PrivateKeyBundleV1(await tmpKeystore.getPrivateKeyBundle()) +} + +async function getBundle( + opts: KeystoreProviderOptions, + apiClient: ApiClient, + wallet: Signer +): Promise { + const networkProvider = new NetworkKeystoreProvider() + try { + const tmpKeystore = await networkProvider.newKeystore( + opts, + apiClient, + wallet + ) + return new PrivateKeyBundleV1(await tmpKeystore.getPrivateKeyBundle()) + } catch (e) { + if (e instanceof KeystoreProviderUnavailableError) { + return createBundle(opts, apiClient, wallet) + } + throw e + } +} + +async function checkSnapLoaded(walletAddress: string) { + const status = await getWalletStatus(walletAddress) + if (status === KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) { + return true } + return false } diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 1a4270e5c..50c531e70 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -1,10 +1,14 @@ import { fetcher, keystore as keystoreProto } from '@xmtp/proto' import type { SnapRPC } from './SnapKeystore' import { b64Decode } from '../utils/bytes' +import { KeystoreError } from './errors' +import { PrivateKeyBundleV1 } from '../crypto' const { + GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, + InitKeystoreRequest, + InitKeystoreResponse, GetKeystoreStatusRequest, GetKeystoreStatusResponse, - GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, } = keystoreProto const { b64Encode } = fetcher @@ -130,3 +134,16 @@ export async function getWalletStatus(walletAddress: string) { return response.status } + +const initKeystoreCodec = { + req: InitKeystoreRequest, + res: InitKeystoreResponse, +} +export async function initSnap(bundle: PrivateKeyBundleV1) { + const response = await snapRPC('initKeystore', initKeystoreCodec, { + v1: bundle, + }) + if (response.error) { + throw new KeystoreError(response.error.code, response.error.message) + } +} From 1419a3b35f628cf67263cf7f3cd1538a5835eebc Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 29 Jun 2023 16:52:14 +0200 Subject: [PATCH 046/137] docs: add coments --- src/keystore/providers/SnapProvider.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 05ea35c20..2e3a4b779 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -16,6 +16,12 @@ import NetworkKeystoreProvider from './NetworkKeystoreProvider' import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' +/** + * The Snap keystore provider will: + * 1. Check if the user is capable of using Snaps + * 2. Check if the user has already setup the Snap with the appropriate keys + * 3. If not, will get keys from the network or create new keys and store them in the Snap + */ export default class SnapKeystoreProvider implements KeystoreProvider { async newKeystore( opts: KeystoreProviderOptions, @@ -54,6 +60,8 @@ async function getBundle( apiClient: ApiClient, wallet: Signer ): Promise { + // I really don't love using other providers inside a provider. Feels like too much indirection + // TODO: Refactor keystore providers to better support the weird Snap flow const networkProvider = new NetworkKeystoreProvider() try { const tmpKeystore = await networkProvider.newKeystore( From 48b9ab021da0babcc0cef1f138bacb5f2e5f97a4 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 11:26:17 +0200 Subject: [PATCH 047/137] feat: add snap tests --- src/keystore/SnapKeystore.ts | 28 +++-------- src/keystore/providers/SnapProvider.ts | 10 ++-- src/keystore/snapHelpers.ts | 45 +++++++++++------ src/types/metamask.ts | 4 ++ src/utils/ethereum.ts | 3 ++ test/keystore/snapHelpers.test.ts | 68 ++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 39 deletions(-) create mode 100644 src/utils/ethereum.ts create mode 100644 test/keystore/snapHelpers.test.ts diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index b024b9e7b..1795e9ace 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -26,9 +26,10 @@ type ApiDefs = { async function getResponse( method: T, - req: Uint8Array | null + req: Uint8Array | null, + walletAddress: string ): Promise { - return snapRPC(method, apiDefs[method], req) + return snapRPC(method, apiDefs[method], req, walletAddress) } export const apiDefs: ApiDefs = { @@ -70,7 +71,7 @@ export const apiDefs: ApiDefs = { }, } as const -export function SnapKeystore(): Keystore { +export function SnapKeystore(walletAddress: string): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any const generatedMethods: any = {} @@ -78,31 +79,18 @@ export function SnapKeystore(): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any generatedMethods[method] = async (req: any) => { if (!apiDef.req) { - return getResponse(method as keyof Keystore, null) + return getResponse(method as keyof Keystore, null, walletAddress) } - return getResponse(method as keyof Keystore, req) + return getResponse(method as keyof Keystore, req, walletAddress) } } return { ...generatedMethods, - async getV2Conversations() { - const rawResponse = await snapRequest('getV2Conversations', null) - if (Array.isArray(rawResponse)) { - return rawResponse.map((r) => - conversationReference.ConversationReference.decode( - fetcher.b64Decode(r) - ) - ) - } - }, + // Don't bother calling the keystore, since we already have the wallet address async getAccountAddress() { - const rawResponse = await snapRequest('getAccountAddress', null) - if (Array.isArray(rawResponse)) { - throw new Error('Unexpected array response') - } - return rawResponse + return walletAddress }, } } diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 2e3a4b779..547934b37 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -26,22 +26,26 @@ export default class SnapKeystoreProvider implements KeystoreProvider { async newKeystore( opts: KeystoreProviderOptions, apiClient: ApiClient, - wallet: Signer + wallet?: Signer ): Promise { if (!isFlask()) { throw new KeystoreProviderUnavailableError('Flask not detected') } + if (!wallet) { + throw new KeystoreProviderUnavailableError('No wallet provided') + } + const walletAddress = await wallet.getAddress() const hasSnap = await getSnap() if (!hasSnap) { await connectSnap() } - if (!(await checkSnapLoaded(await wallet.getAddress()))) { + if (!(await checkSnapLoaded(walletAddress))) { const bundle = await getBundle(opts, apiClient, wallet) await initSnap(bundle) } - return SnapKeystore() + return SnapKeystore(walletAddress) } } diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 50c531e70..86293c09c 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -3,6 +3,7 @@ import type { SnapRPC } from './SnapKeystore' import { b64Decode } from '../utils/bytes' import { KeystoreError } from './errors' import { PrivateKeyBundleV1 } from '../crypto' +import { getEthereum } from '../utils/ethereum' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, InitKeystoreRequest, @@ -13,14 +14,14 @@ const { const { b64Encode } = fetcher -const ethereum = window.ethereum // TODO: Replace with npm package once released export const defaultSnapOrigin = `local:http://localhost:8080` export async function snapRPC( method: string, codecs: SnapRPC, - req: Req + req: Req, + walletAddress: string ): Promise { let reqParam = null if (codecs.req) { @@ -28,7 +29,7 @@ export async function snapRPC( reqParam = b64Encode(reqBytes, 0, reqBytes.length) } - const responseString = await snapRequest(method, reqParam) + const responseString = await snapRequest(method, reqParam, walletAddress) if (Array.isArray(responseString)) { throw new Error('Unexpected array response') } @@ -38,15 +39,16 @@ export async function snapRPC( export async function snapRequest( method: string, - req: string | null + req: string | null, + walletAddress: string ): Promise { - const response = await ethereum.request({ + const response = await getEthereum().request({ method: 'wallet_invokeSnap', params: { snapId: defaultSnapOrigin, request: { method, - params: { req }, + params: { req, walletAddress }, }, }, }) @@ -70,20 +72,20 @@ export type GetSnapsResponse = Record export async function isFlask() { try { + const ethereum = getEthereum() const clientVersion = await ethereum?.request({ method: 'web3_clientVersion', }) - const isFlaskDetected = (clientVersion as string[])?.includes('flask') return Boolean(ethereum && isFlaskDetected) - } catch { + } catch (e) { return false } } export async function getSnaps(): Promise { - return (await ethereum.request({ + return (await getEthereum()?.request({ method: 'wallet_getSnaps', })) as unknown as GetSnapsResponse } @@ -106,7 +108,7 @@ export async function connectSnap( snapId: string = defaultSnapOrigin, params: Record<'version' | string, unknown> = {} ) { - await ethereum.request({ + await getEthereum()?.request({ method: 'wallet_requestSnaps', params: { [snapId]: params, @@ -119,9 +121,14 @@ const getWalletStatusCodec = { res: GetKeystoreStatusResponse, } export async function getWalletStatus(walletAddress: string) { - const response = await snapRPC('getKeystoreStatus', getWalletStatusCodec, { - walletAddress, - }) + const response = await snapRPC( + 'getKeystoreStatus', + getWalletStatusCodec, + { + walletAddress, + }, + walletAddress + ) if ( [ @@ -140,9 +147,15 @@ const initKeystoreCodec = { res: InitKeystoreResponse, } export async function initSnap(bundle: PrivateKeyBundleV1) { - const response = await snapRPC('initKeystore', initKeystoreCodec, { - v1: bundle, - }) + const walletAddress = bundle.identityKey.publicKey.walletSignatureAddress() + const response = await snapRPC( + 'initKeystore', + initKeystoreCodec, + { + v1: bundle, + }, + walletAddress + ) if (response.error) { throw new KeystoreError(response.error.code, response.error.message) } diff --git a/src/types/metamask.ts b/src/types/metamask.ts index 911d2ffac..e93cc49d3 100644 --- a/src/types/metamask.ts +++ b/src/types/metamask.ts @@ -9,4 +9,8 @@ declare global { interface Window { ethereum: MetaMaskInpageProvider } + + interface globalThis { + ethereum: MetaMaskInpageProvider + } } diff --git a/src/utils/ethereum.ts b/src/utils/ethereum.ts new file mode 100644 index 000000000..6c61cf3bc --- /dev/null +++ b/src/utils/ethereum.ts @@ -0,0 +1,3 @@ +export function getEthereum() { + return window.ethereum; +} \ No newline at end of file diff --git a/test/keystore/snapHelpers.test.ts b/test/keystore/snapHelpers.test.ts new file mode 100644 index 000000000..441570b0c --- /dev/null +++ b/test/keystore/snapHelpers.test.ts @@ -0,0 +1,68 @@ +import { + defaultSnapOrigin, + getWalletStatus, + isFlask, +} from '../../src/keystore/snapHelpers' +import { keystore } from '@xmtp/proto' +import { b64Encode } from '../../src/utils' +const { + GetKeystoreStatusRequest, + GetKeystoreStatusResponse, + GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, +} = keystore + +// Setup the mocks for window.ethereum +const mockRequest = jest.fn() +jest.mock('../../src/utils/ethereum', () => { + return { + __esModule: true, + getEthereum: jest.fn(() => ({ + request: mockRequest, + })), + } +}) + +describe('snapHelpers', () => { + beforeEach(() => { + mockRequest.mockClear() + }) + + it('can check if the user has Flask installed', async () => { + mockRequest.mockResolvedValue(['flask']) + + expect(await isFlask()).toBe(true) + expect(mockRequest).toHaveBeenCalledTimes(1) + }) + + it('can check wallet status', async () => { + const method = 'getKeystoreStatus' + const walletAddress = '0xfoo' + const resBytes = GetKeystoreStatusResponse.encode({ + status: KeystoreStatus.KEYSTORE_STATUS_INITIALIZED, + }).finish() + + mockRequest.mockResolvedValue({ + res: b64Encode(resBytes, 0, resBytes.length), + }) + + const status = await getWalletStatus(walletAddress) + expect(status).toBe(KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) + const expectedRequest = GetKeystoreStatusRequest.encode({ + walletAddress, + }).finish() + + expect(mockRequest).toHaveBeenCalledWith({ + method: 'wallet_invokeSnap', + params: { + snapId: defaultSnapOrigin, + request: { + method, + params: { + req: b64Encode(expectedRequest, 0, expectedRequest.length), + walletAddress, + }, + }, + }, + }) + }) +}) From 2edc286c0c464742edfa34529720fd5e83d839aa Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 12:33:40 +0200 Subject: [PATCH 048/137] fix: add full meta object --- src/index.ts | 1 + src/keystore/SnapKeystore.ts | 18 ++++++++++++------ src/keystore/providers/SnapProvider.ts | 12 +++++++----- src/keystore/snapHelpers.ts | 24 +++++++++++++++--------- test/keystore/snapHelpers.test.ts | 5 +++-- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0dd637a96..ba28b44e3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,7 @@ export { ContentOptions, KeyStoreOptions, LegacyOptions, + XmtpEnv, } from './Client' export { Conversations, Conversation } from './conversations' export { GroupConversation } from './conversations/GroupConversation' diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index 1795e9ace..d42ee6939 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -8,7 +8,8 @@ import { signature, } from '@xmtp/proto' import { Reader, Writer } from 'protobufjs/minimal' -import { snapRPC, snapRequest } from './snapHelpers' +import { SnapMeta, snapRPC, snapRequest } from './snapHelpers' +import type { XmtpEnv } from '../Client' type Codec = { decode(input: Reader | Uint8Array, length?: number): T @@ -27,9 +28,9 @@ type ApiDefs = { async function getResponse( method: T, req: Uint8Array | null, - walletAddress: string + meta: SnapMeta ): Promise { - return snapRPC(method, apiDefs[method], req, walletAddress) + return snapRPC(method, apiDefs[method], req, meta) } export const apiDefs: ApiDefs = { @@ -71,18 +72,23 @@ export const apiDefs: ApiDefs = { }, } as const -export function SnapKeystore(walletAddress: string): Keystore { +export function SnapKeystore(walletAddress: string, env: XmtpEnv): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any const generatedMethods: any = {} + const snapMeta: SnapMeta = { + walletAddress, + env, + } + for (const [method, apiDef] of Object.entries(apiDefs)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any generatedMethods[method] = async (req: any) => { if (!apiDef.req) { - return getResponse(method as keyof Keystore, null, walletAddress) + return getResponse(method as keyof Keystore, null, snapMeta) } - return getResponse(method as keyof Keystore, req, walletAddress) + return getResponse(method as keyof Keystore, req, snapMeta) } } diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 547934b37..d1bbbb5c9 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -15,6 +15,7 @@ import ApiClient from '../../ApiClient' import NetworkKeystoreProvider from './NetworkKeystoreProvider' import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' +import type { XmtpEnv } from '../../Client' /** * The Snap keystore provider will: @@ -35,17 +36,18 @@ export default class SnapKeystoreProvider implements KeystoreProvider { throw new KeystoreProviderUnavailableError('No wallet provided') } const walletAddress = await wallet.getAddress() + const env = opts.env const hasSnap = await getSnap() if (!hasSnap) { await connectSnap() } - if (!(await checkSnapLoaded(walletAddress))) { + if (!(await checkSnapLoaded(walletAddress, env))) { const bundle = await getBundle(opts, apiClient, wallet) - await initSnap(bundle) + await initSnap(bundle, env) } - return SnapKeystore(walletAddress) + return SnapKeystore(walletAddress, env) } } @@ -82,8 +84,8 @@ async function getBundle( } } -async function checkSnapLoaded(walletAddress: string) { - const status = await getWalletStatus(walletAddress) +async function checkSnapLoaded(walletAddress: string, env: XmtpEnv) { + const status = await getWalletStatus({ walletAddress, env }) if (status === KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) { return true } diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 86293c09c..34de4bea3 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -4,6 +4,7 @@ import { b64Decode } from '../utils/bytes' import { KeystoreError } from './errors' import { PrivateKeyBundleV1 } from '../crypto' import { getEthereum } from '../utils/ethereum' +import type { XmtpEnv } from '../Client' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, InitKeystoreRequest, @@ -17,11 +18,16 @@ const { b64Encode } = fetcher // TODO: Replace with npm package once released export const defaultSnapOrigin = `local:http://localhost:8080` +export type SnapMeta = { + walletAddress: string + env: XmtpEnv +} + export async function snapRPC( method: string, codecs: SnapRPC, req: Req, - walletAddress: string + meta: SnapMeta ): Promise { let reqParam = null if (codecs.req) { @@ -29,7 +35,7 @@ export async function snapRPC( reqParam = b64Encode(reqBytes, 0, reqBytes.length) } - const responseString = await snapRequest(method, reqParam, walletAddress) + const responseString = await snapRequest(method, reqParam, meta) if (Array.isArray(responseString)) { throw new Error('Unexpected array response') } @@ -40,7 +46,7 @@ export async function snapRPC( export async function snapRequest( method: string, req: string | null, - walletAddress: string + meta: SnapMeta ): Promise { const response = await getEthereum().request({ method: 'wallet_invokeSnap', @@ -48,7 +54,7 @@ export async function snapRequest( snapId: defaultSnapOrigin, request: { method, - params: { req, walletAddress }, + params: { req, meta }, }, }, }) @@ -120,14 +126,14 @@ const getWalletStatusCodec = { req: GetKeystoreStatusRequest, res: GetKeystoreStatusResponse, } -export async function getWalletStatus(walletAddress: string) { +export async function getWalletStatus(meta: SnapMeta) { const response = await snapRPC( 'getKeystoreStatus', getWalletStatusCodec, { - walletAddress, + walletAddress: meta.walletAddress, }, - walletAddress + meta ) if ( @@ -146,7 +152,7 @@ const initKeystoreCodec = { req: InitKeystoreRequest, res: InitKeystoreResponse, } -export async function initSnap(bundle: PrivateKeyBundleV1) { +export async function initSnap(bundle: PrivateKeyBundleV1, env: XmtpEnv) { const walletAddress = bundle.identityKey.publicKey.walletSignatureAddress() const response = await snapRPC( 'initKeystore', @@ -154,7 +160,7 @@ export async function initSnap(bundle: PrivateKeyBundleV1) { { v1: bundle, }, - walletAddress + { walletAddress, env } ) if (response.error) { throw new KeystoreError(response.error.code, response.error.message) diff --git a/test/keystore/snapHelpers.test.ts b/test/keystore/snapHelpers.test.ts index 441570b0c..a292c22b0 100644 --- a/test/keystore/snapHelpers.test.ts +++ b/test/keystore/snapHelpers.test.ts @@ -37,6 +37,7 @@ describe('snapHelpers', () => { it('can check wallet status', async () => { const method = 'getKeystoreStatus' const walletAddress = '0xfoo' + const env = 'dev' const resBytes = GetKeystoreStatusResponse.encode({ status: KeystoreStatus.KEYSTORE_STATUS_INITIALIZED, }).finish() @@ -45,7 +46,7 @@ describe('snapHelpers', () => { res: b64Encode(resBytes, 0, resBytes.length), }) - const status = await getWalletStatus(walletAddress) + const status = await getWalletStatus({ walletAddress, env }) expect(status).toBe(KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) const expectedRequest = GetKeystoreStatusRequest.encode({ walletAddress, @@ -59,7 +60,7 @@ describe('snapHelpers', () => { method, params: { req: b64Encode(expectedRequest, 0, expectedRequest.length), - walletAddress, + meta: { walletAddress, env }, }, }, }, From a41823e2e49f719cfeb2c94ab942d5de426006ca Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 15:14:18 +0200 Subject: [PATCH 049/137] feat: clean up proto imports --- package-lock.json | 8 +++---- package.json | 2 +- src/index.ts | 7 +++++- src/keystore/SnapKeystore.ts | 33 +++++++++++++++++++------- src/keystore/index.ts | 2 +- src/keystore/providers/SnapProvider.ts | 4 ++-- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index f032a7d33..2d8cd5287 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.25.0", + "@xmtp/proto": "^3.26.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", @@ -3326,9 +3326,9 @@ } }, "node_modules/@xmtp/proto": { - "version": "3.25.0", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.25.0.tgz", - "integrity": "sha512-neVPGr40QRAWmIcG3R3d3g6ziSdY8bmKeSFRb6zWANXB3wluHoEGmud5/jZw4u/AY3E6FuNCwVODGku86iIeHw==", + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.26.0.tgz", + "integrity": "sha512-Xhvirf3yZlgaBo1nLQyVg9LQhwiVjg8S7wunf+RfP2Mrudx5bk1gS+9nx9ePcLcUSFfse0CwamqcTf6doxXNMg==", "dependencies": { "long": "^5.2.0", "protobufjs": "^7.0.0", diff --git a/package.json b/package.json index 4de8650a9..56995da85 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ }, "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.25.0", + "@xmtp/proto": "^3.26.0", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", diff --git a/src/index.ts b/src/index.ts index ba28b44e3..e2a2222a1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -68,7 +68,12 @@ export { buildUserInviteTopic, buildUserPrivateStoreTopic, } from './utils' -export { Keystore, InMemoryKeystore, TopicData } from './keystore' +export { + Keystore, + InMemoryKeystore, + TopicData, + keystoreApiDefs, +} from './keystore' export { KeystoreProvider, KeyGeneratorKeystoreProvider, diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index d42ee6939..eb6030a97 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -1,15 +1,14 @@ import { Keystore } from './interfaces' -import { - fetcher, - conversationReference, - keystore, - authn, - publicKey, - signature, -} from '@xmtp/proto' +import { keystore, authn, publicKey, signature } from '@xmtp/proto' import { Reader, Writer } from 'protobufjs/minimal' -import { SnapMeta, snapRPC, snapRequest } from './snapHelpers' +import { SnapMeta, snapRPC } from './snapHelpers' import type { XmtpEnv } from '../Client' +const { + CreateInviteFromTopicRequest, + CreateInvitesRequest, + CreateInvitesResponse, + GetV2ConversationsResponse, +} = keystore type Codec = { decode(input: Reader | Uint8Array, length?: number): T @@ -70,6 +69,22 @@ export const apiDefs: ApiDefs = { req: null, res: publicKey.PublicKeyBundle, }, + getV2Conversations: { + req: null, + res: GetV2ConversationsResponse, + }, + getGroupConversations: { + req: null, + res: GetV2ConversationsResponse, + }, + createInvites: { + req: CreateInvitesRequest, + res: CreateInvitesResponse, + }, + createInviteFromTopic: { + req: CreateInviteFromTopicRequest, + res: CreateInvitesResponse, + }, } as const export function SnapKeystore(walletAddress: string, env: XmtpEnv): Keystore { diff --git a/src/keystore/index.ts b/src/keystore/index.ts index 6219fa15a..b3ace9da4 100644 --- a/src/keystore/index.ts +++ b/src/keystore/index.ts @@ -1,6 +1,6 @@ export { default as InMemoryKeystore } from './InMemoryKeystore' export { default as InviteStore } from './InviteStore' -export { SnapKeystore } from './SnapKeystore' +export { SnapKeystore, apiDefs as keystoreApiDefs } from './SnapKeystore' export * from './encryption' export * from './errors' export * from './interfaces' diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index d1bbbb5c9..439bf5bdc 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -9,14 +9,14 @@ import { initSnap, isFlask, } from '../snapHelpers' -import { GetKeystoreStatusResponse_KeystoreStatus as KeystoreStatus } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' +import { keystore } from '@xmtp/proto' import { Signer } from '../../types/Signer' import ApiClient from '../../ApiClient' import NetworkKeystoreProvider from './NetworkKeystoreProvider' import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' import type { XmtpEnv } from '../../Client' - +const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus } = keystore /** * The Snap keystore provider will: * 1. Check if the user is capable of using Snaps From 106194d7818f4f16f94849341f5e00a7b5657e8c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 16:38:59 +0200 Subject: [PATCH 050/137] build: add snap config --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 56995da85..2e571aea7 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,10 @@ { "name": "beta", "prerelease": true + }, + { + "name": "snap", + "prerelease": true } ] }, From 222a943fcad4bc8b79c7661e3b6703ead095941e Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 16:43:13 +0200 Subject: [PATCH 051/137] build: release on snap branch --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e0333fbf1..31a6e3062 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,7 @@ on: branches: - main - beta + - snap jobs: release: name: Release From 17947261910eee95ea9adaeca1b0d8aa35607612 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 16:43:53 +0200 Subject: [PATCH 052/137] build: fmt --- src/utils/ethereum.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/ethereum.ts b/src/utils/ethereum.ts index 6c61cf3bc..d6673ba2c 100644 --- a/src/utils/ethereum.ts +++ b/src/utils/ethereum.ts @@ -1,3 +1,3 @@ export function getEthereum() { - return window.ethereum; -} \ No newline at end of file + return window.ethereum +} From 2cfe3ff89258642d47c8b124a90f822884366919 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 5 Jul 2023 17:27:55 +0200 Subject: [PATCH 053/137] fix: export SnapProvider --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index e2a2222a1..1babbd862 100644 --- a/src/index.ts +++ b/src/index.ts @@ -79,6 +79,7 @@ export { KeyGeneratorKeystoreProvider, NetworkKeystoreProvider, StaticKeystoreProvider, + SnapProvider, } from './keystore/providers' export { EncryptedPersistence, From 01d7ef0224d860282e18de36c7c79a1d4c1f1b20 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 6 Jul 2023 11:07:54 +0200 Subject: [PATCH 054/137] fix: add more logging --- src/keystore/providers/SnapProvider.ts | 3 +++ src/keystore/snapHelpers.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 439bf5bdc..90f5a3699 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -29,6 +29,7 @@ export default class SnapKeystoreProvider implements KeystoreProvider { apiClient: ApiClient, wallet?: Signer ): Promise { + console.log('Starting Snap Keystore provider') if (!isFlask()) { throw new KeystoreProviderUnavailableError('Flask not detected') } @@ -39,9 +40,11 @@ export default class SnapKeystoreProvider implements KeystoreProvider { const env = opts.env const hasSnap = await getSnap() if (!hasSnap) { + console.log('Connecting snap') await connectSnap() } + console.log('Checking if snap is loaded') if (!(await checkSnapLoaded(walletAddress, env))) { const bundle = await getBundle(opts, apiClient, wallet) await initSnap(bundle, env) diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 34de4bea3..57e9dbc88 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -29,6 +29,7 @@ export async function snapRPC( req: Req, meta: SnapMeta ): Promise { + console.log(`Doing request to ${method} with req: ${JSON.stringify(req)}`) let reqParam = null if (codecs.req) { const reqBytes = codecs.req.encode(req).finish() From 2c450cc957fe681dc43bbd73871cd8442a9a6d4d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 6 Jul 2023 11:15:01 +0200 Subject: [PATCH 055/137] fix: do not send empty params --- src/keystore/snapHelpers.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 57e9dbc88..f9fbc71b1 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -49,13 +49,17 @@ export async function snapRequest( req: string | null, meta: SnapMeta ): Promise { + const params: any = { meta } + if (req) { + params['req'] = req + } const response = await getEthereum().request({ method: 'wallet_invokeSnap', params: { snapId: defaultSnapOrigin, request: { method, - params: { req, meta }, + params, }, }, }) From f94d2434088444bf4fc1504bb427e5e131b02253 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 6 Jul 2023 11:50:12 +0200 Subject: [PATCH 056/137] feat: use new GetV2ConversationsResponse --- src/conversations/Conversations.ts | 2 +- src/keystore/InMemoryKeystore.ts | 9 +++++---- src/keystore/interfaces.ts | 2 +- test/conversations/Conversations.test.ts | 3 ++- test/keystore/InMemoryKeystore.test.ts | 11 +++++++---- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index e300a2556..8dcf207d3 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -176,7 +176,7 @@ export default class Conversations { } private async getV2ConversationsFromKeystore(): Promise { - return (await this.client.keystore.getV2Conversations()).map( + return (await this.client.keystore.getV2Conversations()).conversations.map( this.conversationReferenceToV2.bind(this) ) } diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 92b1bb2fa..3305cfcc3 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -31,6 +31,7 @@ import Long from 'long' import { hmacSha256Sign } from '../crypto/ecies' import crypto from '../crypto/crypto' import { bytesToHex } from '../crypto/utils' +import { GetV2ConversationsResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' const { ErrorCode } = keystore // Constant, 32 byte salt @@ -474,9 +475,7 @@ export default class InMemoryKeystore implements Keystore { return key.sign(digest) } - async getV2Conversations(): Promise< - conversationReference.ConversationReference[] - > { + async getV2Conversations(): Promise { const convos = this.inviteStore.topics.map((invite) => topicDataToConversationReference(invite) ) @@ -484,7 +483,9 @@ export default class InMemoryKeystore implements Keystore { convos.sort((a, b) => a.createdNs.div(1_000_000).sub(b.createdNs.div(1_000_000)).toNumber() ) - return convos + return keystore.GetV2ConversationsResponse.fromPartial({ + conversations: convos, + }) } async getGroupConversations(): Promise< diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index 35198f632..885e3e0ae 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -67,7 +67,7 @@ export interface Keystore { /** * Get a list of V2 conversations */ - getV2Conversations(): Promise + getV2Conversations(): Promise /** * Get a list of group conversations */ diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 7ac047bfa..40fc548c9 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -68,7 +68,8 @@ describe('conversations', () => { metadata: {}, }) await sleep(100) - const fromKeystore = await alice.keystore.getV2Conversations() + const fromKeystore = (await alice.keystore.getV2Conversations()) + .conversations expect(fromKeystore[1].context?.conversationId).toBe('bar') const aliceConversations3 = await alice.conversations.list() diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index 5ad23ce8d..de8c784ab 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -238,7 +238,8 @@ describe('InMemoryKeystore', () => { expect(firstResult.result!.conversation!.topic).toEqual(invite.topic) expect(firstResult.result!.conversation?.context).toBeUndefined() - const conversations = await keystore.getV2Conversations() + const conversations = (await keystore.getV2Conversations()) + .conversations expect(conversations).toHaveLength(1) expect(conversations[0].topic).toBe(invite.topic) } @@ -259,7 +260,8 @@ describe('InMemoryKeystore', () => { throw aliceResponse } - const aliceConversations = await aliceKeystore.getV2Conversations() + const aliceConversations = (await aliceKeystore.getV2Conversations()) + .conversations expect(aliceConversations).toHaveLength(1) const { @@ -269,7 +271,8 @@ describe('InMemoryKeystore', () => { throw bobResponse } - const bobConversations = await bobKeystore.getV2Conversations() + const bobConversations = (await bobKeystore.getV2Conversations()) + .conversations expect(bobConversations).toHaveLength(1) }) @@ -470,7 +473,7 @@ describe('InMemoryKeystore', () => { }) ) - const convos = await aliceKeystore.getV2Conversations() + const convos = (await aliceKeystore.getV2Conversations()).conversations let lastCreated = Long.fromNumber(0) for (let i = 0; i < convos.length; i++) { expect(convos[i].createdNs.equals(dateToNs(timestamps[i]))).toBeTruthy() From 858b39dec0562247dfc6bcaf907a7b25a282715d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 6 Jul 2023 16:33:06 +0200 Subject: [PATCH 057/137] build: rename RPCs to be generic --- src/keystore/index.ts | 3 +- src/keystore/rpcDefinitions.ts | 77 ++++++++++++++++++++++++++++++++++ src/keystore/snapHelpers.ts | 4 +- 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/keystore/rpcDefinitions.ts diff --git a/src/keystore/index.ts b/src/keystore/index.ts index b3ace9da4..7b011425e 100644 --- a/src/keystore/index.ts +++ b/src/keystore/index.ts @@ -1,6 +1,7 @@ export { default as InMemoryKeystore } from './InMemoryKeystore' export { default as InviteStore } from './InviteStore' -export { SnapKeystore, apiDefs as keystoreApiDefs } from './SnapKeystore' +export { SnapKeystore } from './SnapKeystore' +export { apiDefs as keystoreApiDefs } from './rpcDefinitions' export * from './encryption' export * from './errors' export * from './interfaces' diff --git a/src/keystore/rpcDefinitions.ts b/src/keystore/rpcDefinitions.ts new file mode 100644 index 000000000..32a54eae9 --- /dev/null +++ b/src/keystore/rpcDefinitions.ts @@ -0,0 +1,77 @@ +import { keystore, authn, publicKey, signature } from '@xmtp/proto' +import { Reader, Writer } from 'protobufjs/minimal' +const { + CreateInviteFromTopicRequest, + CreateInvitesRequest, + CreateInvitesResponse, + GetV2ConversationsResponse, +} = keystore + +type Codec = { + decode(input: Reader | Uint8Array, length?: number): T + encode(message: T, writer?: Writer): Writer +} + +export type RPC = { + req: Codec | null + res: Codec +} + +type ApiDefs = { + [k: string]: RPC +} + +export const apiDefs: ApiDefs = { + decryptV1: { + req: keystore.DecryptV1Request, + res: keystore.DecryptResponse, + }, + encryptV1: { + req: keystore.EncryptV1Request, + res: keystore.EncryptResponse, + }, + encryptV2: { + req: keystore.EncryptV2Request, + res: keystore.EncryptResponse, + }, + decryptV2: { + req: keystore.DecryptV2Request, + res: keystore.DecryptResponse, + }, + saveInvites: { + req: keystore.SaveInvitesRequest, + res: keystore.SaveInvitesResponse, + }, + createInvite: { + req: keystore.CreateInviteRequest, + res: keystore.CreateInviteResponse, + }, + createAuthToken: { + req: keystore.CreateAuthTokenRequest, + res: authn.Token, + }, + signDigest: { + req: keystore.SignDigestRequest, + res: signature.Signature, + }, + getPublicKeyBundle: { + req: null, + res: publicKey.PublicKeyBundle, + }, + getV2Conversations: { + req: null, + res: GetV2ConversationsResponse, + }, + getGroupConversations: { + req: null, + res: GetV2ConversationsResponse, + }, + createInvites: { + req: CreateInvitesRequest, + res: CreateInvitesResponse, + }, + createInviteFromTopic: { + req: CreateInviteFromTopicRequest, + res: CreateInvitesResponse, + }, +} as const diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index f9fbc71b1..4f1608436 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -1,5 +1,5 @@ import { fetcher, keystore as keystoreProto } from '@xmtp/proto' -import type { SnapRPC } from './SnapKeystore' +import type { RPC } from './rpcDefinitions' import { b64Decode } from '../utils/bytes' import { KeystoreError } from './errors' import { PrivateKeyBundleV1 } from '../crypto' @@ -25,7 +25,7 @@ export type SnapMeta = { export async function snapRPC( method: string, - codecs: SnapRPC, + codecs: RPC, req: Req, meta: SnapMeta ): Promise { From e101b6f84e1bdeeb6d09d304fd576bc49e977483 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 7 Jul 2023 14:31:22 +0200 Subject: [PATCH 058/137] fix: move around api defs --- src/keystore/SnapKeystore.ts | 78 +----------------------------------- 1 file changed, 1 insertion(+), 77 deletions(-) diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index eb6030a97..22fca4c8c 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -1,28 +1,7 @@ import { Keystore } from './interfaces' -import { keystore, authn, publicKey, signature } from '@xmtp/proto' -import { Reader, Writer } from 'protobufjs/minimal' import { SnapMeta, snapRPC } from './snapHelpers' import type { XmtpEnv } from '../Client' -const { - CreateInviteFromTopicRequest, - CreateInvitesRequest, - CreateInvitesResponse, - GetV2ConversationsResponse, -} = keystore - -type Codec = { - decode(input: Reader | Uint8Array, length?: number): T - encode(message: T, writer?: Writer): Writer -} - -export type SnapRPC = { - req: Codec | null - res: Codec -} - -type ApiDefs = { - [k: string]: SnapRPC -} +import { apiDefs } from './rpcDefinitions' async function getResponse( method: T, @@ -32,61 +11,6 @@ async function getResponse( return snapRPC(method, apiDefs[method], req, meta) } -export const apiDefs: ApiDefs = { - decryptV1: { - req: keystore.DecryptV1Request, - res: keystore.DecryptResponse, - }, - encryptV1: { - req: keystore.EncryptV1Request, - res: keystore.EncryptResponse, - }, - encryptV2: { - req: keystore.EncryptV2Request, - res: keystore.EncryptResponse, - }, - decryptV2: { - req: keystore.DecryptV2Request, - res: keystore.DecryptResponse, - }, - saveInvites: { - req: keystore.SaveInvitesRequest, - res: keystore.SaveInvitesResponse, - }, - createInvite: { - req: keystore.CreateInviteRequest, - res: keystore.CreateInviteResponse, - }, - createAuthToken: { - req: keystore.CreateAuthTokenRequest, - res: authn.Token, - }, - signDigest: { - req: keystore.SignDigestRequest, - res: signature.Signature, - }, - getPublicKeyBundle: { - req: null, - res: publicKey.PublicKeyBundle, - }, - getV2Conversations: { - req: null, - res: GetV2ConversationsResponse, - }, - getGroupConversations: { - req: null, - res: GetV2ConversationsResponse, - }, - createInvites: { - req: CreateInvitesRequest, - res: CreateInvitesResponse, - }, - createInviteFromTopic: { - req: CreateInviteFromTopicRequest, - res: CreateInvitesResponse, - }, -} as const - export function SnapKeystore(walletAddress: string, env: XmtpEnv): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any const generatedMethods: any = {} From 3d83e9498d892523379f0245ca4f37db99fadf1d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 7 Jul 2023 15:19:39 +0200 Subject: [PATCH 059/137] build: update package-lock --- package-lock.json | 5201 +++++++++++++++++++++++++++++---------------- 1 file changed, 3414 insertions(+), 1787 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d8cd5287..e9664c188 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,7 +45,7 @@ "jest-environment-jsdom": "^28.1.3", "prettier": "^2.4.0", "rimraf": "^5.0.0", - "semantic-release": "^19.0.2", + "semantic-release": "^21.0.3", "ts-jest": "^28.0.0", "ts-node": "^10.9.1", "tsup": "^6.7.0", @@ -714,33 +714,6 @@ "node": ">=v12" } }, - "node_modules/@commitlint/cli/node_modules/yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@commitlint/cli/node_modules/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/@commitlint/config-conventional": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-16.0.0.tgz", @@ -2484,153 +2457,182 @@ } }, "node_modules/@octokit/auth-token": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", "dev": true, - "dependencies": { - "@octokit/types": "^6.0.3" + "engines": { + "node": ">= 14" } }, "node_modules/@octokit/core": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz", - "integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", + "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", "dev": true, "dependencies": { - "@octokit/auth-token": "^2.4.4", - "@octokit/graphql": "^4.5.8", - "@octokit/request": "^5.6.0", - "@octokit/request-error": "^2.0.5", - "@octokit/types": "^6.0.3", + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@octokit/endpoint": { - "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", "dev": true, "dependencies": { - "@octokit/types": "^6.0.3", + "@octokit/types": "^9.0.0", "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" - } - }, - "node_modules/@octokit/endpoint/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, + }, "engines": { - "node": ">=0.10.0" + "node": ">= 14" } }, "node_modules/@octokit/graphql": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", "dev": true, "dependencies": { - "@octokit/request": "^5.6.0", - "@octokit/types": "^6.0.3", + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@octokit/openapi-types": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz", + "integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-7.1.2.tgz", + "integrity": "sha512-Jx8KuKqEAVRsK6fMzZKv3h6UH9/NRDHsDRtUAROqqmZlCptM///Uef7A1ViZ/cbDplekz7VbDWdFLAZ/mpuDww==", "dev": true, "dependencies": { - "@octokit/types": "^6.34.0" + "@octokit/tsconfig": "^2.0.0", + "@octokit/types": "^9.3.2" + }, + "engines": { + "node": ">= 18" }, "peerDependencies": { - "@octokit/core": ">=2" + "@octokit/core": ">=4" } }, - "node_modules/@octokit/plugin-request-log": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", - "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "node_modules/@octokit/plugin-retry": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-5.0.5.tgz", + "integrity": "sha512-sB1RWMhSrre02Atv95K6bhESlJ/sPdZkK/wE/w1IdSCe0yM6FxSjksLa6T7aAvxvxlLKzQEC4KIiqpqyov1Tbg==", "dev": true, + "dependencies": { + "@octokit/request-error": "^4.0.1", + "@octokit/types": "^10.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, "peerDependencies": { "@octokit/core": ">=3" } }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "node_modules/@octokit/plugin-retry/node_modules/@octokit/request-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-4.0.2.tgz", + "integrity": "sha512-uqwUEmZw3x4I9DGYq9fODVAAvcLsPQv97NRycP6syEFu5916M189VnNBW2zANNwqg3OiligNcAey7P0SET843w==", + "dev": true, + "dependencies": { + "@octokit/types": "^10.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/plugin-retry/node_modules/@octokit/types": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", + "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^18.0.0" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-6.1.0.tgz", + "integrity": "sha512-JqMbTiPC0sUSTsLQsdq3JVx1mx8UtTo5mwR80YqPXE93+XhevvSyOR1rO2Z+NbO/r0TK4hqFJSSi/9oIZBxZTg==", "dev": true, "dependencies": { - "@octokit/types": "^6.34.0", - "deprecation": "^2.3.1" + "@octokit/types": "^9.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" }, "peerDependencies": { - "@octokit/core": ">=3" + "@octokit/core": "^4.0.0" } }, "node_modules/@octokit/request": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", + "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", "dev": true, "dependencies": { - "@octokit/endpoint": "^6.0.1", - "@octokit/request-error": "^2.1.0", - "@octokit/types": "^6.16.1", + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.7", "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" } }, "node_modules/@octokit/request-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", "dev": true, "dependencies": { - "@octokit/types": "^6.0.3", + "@octokit/types": "^9.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" - } - }, - "node_modules/@octokit/request/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, + }, "engines": { - "node": ">=0.10.0" + "node": ">= 14" } }, - "node_modules/@octokit/rest": { - "version": "18.12.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", - "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", - "dev": true, - "dependencies": { - "@octokit/core": "^3.5.1", - "@octokit/plugin-paginate-rest": "^2.16.8", - "@octokit/plugin-request-log": "^1.0.4", - "@octokit/plugin-rest-endpoint-methods": "^5.12.0" - } + "node_modules/@octokit/tsconfig": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-2.0.0.tgz", + "integrity": "sha512-tWnrai3quGt8+gRN2edzo9fmraWekeryXPeXDomMw2oFSpu/lH3VSWGn/q4V+rwjTRMeeXk/ci623/01Zet4VQ==", + "dev": true }, "node_modules/@octokit/types": { - "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", + "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^11.2.0" + "@octokit/openapi-types": "^18.0.0" } }, "node_modules/@pkgjs/parseargs": { @@ -2643,6 +2645,47 @@ "node": ">=14" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -2698,210 +2741,774 @@ "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, "node_modules/@semantic-release/commit-analyzer": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-9.0.2.tgz", - "integrity": "sha512-E+dr6L+xIHZkX4zNMe6Rnwg4YQrWNXK+rNsvwOPpdFppvZO1olE2fIgWhv89TkQErygevbjsZFSIxp+u6w2e5g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-10.0.1.tgz", + "integrity": "sha512-9ejHzTAijYs9z246sY/dKBatmOPcd0GQ7lH4MgLCkv1q4GCiDZRkjHJkaQZXZVaK7mJybS+sH3Ng6G8i3pYMGQ==", "dev": true, "dependencies": { - "conventional-changelog-angular": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.2.3", + "conventional-changelog-angular": "^6.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", "debug": "^4.0.0", "import-from": "^4.0.0", - "lodash": "^4.17.4", + "lodash-es": "^4.17.21", "micromatch": "^4.0.2" }, "engines": { - "node": ">=14.17" + "node": ">=18" }, "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", + "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" } }, "node_modules/@semantic-release/error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", - "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", "dev": true, "engines": { - "node": ">=14.17" + "node": ">=18" } }, "node_modules/@semantic-release/github": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-8.0.2.tgz", - "integrity": "sha512-wIbfhOeuxlYzMTjtSAa2xgr54n7ZuPAS2gadyTWBpUt2PNAPgla7A6XxCXJnaKPgfVF0iFfSk3B+KlVKk6ByVg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.0.3.tgz", + "integrity": "sha512-X6gq4USKVlCxPwIIyXb99jU7gwVWlnsKOevs+OyABRdoqc+OIRITbFmrrYU3eE1vGMGk+Qu/GAoLUQQQwC3YOA==", "dev": true, "dependencies": { - "@octokit/rest": "^18.0.0", - "@semantic-release/error": "^2.2.0", - "aggregate-error": "^3.0.0", - "bottleneck": "^2.18.1", - "debug": "^4.0.0", - "dir-glob": "^3.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^7.0.0", + "@octokit/plugin-retry": "^5.0.0", + "@octokit/plugin-throttling": "^6.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^4.0.1", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^13.1.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", "issue-parser": "^6.0.0", - "lodash": "^4.17.4", + "lodash-es": "^4.17.21", "mime": "^3.0.0", - "p-filter": "^2.0.0", - "p-retry": "^4.0.0", - "url-join": "^4.0.0" + "p-filter": "^3.0.0", + "url-join": "^5.0.0" }, "engines": { - "node": ">=14.17" + "node": ">=18" }, "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" + "semantic-release": ">=20.1.0" } }, - "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz", - "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg==", - "dev": true - }, - "node_modules/@semantic-release/npm": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-9.0.0.tgz", - "integrity": "sha512-hj2jqayS2SPUmFtCMCOQMX975uMDfRoymj1HvMSwYdaoI6hVZvhrTFPBgJeM85O0C+G3IFviAUar5gel/1VGDQ==", + "node_modules/@semantic-release/github/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dev": true, "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.0.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.0", - "lodash": "^4.17.15", - "nerf-dart": "^1.0.0", - "normalize-url": "^6.0.0", - "npm": "^8.3.0", - "rc": "^1.2.8", - "read-pkg": "^5.0.0", - "registry-auth-token": "^4.0.0", - "semver": "^7.1.2", - "tempy": "^1.0.0" + "debug": "^4.3.4" }, "engines": { - "node": ">=16 || ^14.17" - }, - "peerDependencies": { - "semantic-release": ">=19.0.0" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-10.0.3.tgz", - "integrity": "sha512-k4x4VhIKneOWoBGHkx0qZogNjCldLPRiAjnIpMnlUh6PtaWXp/T+C9U7/TaNDDtgDa5HMbHl4WlREdxHio6/3w==", + "node_modules/@semantic-release/github/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, "dependencies": { - "conventional-changelog-angular": "^5.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.2.3", - "debug": "^4.0.0", - "get-stream": "^6.0.0", - "import-from": "^4.0.0", - "into-stream": "^6.0.0", - "lodash": "^4.17.4", - "read-pkg-up": "^7.0.0" + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" }, "engines": { - "node": ">=14.17" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependencies": { - "semantic-release": ">=18.0.0-beta.1" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@semantic-release/github/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", "dev": true, "dependencies": { - "type-detect": "4.0.8" + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "node_modules/@semantic-release/github/node_modules/https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/@semantic-release/github/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "node_modules/@semantic-release/npm": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-10.0.4.tgz", + "integrity": "sha512-6R3timIQ7VoL2QWRkc9DG8v74RQtRp7UOe/2KbNaqwJ815qOibAv65bH3RtTEhs4axEaHoZf7HDgFs5opaZ9Jw==", "dev": true, "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^4.0.1", + "execa": "^7.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^9.5.0", + "rc": "^1.2.8", + "read-pkg": "^8.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "node_modules/@semantic-release/npm/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dev": true, "dependencies": { - "@babel/types": "^7.0.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "node_modules/@semantic-release/npm/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@semantic-release/npm/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@semantic-release/npm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/parse-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.0.0.tgz", + "integrity": "sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/read-pkg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.0.0.tgz", + "integrity": "sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^5.0.0", + "parse-json": "^7.0.0", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/type-fest": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", + "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-11.0.4.tgz", + "integrity": "sha512-j0Znnwq9IdWTCGzqSlkLv4MpALTsVDZxcVESzJCNN8pK2BYQlYaKsdZ1Ea/+7RlppI3vjhEi33ZKmjSGY1FLKw==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^6.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from": "^4.0.0", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-pkg-up": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", + "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/parse-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.0.0.tgz", + "integrity": "sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.0.0.tgz", + "integrity": "sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^5.0.0", + "parse-json": "^7.0.0", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg-up": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.0.0.tgz", + "integrity": "sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.0.0", + "type-fest": "^3.12.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/type-fest": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", + "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } }, "node_modules/@types/babel__traverse": { "version": "7.18.3", @@ -3069,12 +3676,6 @@ "safe-buffer": "*" } }, - "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -3435,16 +4036,31 @@ } }, "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", "dev": true, "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ajv": { @@ -3752,9 +4368,9 @@ "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "node_modules/before-after-hook": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, "node_modules/benchmark": { @@ -4098,12 +4714,30 @@ "dev": true }, "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clean-stack/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-cursor": { @@ -4234,6 +4868,16 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/conventional-changelog-angular": { "version": "5.0.13", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", @@ -4262,26 +4906,24 @@ } }, "node_modules/conventional-changelog-writer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", - "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.0.tgz", + "integrity": "sha512-8PyWTnn7zBIt9l4hj4UusFs1TyG+9Ulu1zlOAc72L7Sdv9Hsc8E86ot7htY3HXCVhXHB/NO0pVGvZpwsyJvFfw==", "dev": true, "dependencies": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" + "meow": "^8.1.2", + "semver": "^6.3.0", + "split": "^1.0.1" }, "bin": { "conventional-changelog-writer": "cli.js" }, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/conventional-changelog-writer/node_modules/semver": { @@ -4294,16 +4936,16 @@ } }, "node_modules/conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", "dev": true, "dependencies": { "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" + "modify-values": "^1.0.1" }, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/conventional-commits-parser": { @@ -4394,12 +5036,30 @@ } }, "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/crypto-randomuuid": { @@ -4628,58 +5288,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/del/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/delay": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", @@ -4890,17 +5498,126 @@ } }, "node_modules/env-ci": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.5.0.tgz", - "integrity": "sha512-o0JdWIbOLP+WJKIUt36hz1ImQQFuN92nhsfTkHHap+J8CiI8WgGpH/a9jEGHh4/TU5BUUGjlnKXNoDb57+ne+A==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-9.1.1.tgz", + "integrity": "sha512-Im2yEWeF4b2RAMAaWvGioXk6m0UNaIjD8hj28j2ij5ldnIFrDQT0+pzDvpbRkcjurhXhf/AsBKv8P2rtmGi9Aw==", "dev": true, "dependencies": { - "execa": "^5.0.0", - "fromentries": "^1.3.2", - "java-properties": "^1.0.0" + "execa": "^7.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^16.14 || >=18" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/env-ci/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { - "node": ">=10.17" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/error-ex": { @@ -5943,9 +6660,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5995,27 +6712,31 @@ } }, "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", "dev": true, "dependencies": { - "escape-string-regexp": "^1.0.5" + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" }, "engines": { - "node": ">=8" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/file-entry-cache": { @@ -6056,15 +6777,15 @@ } }, "node_modules/find-versions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", - "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", "dev": true, "dependencies": { - "semver-regex": "^3.1.2" + "semver-regex": "^4.0.5" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6158,7 +6879,7 @@ "node_modules/from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, "dependencies": { "inherits": "^2.0.1", @@ -6166,9 +6887,9 @@ } }, "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -6189,26 +6910,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/fs-extra": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", @@ -6643,12 +7344,15 @@ } }, "node_modules/hook-std": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz", - "integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/hosted-git-info": { @@ -6745,9 +7449,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -6872,16 +7576,16 @@ } }, "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", "dev": true, "dependencies": { "from2": "^2.3.0", "p-is-promise": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7056,22 +7760,13 @@ "node": ">=8" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/is-potential-custom-element-name": { @@ -7162,6 +7857,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -7437,47 +8144,6 @@ } } }, - "node_modules/jest-cli/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/jest-cli/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/jest-cli/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/jest-config": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", @@ -8213,7 +8879,7 @@ "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "node_modules/json2csv": { @@ -8433,16 +9099,22 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, "node_modules/lodash.capitalize": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", - "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", "dev": true }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", "dev": true }, "node_modules/lodash.get": { @@ -8454,19 +9126,19 @@ "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "dev": true }, "node_modules/lodash.kebabcase": { @@ -8508,7 +9180,7 @@ "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", "dev": true }, "node_modules/log-update": { @@ -8954,7 +9626,7 @@ "node_modules/nerf-dart": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", - "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", "dev": true }, "node_modules/node-emoji": { @@ -8967,9 +9639,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -9056,40 +9728,38 @@ } }, "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.4.1.tgz", - "integrity": "sha512-Br6GQ6MGF06MhgBNhAJ4heYsCO5NJDKXnwHGaBgNDFz6HZiEOhc+sDGEcoXki4IlSUuAFdLY66BWaFI7BasMCA==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.8.0.tgz", + "integrity": "sha512-AXeiBAdfM5K2jvBwA7EGLKeYyt0VnhmJRnlq4k2+M0Ao9v7yKJBqF8xFPzQL8kAybzwlfpTPCZwM4uTIszb3xA==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", - "@npmcli/ci-detect", "@npmcli/config", "@npmcli/map-workspaces", "@npmcli/package-json", "@npmcli/run-script", "abbrev", - "ansicolors", - "ansistyles", "archy", "cacache", "chalk", - "chownr", + "ci-info", "cli-columns", "cli-table3", "columnify", "fastest-levenshtein", + "fs-minipass", "glob", "graceful-fs", "hosted-git-info", @@ -9109,10 +9779,9 @@ "libnpmteam", "libnpmversion", "make-fetch-happen", + "minimatch", "minipass", "minipass-pipeline", - "mkdirp", - "mkdirp-infer-owner", "ms", "node-gyp", "nopt", @@ -9124,18 +9793,16 @@ "npm-registry-fetch", "npm-user-validate", "npmlog", - "opener", + "p-map", "pacote", "parse-conflict-json", "proc-log", "qrcode-terminal", "read", - "read-package-json", - "read-package-json-fast", - "readdir-scoped-modules", - "rimraf", "semver", + "sigstore", "ssri", + "supports-color", "tar", "text-table", "tiny-relative-date", @@ -9146,84 +9813,79 @@ ], "dev": true, "dependencies": { - "@isaacs/string-locale-compare": "*", - "@npmcli/arborist": "*", - "@npmcli/ci-detect": "*", - "@npmcli/config": "*", - "@npmcli/map-workspaces": "*", - "@npmcli/package-json": "*", - "@npmcli/run-script": "*", - "abbrev": "*", - "ansicolors": "*", - "ansistyles": "*", - "archy": "*", - "cacache": "*", - "chalk": "*", - "chownr": "*", - "cli-columns": "*", - "cli-table3": "*", - "columnify": "*", - "fastest-levenshtein": "*", - "glob": "*", - "graceful-fs": "*", - "hosted-git-info": "*", - "ini": "*", - "init-package-json": "*", - "is-cidr": "*", - "json-parse-even-better-errors": "*", - "libnpmaccess": "*", - "libnpmdiff": "*", - "libnpmexec": "*", - "libnpmfund": "*", - "libnpmhook": "*", - "libnpmorg": "*", - "libnpmpack": "*", - "libnpmpublish": "*", - "libnpmsearch": "*", - "libnpmteam": "*", - "libnpmversion": "*", - "make-fetch-happen": "*", - "minipass": "*", - "minipass-pipeline": "*", - "mkdirp": "*", - "mkdirp-infer-owner": "*", - "ms": "*", - "node-gyp": "*", - "nopt": "*", - "npm-audit-report": "*", - "npm-install-checks": "*", - "npm-package-arg": "*", - "npm-pick-manifest": "*", - "npm-profile": "*", - "npm-registry-fetch": "*", - "npm-user-validate": "*", - "npmlog": "*", - "opener": "*", - "pacote": "*", - "parse-conflict-json": "*", - "proc-log": "*", - "qrcode-terminal": "*", - "read": "*", - "read-package-json": "*", - "read-package-json-fast": "*", - "readdir-scoped-modules": "*", - "rimraf": "*", - "semver": "*", - "ssri": "*", - "tar": "*", - "text-table": "*", - "tiny-relative-date": "*", - "treeverse": "*", - "validate-npm-package-name": "*", - "which": "*", - "write-file-atomic": "*" + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^6.3.0", + "@npmcli/config": "^6.2.1", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^4.0.0", + "@npmcli/run-script": "^6.0.2", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^17.1.3", + "chalk": "^5.2.0", + "ci-info": "^3.8.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.2", + "glob": "^10.2.7", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^6.1.1", + "ini": "^4.1.1", + "init-package-json": "^5.0.0", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^3.0.0", + "libnpmaccess": "^7.0.2", + "libnpmdiff": "^5.0.19", + "libnpmexec": "^6.0.2", + "libnpmfund": "^4.0.19", + "libnpmhook": "^9.0.3", + "libnpmorg": "^5.0.4", + "libnpmpack": "^5.0.19", + "libnpmpublish": "^7.5.0", + "libnpmsearch": "^6.0.2", + "libnpmteam": "^5.0.3", + "libnpmversion": "^4.0.2", + "make-fetch-happen": "^11.1.1", + "minimatch": "^9.0.0", + "minipass": "^5.0.0", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^9.4.0", + "nopt": "^7.2.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.1.1", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-profile": "^7.0.1", + "npm-registry-fetch": "^14.0.5", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^15.2.0", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.2", + "sigstore": "^1.7.0", + "ssri": "^10.0.4", + "supports-color": "^9.3.1", + "tar": "^6.1.15", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^3.0.1", + "write-file-atomic": "^5.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-run-path": { @@ -9238,12 +9900,83 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/@gar/promisify": { - "version": "1.1.2", + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", "dev": true, "inBundle": true, "license": "MIT" }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "dev": true, @@ -9251,75 +9984,73 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "4.3.0", + "version": "6.3.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.0", - "@npmcli/metavuln-calculator": "^2.0.0", - "@npmcli/move-file": "^1.1.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^1.0.3", - "@npmcli/package-json": "^1.0.1", - "@npmcli/run-script": "^2.0.0", - "bin-links": "^3.0.0", - "cacache": "^15.0.3", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^5.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^4.0.0", + "@npmcli/query": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "bin-links": "^4.0.1", + "cacache": "^17.0.4", "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", + "hosted-git-info": "^6.1.1", + "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "npm-install-checks": "^4.0.0", - "npm-package-arg": "^8.1.5", - "npm-pick-manifest": "^6.1.0", - "npm-registry-fetch": "^12.0.1", - "pacote": "^12.0.2", - "parse-conflict-json": "^2.0.1", - "proc-log": "^1.0.0", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-registry-fetch": "^14.0.3", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "ssri": "^8.0.1", - "treeverse": "^1.0.4", - "walk-up-path": "^1.0.0" + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.1", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" }, "bin": { "arborist": "bin/index.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/ci-detect": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "2.4.0", + "version": "6.2.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "ini": "^2.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^5.0.0", - "semver": "^7.3.4", - "walk-up-path": "^1.0.0" + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^3.8.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/disparity-colors": { - "version": "1.0.1", + "version": "3.0.0", "dev": true, "inBundle": true, "license": "ISC", @@ -9327,153 +10058,244 @@ "ansi-styles": "^4.3.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/fs": { - "version": "1.1.0", + "version": "3.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@gar/promisify": "^1.0.1", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "2.1.0", + "version": "4.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", "promise-retry": "^2.0.1", "semver": "^7.3.5", - "which": "^2.0.2" + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", + "version": "2.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "bin": { - "installed-package-contents": "index.js" + "installed-package-contents": "lib/index.js" }, "engines": { - "node": ">= 10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^17.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^15.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^4.1.0", + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.1", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "2.0.0", + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^7.1.6", - "minimatch": "^3.0.4", - "read-package-json-fast": "^2.0.1" + "postcss-selector-parser": "^6.0.10" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "2.0.0", + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "cacache": "^15.0.5", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^12.0.0", - "semver": "^7.3.2" + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "1.1.2", + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", "dev": true, "inBundle": true, "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, + "optional": true, "engines": { - "node": ">=10" + "node": ">=14" } }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.1.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "1.0.3", + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "1.0.2", "dev": true, "inBundle": true, - "license": "ISC" + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "1.0.1", + "node_modules/npm/node_modules/@tootallnate/once": { + "version": "2.0.0", "dev": true, "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.1" + "license": "MIT", + "engines": { + "node": ">= 10" } }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "1.3.2", + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "1.0.0", "dev": true, "inBundle": true, - "license": "ISC", - "dependencies": { - "infer-owner": "^1.0.4" + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "2.0.0", + "node_modules/npm/node_modules/@tufjs/models": { + "version": "1.0.4", "dev": true, "inBundle": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^8.2.0", - "read-package-json-fast": "^2.0.1" + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@tootallnate/once": { + "node_modules/npm/node_modules/abbrev": { "version": "2.0.0", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/abbrev": { - "version": "1.1.1", + "node_modules/npm/node_modules/abort-controller": { + "version": "3.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } }, "node_modules/npm/node_modules/agent-base": { "version": "6.0.2", @@ -9488,13 +10310,13 @@ } }, "node_modules/npm/node_modules/agentkeepalive": { - "version": "4.2.0", + "version": "4.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "debug": "^4.1.0", - "depd": "^1.1.2", + "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { @@ -9515,12 +10337,12 @@ } }, "node_modules/npm/node_modules/ansi-regex": { - "version": "2.1.1", + "version": "5.0.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/npm/node_modules/ansi-styles": { @@ -9538,18 +10360,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm/node_modules/ansicolors": { - "version": "0.3.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ansistyles": { - "version": "0.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/aproba": { "version": "2.0.0", "dev": true, @@ -9563,45 +10373,57 @@ "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { - "version": "2.0.0", + "version": "4.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "readable-stream": "^4.1.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/asap": { - "version": "2.0.6", + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", "dev": true, "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", + "node_modules/npm/node_modules/base64-js": { + "version": "1.5.1", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { - "version": "3.0.0", + "version": "4.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "cmd-shim": "^4.0.1", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^2.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/binary-extensions": { @@ -9614,61 +10436,77 @@ } }, "node_modules/npm/node_modules/brace-expansion": { - "version": "1.1.11", + "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/npm/node_modules/builtins": { - "version": "1.0.3", + "version": "5.0.1", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } }, "node_modules/npm/node_modules/cacache": { - "version": "15.3.0", + "version": "17.1.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" }, "engines": { - "node": ">= 10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/chalk": { - "version": "4.1.2", + "version": "5.2.0", "dev": true, "inBundle": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -9683,141 +10521,68 @@ "node": ">=10" } }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^4.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-columns/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-columns/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.1", + "node_modules/npm/node_modules/ci-info": { + "version": "3.8.0", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "1.4.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/npm/node_modules/cli-table3/node_modules/ansi-regex": { - "version": "5.0.0", + "node_modules/npm/node_modules/cidr-regex": { + "version": "3.1.1", "dev": true, "inBundle": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^4.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/npm/node_modules/cli-table3/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/npm/node_modules/cli-table3/node_modules/string-width": { - "version": "4.2.2", + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/npm/node_modules/cli-table3/node_modules/strip-ansi": { - "version": "6.0.0", + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.0" + "string-width": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" } }, "node_modules/npm/node_modules/clone": { @@ -9830,15 +10595,12 @@ } }, "node_modules/npm/node_modules/cmd-shim": { - "version": "4.1.0", + "version": "6.0.1", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "mkdirp-infer-owner": "^2.0.0" - }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/color-convert": { @@ -9868,24 +10630,17 @@ "color-support": "bin.js" } }, - "node_modules/npm/node_modules/colors": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/npm/node_modules/columnify": { - "version": "1.5.4", + "version": "1.6.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "strip-ansi": "^3.0.0", + "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" } }, "node_modules/npm/node_modules/common-ancestor-path": { @@ -9906,8 +10661,49 @@ "inBundle": true, "license": "ISC" }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/npm/node_modules/debug": { - "version": "4.3.3", + "version": "4.3.4", "dev": true, "inBundle": true, "license": "MIT", @@ -9929,22 +10725,16 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/debuglog": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/npm/node_modules/defaults": { - "version": "1.0.3", + "version": "1.0.4", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm/node_modules/delegates": { @@ -9954,26 +10744,16 @@ "license": "MIT" }, "node_modules/npm/node_modules/depd": { - "version": "1.1.2", + "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/dezalgo": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" + "node": ">= 0.8" } }, "node_modules/npm/node_modules/diff": { - "version": "5.0.0", + "version": "5.1.0", "dev": true, "inBundle": true, "license": "BSD-3-Clause", @@ -9981,6 +10761,12 @@ "node": ">=0.3.1" } }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", "dev": true, @@ -10012,122 +10798,122 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.12", + "node_modules/npm/node_modules/event-target-shim": { + "version": "5.0.1", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/npm/node_modules/events": { + "version": "3.3.0", "dev": true, "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=0.8.x" } }, - "node_modules/npm/node_modules/fs.realpath": { - "version": "1.0.0", + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", "dev": true, "inBundle": true, - "license": "ISC" + "license": "Apache-2.0" }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } }, - "node_modules/npm/node_modules/gauge": { - "version": "4.0.0", + "node_modules/npm/node_modules/foreground-child": { + "version": "3.1.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1", - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.2", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "minipass": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/npm/node_modules/fs.realpath": { + "version": "1.0.0", "dev": true, "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/npm/node_modules/gauge/node_modules/string-width": { - "version": "4.2.3", + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.1", "dev": true, "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": { - "version": "6.0.1", + "node_modules/npm/node_modules/gauge": { + "version": "5.0.1", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/glob": { - "version": "7.2.0", + "version": "10.2.7", "dev": true, "inBundle": true, "license": "ISC", "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" + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", + "path-scurry": "^1.7.0" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.9", + "version": "4.2.11", "dev": true, "inBundle": true, "license": "ISC" @@ -10144,15 +10930,6 @@ "node": ">= 0.4.0" } }, - "node_modules/npm/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", "dev": true, @@ -10160,19 +10937,19 @@ "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { - "version": "4.1.0", + "version": "6.1.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.0", + "version": "4.1.1", "dev": true, "inBundle": true, "license": "BSD-2-Clause" @@ -10192,7 +10969,7 @@ } }, "node_modules/npm/node_modules/https-proxy-agent": { - "version": "5.0.0", + "version": "5.0.1", "dev": true, "inBundle": true, "license": "MIT", @@ -10226,16 +11003,36 @@ "node": ">=0.10.0" } }, + "node_modules/npm/node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, "node_modules/npm/node_modules/ignore-walk": { - "version": "4.0.1", + "version": "6.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^9.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/imurmurhash": { @@ -10256,12 +11053,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" - }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", "dev": true, @@ -10279,34 +11070,34 @@ "license": "ISC" }, "node_modules/npm/node_modules/ini": { - "version": "2.0.0", + "version": "4.1.1", "dev": true, "inBundle": true, "license": "ISC", "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/init-package-json": { - "version": "2.0.5", + "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-package-arg": "^8.1.5", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "^4.1.1", + "npm-package-arg": "^10.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^6.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^3.0.0" + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/ip": { - "version": "1.1.5", + "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT" @@ -10333,7 +11124,7 @@ } }, "node_modules/npm/node_modules/is-core-module": { - "version": "2.8.1", + "version": "2.12.1", "dev": true, "inBundle": true, "license": "MIT", @@ -10345,12 +11136,12 @@ } }, "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", + "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/npm/node_modules/is-lambda": { @@ -10359,23 +11150,38 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/is-typedarray": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "ISC" }, + "node_modules/npm/node_modules/jackspeak": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", + "version": "3.0.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/json-stringify-nice": { "version": "1.1.4", @@ -10396,241 +11202,240 @@ "license": "MIT" }, "node_modules/npm/node_modules/just-diff": { - "version": "5.0.1", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff-apply": { - "version": "4.0.1", + "version": "5.5.0", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "5.0.1", + "version": "7.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^12.0.1" + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "3.0.0", + "version": "5.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/disparity-colors": "^1.0.1", - "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/arborist": "^6.3.0", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^3.0.4", - "npm-package-arg": "^8.1.4", - "pacote": "^12.0.0", - "tar": "^6.1.0" + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8", + "tar": "^6.1.13" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "3.0.3", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^4.0.0", - "@npmcli/ci-detect": "^1.3.0", - "@npmcli/run-script": "^2.0.0", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^8.1.2", - "pacote": "^12.0.0", - "proc-log": "^1.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "walk-up-path": "^1.0.0" + "@npmcli/arborist": "^6.3.0", + "@npmcli/run-script": "^6.0.0", + "ci-info": "^3.7.1", + "npm-package-arg": "^10.1.0", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "2.0.2", + "version": "4.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^4.0.0" + "@npmcli/arborist": "^6.3.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmhook": { - "version": "7.0.1", + "version": "9.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^12.0.1" + "npm-registry-fetch": "^14.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmorg": { - "version": "3.0.1", + "version": "5.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^12.0.1" + "npm-registry-fetch": "^14.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "3.0.1", + "version": "5.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/run-script": "^2.0.0", - "npm-package-arg": "^8.1.0", - "pacote": "^12.0.0" + "@npmcli/arborist": "^6.3.0", + "@npmcli/run-script": "^6.0.0", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "5.0.1", + "version": "7.5.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "normalize-package-data": "^3.0.2", - "npm-package-arg": "^8.1.2", - "npm-registry-fetch": "^12.0.1", - "semver": "^7.1.3", - "ssri": "^8.0.1" + "ci-info": "^3.6.1", + "normalize-package-data": "^5.0.0", + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^1.4.0", + "ssri": "^10.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmsearch": { - "version": "4.0.1", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^12.0.1" + "npm-registry-fetch": "^14.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "3.0.1", + "version": "5.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^12.0.1" + "npm-registry-fetch": "^14.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "2.0.2", + "version": "4.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^2.0.7", - "@npmcli/run-script": "^2.0.0", - "json-parse-even-better-errors": "^2.3.1", - "semver": "^7.3.5", - "stringify-package": "^1.0.1" + "@npmcli/git": "^4.0.1", + "@npmcli/run-script": "^6.0.0", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/lru-cache": { - "version": "6.0.0", + "version": "7.18.3", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/npm/node_modules/make-fetch-happen": { - "version": "10.0.0", + "version": "11.1.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/minimatch": { - "version": "3.0.4", + "version": "9.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/npm/node_modules/minipass": { - "version": "3.1.6", + "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { "node": ">=8" } @@ -10647,21 +11452,33 @@ "node": ">= 8" } }, + "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/minipass-fetch": { - "version": "1.4.1", + "version": "3.0.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "minipass": "^3.1.0", + "minipass": "^5.0.0", "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" + "minizlib": "^2.1.2" }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "optionalDependencies": { - "encoding": "^0.1.12" + "encoding": "^0.1.13" } }, "node_modules/npm/node_modules/minipass-flush": { @@ -10676,6 +11493,18 @@ "node": ">= 8" } }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/minipass-json-stream": { "version": "1.0.1", "dev": true, @@ -10686,6 +11515,18 @@ "minipass": "^3.0.0" } }, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", "dev": true, @@ -10698,6 +11539,18 @@ "node": ">=8" } }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/minipass-sized": { "version": "1.0.3", "dev": true, @@ -10710,6 +11563,18 @@ "node": ">=8" } }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/minizlib": { "version": "2.1.2", "dev": true, @@ -10723,6 +11588,18 @@ "node": ">= 8" } }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/mkdirp": { "version": "1.0.4", "dev": true, @@ -10735,168 +11612,253 @@ "node": ">=10" } }, - "node_modules/npm/node_modules/mkdirp-infer-owner": { - "version": "2.0.0", + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", "dev": true, "inBundle": true, "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">=10" + "node": "^12.13 || ^14.13 || >=16" } }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", + "node_modules/npm/node_modules/node-gyp/node_modules/abbrev": { + "version": "1.1.1", "dev": true, "inBundle": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/npm/node_modules/mute-stream": { - "version": "0.0.8", + "node_modules/npm/node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/npm/node_modules/negotiator": { - "version": "0.6.3", + "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.2", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/npm/node_modules/node-gyp": { - "version": "8.4.1", + "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { + "version": "6.0.0", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" + "abbrev": "^1.0.0" }, "bin": { - "node-gyp": "bin/node-gyp.js" + "nopt": "bin/nopt.js" }, "engines": { - "node": ">= 10.12.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/@tootallnate/once": { - "version": "1.1.2", + "node_modules/npm/node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, "engines": { - "node": ">= 6" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/http-proxy-agent": { - "version": "4.0.1", + "node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { "node": ">= 6" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "9.1.0", + "node_modules/npm/node_modules/node-gyp/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">= 10" + "node": ">= 8" } }, "node_modules/npm/node_modules/nopt": { - "version": "5.0.0", + "version": "7.2.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "abbrev": "1" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": ">=6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/normalize-package-data": { - "version": "3.0.3", + "version": "5.0.0", "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-audit-report": { - "version": "2.1.5", + "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "chalk": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-bundled": { - "version": "1.1.2", + "version": "3.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-normalize-package-bin": "^1.0.1" + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-install-checks": { - "version": "4.0.0", + "version": "6.1.1", "dev": true, "inBundle": true, "license": "BSD-2-Clause", @@ -10904,107 +11866,113 @@ "semver": "^7.1.1" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", + "version": "3.0.1", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "8.1.5", + "version": "10.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-packlist": { - "version": "3.0.0", + "version": "7.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^7.1.6", - "ignore-walk": "^4.0.1", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" + "ignore-walk": "^6.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "6.1.1", + "version": "8.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-profile": { - "version": "6.0.0", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^12.0.0" + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "12.0.1", + "version": "14.0.5", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "make-fetch-happen": "^10.0.0", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/npm-user-validate": { - "version": "1.0.1", + "version": "2.0.0", "dev": true, "inBundle": true, - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/npmlog": { - "version": "6.0.0", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "are-we-there-yet": "^2.0.0", + "are-we-there-yet": "^4.0.0", "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", + "gauge": "^5.0.0", "set-blocking": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/once": { @@ -11016,15 +11984,6 @@ "wrappy": "1" } }, - "node_modules/npm/node_modules/opener": { - "version": "1.5.2", - "dev": true, - "inBundle": true, - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" - } - }, "node_modules/npm/node_modules/p-map": { "version": "4.0.0", "dev": true, @@ -11041,50 +12000,49 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "12.0.3", + "version": "15.2.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^2.0.0", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^3.0.0", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^12.0.0", + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" }, "bin": { "pacote": "lib/bin.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/parse-conflict-json": { - "version": "2.0.1", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^4.0.1" + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/path-is-absolute": { @@ -11096,11 +12054,70 @@ "node": ">=0.10.0" } }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.9.2", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1", + "minipass": "^5.0.0 || ^6.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/path-scurry/node_modules/lru-cache": { + "version": "9.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/npm/node_modules/proc-log": { - "version": "1.0.0", + "version": "3.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/process": { + "version": "0.11.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", @@ -11112,7 +12129,7 @@ } }, "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", + "version": "1.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -11140,12 +12157,15 @@ } }, "node_modules/npm/node_modules/promzard": { - "version": "0.3.0", + "version": "1.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "read": "1" + "read": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/qrcode-terminal": { @@ -11157,99 +12177,133 @@ } }, "node_modules/npm/node_modules/read": { - "version": "1.0.7", + "version": "2.1.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "mute-stream": "~0.0.4" + "mute-stream": "~1.0.0" }, "engines": { - "node": ">=0.8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/read-cmd-shim": { - "version": "2.0.0", + "version": "4.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/read-package-json": { - "version": "4.1.1", + "version": "6.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^3.0.0", - "npm-normalize-package-bin": "^1.0.0" + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/read-package-json-fast": { - "version": "2.0.3", + "version": "3.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/readable-stream": { - "version": "3.6.0", + "version": "4.4.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/npm/node_modules/readdir-scoped-modules": { - "version": "1.1.0", + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "3.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", + "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "inBundle": true, "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">= 4" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/rimraf": { - "version": "3.0.2", + "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "*" } }, "node_modules/npm/node_modules/safe-buffer": { @@ -11280,7 +12334,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.3.5", + "version": "7.5.2", "dev": true, "inBundle": true, "license": "ISC", @@ -11294,17 +12348,73 @@ "node": ">=10" } }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "ISC" }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/signal-exit": { - "version": "3.0.6", + "version": "4.0.2", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "1.7.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/tuf": "^1.0.1", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/smart-buffer": { "version": "4.2.0", @@ -11317,13 +12427,13 @@ } }, "node_modules/npm/node_modules/socks": { - "version": "2.6.1", + "version": "2.7.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ip": "^1.1.5", - "smart-buffer": "^4.1.0" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" }, "engines": { "node": ">= 10.13.0", @@ -11331,21 +12441,21 @@ } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "6.1.1", + "version": "7.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "debug": "^4.3.3", + "socks": "^2.6.2" }, "engines": { "node": ">= 10" } }, "node_modules/npm/node_modules/spdx-correct": { - "version": "3.1.1", + "version": "3.2.0", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -11371,21 +12481,21 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.11", + "version": "3.0.13", "dev": true, "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { - "version": "8.0.1", + "version": "10.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "minipass": "^3.1.1" + "minipass": "^5.0.0" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/string_decoder": { @@ -11398,84 +12508,110 @@ } }, "node_modules/npm/node_modules/string-width": { - "version": "2.1.1", + "version": "4.2.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { - "version": "3.0.0", + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", "dev": true, "inBundle": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/npm/node_modules/stringify-package": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "3.0.1", + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/npm/node_modules/supports-color": { - "version": "7.2.0", + "version": "9.3.1", "dev": true, "inBundle": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/npm/node_modules/tar": { - "version": "6.1.11", + "version": "6.1.15", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, "engines": { - "node": ">= 10" + "node": ">=10" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/npm/node_modules/text-table": { @@ -11491,47 +12627,50 @@ "license": "MIT" }, "node_modules/npm/node_modules/treeverse": { - "version": "1.0.4", + "version": "3.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/npm/node_modules/typedarray-to-buffer": { - "version": "4.0.0", + "node_modules/npm/node_modules/tuf-js": { + "version": "1.1.7", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "inBundle": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm/node_modules/unique-filename": { - "version": "1.1.1", + "version": "3.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "unique-slug": "^2.0.0" + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/unique-slug": { - "version": "2.0.2", + "version": "4.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/util-deprecate": { @@ -11551,16 +12690,19 @@ } }, "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "3.0.0", + "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "builtins": "^1.0.3" + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/walk-up-path": { - "version": "1.0.0", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC" @@ -11575,7 +12717,7 @@ } }, "node_modules/npm/node_modules/which": { - "version": "2.0.2", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -11583,10 +12725,10 @@ "isexe": "^2.0.0" }, "bin": { - "node-which": "bin/node-which" + "node-which": "bin/which.js" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/wide-align": { @@ -11598,6 +12740,103 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/npm/node_modules/wrappy": { "version": "1.0.2", "dev": true, @@ -11605,18 +12844,16 @@ "license": "ISC" }, "node_modules/npm/node_modules/write-file-atomic": { - "version": "4.0.0", + "version": "5.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^4.0.0" + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/yallist": { @@ -11744,27 +12981,30 @@ } }, "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-filter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", - "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", + "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", "dev": true, "dependencies": { - "p-map": "^2.0.0" + "p-map": "^5.1.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-is-promise": { @@ -11804,34 +13044,30 @@ } }, "node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", "dev": true, + "dependencies": { + "aggregate-error": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-reduce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", - "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" + "node": ">=12" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -12203,6 +13439,12 @@ "node": ">= 6" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/protobufjs": { "version": "6.11.3", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", @@ -12247,569 +13489,920 @@ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", + "dev": true, + "dependencies": { + "esprima": "~4.0.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "node_modules/regextras": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", + "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", "dev": true, "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" + "node": ">=0.1.14" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { - "rc": "cli.js" + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "global-dirs": "^0.1.1" }, "engines": { "node": ">=8" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, "engines": { - "node": ">=8" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "node_modules/rimraf": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", + "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", + "dev": true, + "dependencies": { + "glob": "^10.0.0" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "balanced-match": "^1.0.0" } }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/rimraf/node_modules/glob": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", + "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.0", + "minipass": "^5.0.0", + "path-scurry": "^1.7.0" + }, "bin": { - "semver": "bin/semver" + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/rollup": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz", + "integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">= 6" + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", + "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", "dev": true, "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=", - "dev": true, - "dependencies": { - "esprima": "~4.0.0" + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/semantic-release": { + "version": "21.0.7", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-21.0.7.tgz", + "integrity": "sha512-peRDSXN+hF8EFSKzze90ff/EnAmgITHQ/a3SZpRV3479ny0BIZWEJ33uX6/GlOSKdaSxo9hVRDyv2/u2MuF+Bw==", + "dev": true, + "dependencies": { + "@semantic-release/commit-analyzer": "^10.0.0", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^9.0.0", + "@semantic-release/npm": "^10.0.2", + "@semantic-release/release-notes-generator": "^11.0.0", + "aggregate-error": "^4.0.1", + "cosmiconfig": "^8.0.0", + "debug": "^4.0.0", + "env-ci": "^9.0.0", + "execa": "^7.0.0", + "figures": "^5.0.0", + "find-versions": "^5.1.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^6.0.0", + "lodash-es": "^4.17.21", + "marked": "^5.0.0", + "marked-terminal": "^5.1.1", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-pkg-up": "^10.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": ">=18" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "node_modules/semantic-release/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/semantic-release/node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/d-fischer" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "node_modules/semantic-release/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/regextras": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz", - "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", + "node_modules/semantic-release/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, "engines": { - "node": ">=0.1.14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "node_modules/semantic-release/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { - "rc": "^1.2.8" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=6.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "node_modules/semantic-release/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=14.18.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "node_modules/semantic-release/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "node_modules/semantic-release/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "argparse": "^2.0.1" }, "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/resolve-cwd": { + "node_modules/semantic-release/node_modules/json-parse-even-better-errors": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/semantic-release/node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/resolve-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", - "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "node_modules/semantic-release/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "global-dirs": "^0.1.1" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resolve.exports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", - "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "node_modules/semantic-release/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/semantic-release/node_modules/marked": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-5.1.0.tgz", + "integrity": "sha512-z3/nBe7aTI8JDszlYLk7dDVNpngjw0o1ZJtrA9kIfkkHcIF+xH7mO23aISl4WxP83elU+MFROgahqdpd05lMEQ==", "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "bin": { + "marked": "bin/marked.js" }, "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" + "node": ">= 18" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/semantic-release/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rimraf": { + "node_modules/semantic-release/node_modules/normalize-package-data": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", "dev": true, "dependencies": { - "glob": "^10.0.0" + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/semantic-release/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" }, "engines": { - "node": ">=14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/semantic-release/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", + "node_modules/semantic-release/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "node_modules/semantic-release/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rimraf/node_modules/minipass": { + "node_modules/semantic-release/node_modules/path-exists": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/rollup": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.2.tgz", - "integrity": "sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==", + "node_modules/semantic-release/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" + "node": ">=12" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/semantic-release/node_modules/read-pkg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.0.0.tgz", + "integrity": "sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "dependencies": { - "queue-microtask": "^1.2.2" + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^5.0.0", + "parse-json": "^7.0.0", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "node_modules/semantic-release/node_modules/read-pkg-up": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.0.0.tgz", + "integrity": "sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==", + "dev": true, "dependencies": { - "tslib": "^2.1.0" + "find-up": "^6.3.0", + "read-pkg": "^8.0.0", + "type-fest": "^3.12.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", - "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "node_modules/semantic-release/node_modules/read-pkg/node_modules/parse-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.0.0.tgz", + "integrity": "sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==", "dev": true, "dependencies": { - "xmlchars": "^2.2.0" + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" }, "engines": { - "node": ">=10" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" - }, - "node_modules/semantic-release": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.2.tgz", - "integrity": "sha512-7tPonjZxukKECmClhsfyMKDt0GR38feIC2HxgyYaBi+9tDySBLjK/zYDLhh+m6yjnHIJa9eBTKYE7k63ZQcYbw==", + "node_modules/semantic-release/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "dependencies": { - "@semantic-release/commit-analyzer": "^9.0.2", - "@semantic-release/error": "^3.0.0", - "@semantic-release/github": "^8.0.0", - "@semantic-release/npm": "^9.0.0", - "@semantic-release/release-notes-generator": "^10.0.0", - "aggregate-error": "^3.0.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.0.0", - "env-ci": "^5.0.0", - "execa": "^5.0.0", - "figures": "^3.0.0", - "find-versions": "^4.0.0", - "get-stream": "^6.0.0", - "git-log-parser": "^1.2.0", - "hook-std": "^2.0.0", - "hosted-git-info": "^4.0.0", - "lodash": "^4.17.21", - "marked": "^4.0.10", - "marked-terminal": "^5.0.0", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "p-reduce": "^2.0.0", - "read-pkg-up": "^7.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.3.2", - "semver-diff": "^3.1.1", - "signale": "^1.2.1", - "yargs": "^16.2.0" + "engines": { + "node": ">=12" }, - "bin": { - "semantic-release": "bin/semantic-release.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/type-fest": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", + "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", + "dev": true, + "engines": { + "node": ">=14.16" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, "engines": { - "node": ">=16 || ^14.17" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/semver": { @@ -12828,33 +14421,27 @@ } }, "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", "dev": true, "dependencies": { - "semver": "^6.3.0" + "semver": "^7.3.5" }, "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/semver-regex": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz", - "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -13436,31 +15023,42 @@ } }, "node_modules/tempy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", - "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.0.0.tgz", + "integrity": "sha512-B2I9X7+o2wOaW4r/CWMkpOO9mdiTRCxXNgob6iGvPmfPWgH/KyUD6Uy5crtWBxIBe3YrNZKR2lSzv1JJKWD4vA==", "dev": true, "dependencies": { - "del": "^6.0.0", - "is-stream": "^2.0.0", + "is-stream": "^3.0.0", "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -13965,9 +15563,9 @@ } }, "node_modules/uglify-js": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.1.tgz", - "integrity": "sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true, "bin": { @@ -14004,15 +15602,18 @@ } }, "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", "dev": true, "dependencies": { - "crypto-random-string": "^2.0.0" + "crypto-random-string": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/universal-user-agent": { @@ -14066,10 +15667,13 @@ } }, "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } }, "node_modules/url-parse": { "version": "1.5.10", @@ -14252,7 +15856,7 @@ "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "node_modules/wrap-ansi": { @@ -14360,21 +15964,21 @@ } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { @@ -14386,6 +15990,29 @@ "node": ">=10" } }, + "node_modules/yargs/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", From 13f86107cde574cac4e73cbbbde9b64844b1effa Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 7 Jul 2023 16:17:42 +0200 Subject: [PATCH 060/137] fix: export defaultKeystoreProviders --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index efecd32dd..8bee45193 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,6 +23,7 @@ export { default as Stream } from './Stream' export { Signer } from './types/Signer' export { default as Client, + defaultKeystoreProviders, ClientOptions, ListMessagesOptions, ListMessagesPaginatedOptions, From a8d2d85b3814a97553850871af21184bf47ad1f0 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 7 Jul 2023 16:42:48 +0200 Subject: [PATCH 061/137] fix: allow for empty strings to be sent --- src/keystore/snapHelpers.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 4f1608436..55cde8a3c 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -1,6 +1,6 @@ -import { fetcher, keystore as keystoreProto } from '@xmtp/proto' +import { keystore as keystoreProto } from '@xmtp/proto' import type { RPC } from './rpcDefinitions' -import { b64Decode } from '../utils/bytes' +import { b64Decode, b64Encode } from '../utils/bytes' import { KeystoreError } from './errors' import { PrivateKeyBundleV1 } from '../crypto' import { getEthereum } from '../utils/ethereum' @@ -13,8 +13,6 @@ const { GetKeystoreStatusResponse, } = keystoreProto -const { b64Encode } = fetcher - // TODO: Replace with npm package once released export const defaultSnapOrigin = `local:http://localhost:8080` @@ -23,13 +21,18 @@ export type SnapMeta = { env: XmtpEnv } +type SnapParams = { + meta: SnapMeta + req?: string +} + export async function snapRPC( method: string, codecs: RPC, req: Req, meta: SnapMeta ): Promise { - console.log(`Doing request to ${method} with req: ${JSON.stringify(req)}`) + console.log(`Doing request to ${method} with params: ${JSON.stringify(req)}`) let reqParam = null if (codecs.req) { const reqBytes = codecs.req.encode(req).finish() @@ -49,9 +52,9 @@ export async function snapRequest( req: string | null, meta: SnapMeta ): Promise { - const params: any = { meta } - if (req) { - params['req'] = req + const params: SnapParams = { meta } + if (typeof req === 'string') { + params.req = req } const response = await getEthereum().request({ method: 'wallet_invokeSnap', From 585ba4371f3c8893d6fdb50921977c68c70dc73a Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 7 Jul 2023 16:42:58 +0200 Subject: [PATCH 062/137] build: eslint disable --- src/keystore/rpcDefinitions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/keystore/rpcDefinitions.ts b/src/keystore/rpcDefinitions.ts index 32a54eae9..6e37980fe 100644 --- a/src/keystore/rpcDefinitions.ts +++ b/src/keystore/rpcDefinitions.ts @@ -18,6 +18,7 @@ export type RPC = { } type ApiDefs = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [k: string]: RPC } From 262e048f2394e4ee22fe6b40ac497e5520e871dc Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 17 Jul 2023 10:58:40 +0200 Subject: [PATCH 063/137] feat: support group conversations --- src/conversations/Conversations.ts | 4 +++- src/keystore/InMemoryKeystore.ts | 17 ++++++----------- src/keystore/interfaces.ts | 13 ++----------- src/keystore/snapHelpers.ts | 1 - 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 5e61f94c2..ddf31ba2a 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -196,7 +196,9 @@ export default class Conversations { private async getGroupConversationsFromKeystore(): Promise< GroupConversation[] > { - return (await this.client.keystore.getGroupConversations()).map((ref) => { + return ( + await this.client.keystore.getGroupConversations() + ).conversations.map((ref) => { return GroupConversation.from(this.conversationReferenceToV2(ref)) }) } diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index f554f5031..1d962813c 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -1,10 +1,4 @@ -import { - authn, - keystore, - privateKey, - signature, - conversationReference, -} from '@xmtp/proto' +import { authn, keystore, privateKey, signature } from '@xmtp/proto' import { PrivateKeyBundleV1, PrivateKeyBundleV2, @@ -487,9 +481,7 @@ export default class InMemoryKeystore implements Keystore { }) } - async getGroupConversations(): Promise< - conversationReference.ConversationReference[] - > { + async getGroupConversations(): Promise { const convos = this.inviteStore.groupTopics.map((invite) => topicDataToConversationReference(invite) ) @@ -497,7 +489,10 @@ export default class InMemoryKeystore implements Keystore { convos.sort((a, b) => a.createdNs.div(1_000_000).sub(b.createdNs.div(1_000_000)).toNumber() ) - return convos + + return keystore.GetV2ConversationsResponse.fromPartial({ + conversations: convos, + }) } async getPublicKeyBundle(): Promise { diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index 885e3e0ae..bc3991b7c 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -1,11 +1,4 @@ -import { - conversationReference, - keystore, - publicKey, - authn, - privateKey, - signature, -} from '@xmtp/proto' +import { keystore, publicKey, authn, privateKey, signature } from '@xmtp/proto' import { WithoutUndefined } from '../utils/typedefs' /** @@ -71,9 +64,7 @@ export interface Keystore { /** * Get a list of group conversations */ - getGroupConversations(): Promise< - conversationReference.ConversationReference[] - > + getGroupConversations(): Promise /** * Get the `PublicKeyBundle` associated with the Keystore's private keys */ diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 55cde8a3c..d5955895d 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -32,7 +32,6 @@ export async function snapRPC( req: Req, meta: SnapMeta ): Promise { - console.log(`Doing request to ${method} with params: ${JSON.stringify(req)}`) let reqParam = null if (codecs.req) { const reqBytes = codecs.req.encode(req).finish() From 0dff02f59a8935ea5535bf6917c2c189ff2617ac Mon Sep 17 00:00:00 2001 From: Pat Nakajima Date: Mon, 31 Jul 2023 15:22:59 -0700 Subject: [PATCH 064/137] feat: move content fallback definitions to content codecs this will allow content types to define standard fallback content instead of forcing clients to figure it out for themselves --- src/Client.ts | 7 ++++--- src/MessageContent.ts | 1 + src/codecs/Composite.ts | 5 +++++ src/codecs/Text.ts | 12 +++++++++++- src/codecs/TypingNotification.ts | 5 +++++ test/ContentTypeTestKey.ts | 5 +++++ test/Message.test.ts | 1 - test/conversations/Conversation.test.ts | 6 ++---- 8 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index ebd6de1aa..80d7132ea 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -56,7 +56,6 @@ export type ListMessagesPaginatedOptions = { export { Compression } export type SendOptions = { contentType?: ContentTypeId - contentFallback?: string compression?: proto.Compression timestamp?: Date ephemeral?: boolean @@ -581,8 +580,10 @@ export default class Client { throw new Error('unknown content type ' + contentType) } const encoded = codec.encode(content, this) - if (options?.contentFallback) { - encoded.fallback = options.contentFallback + + const fallback = codec.fallback(content) + if (fallback) { + encoded.fallback = fallback } if (typeof options?.compression === 'number') { encoded.compression = options.compression diff --git a/src/MessageContent.ts b/src/MessageContent.ts index ef32dcfe4..216016d78 100644 --- a/src/MessageContent.ts +++ b/src/MessageContent.ts @@ -57,6 +57,7 @@ export interface ContentCodec { contentType: ContentTypeId encode(content: T, registry: CodecRegistry): EncodedContent decode(content: EncodedContent, registry: CodecRegistry): T + fallback(content: T): string | undefined } // xmtp.org/fallback diff --git a/src/codecs/Composite.ts b/src/codecs/Composite.ts index 02c10717a..1a8c13178 100644 --- a/src/codecs/Composite.ts +++ b/src/codecs/Composite.ts @@ -107,4 +107,9 @@ export class CompositeCodec implements ContentCodec { } return { parts } } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fallback(content: Composite): string | undefined { + return undefined + } } diff --git a/src/codecs/Text.ts b/src/codecs/Text.ts index 4acc79f5c..606dccc35 100644 --- a/src/codecs/Text.ts +++ b/src/codecs/Text.ts @@ -1,4 +1,9 @@ -import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' +import { + ContentTypeId, + ContentCodec, + EncodedContent, + CodecRegistry, +} from '../MessageContent' // xmtp.org/text // @@ -34,4 +39,9 @@ export class TextCodec implements ContentCodec { } return new TextDecoder().decode(content.content) } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fallback(content: string): string | undefined { + return undefined + } } diff --git a/src/codecs/TypingNotification.ts b/src/codecs/TypingNotification.ts index de3e89df5..f7d2f1cd3 100644 --- a/src/codecs/TypingNotification.ts +++ b/src/codecs/TypingNotification.ts @@ -47,4 +47,9 @@ export class TypingNotificationCodec isFinished, } } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fallback(content: TypingNotification): string | undefined { + return undefined + } } diff --git a/test/ContentTypeTestKey.ts b/test/ContentTypeTestKey.ts index 1a66ac1a9..0b844f510 100644 --- a/test/ContentTypeTestKey.ts +++ b/test/ContentTypeTestKey.ts @@ -24,4 +24,9 @@ export class TestKeyCodec implements ContentCodec { decode(content: EncodedContent): PublicKey { return new PublicKey(publicKey.PublicKey.decode(content.content)) } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fallback(content: PublicKey): string | undefined { + return 'publickey bundle' + } } diff --git a/test/Message.test.ts b/test/Message.test.ts index cb6800862..1448986a2 100644 --- a/test/Message.test.ts +++ b/test/Message.test.ts @@ -218,7 +218,6 @@ describe('Message', function () { const fallback = 'publickey bundle' const sentMessage = await convo.send(msg, { contentType: ContentTypeTestKey, - contentFallback: fallback, }) expect(sentMessage.contentType).toEqual(ContentTypeTestKey) diff --git a/test/conversations/Conversation.test.ts b/test/conversations/Conversation.test.ts index 5f2fa4e45..612f2b69a 100644 --- a/test/conversations/Conversation.test.ts +++ b/test/conversations/Conversation.test.ts @@ -442,7 +442,6 @@ describe('conversation', () => { alice.registerCodec(new TestKeyCodec()) await aliceConvo.send(key, { contentType: ContentTypeTestKey, - contentFallback: 'this is a public key', }) const aliceResult1 = await aliceStream.next() @@ -458,7 +457,7 @@ describe('conversation', () => { expect(bobMessage1.contentType).toBeTruthy() expect(bobMessage1.contentType.sameAs(ContentTypeTestKey)) expect(bobMessage1.content).toBeUndefined() - expect(bobMessage1.contentFallback).toBe('this is a public key') + expect(bobMessage1.contentFallback).toBe('publickey bundle') // both recognize the type bob.registerCodec(new TestKeyCodec()) @@ -681,7 +680,6 @@ describe('conversation', () => { alice.registerCodec(new TestKeyCodec()) await aliceConvo.send(key, { contentType: ContentTypeTestKey, - contentFallback: 'this is a public key', }) const aliceResult1 = await aliceStream.next() @@ -697,7 +695,7 @@ describe('conversation', () => { expect(bobMessage1.contentType).toBeTruthy() expect(bobMessage1.contentType.sameAs(ContentTypeTestKey)) expect(bobMessage1.content).toBeUndefined() - expect(bobMessage1.contentFallback).toBe('this is a public key') + expect(bobMessage1.contentFallback).toBe('publickey bundle') // both recognize the type bob.registerCodec(new TestKeyCodec()) From fdeefe5eb3b0f41bca6672be342bbc0167b6ef8e Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 17 Aug 2023 08:59:15 -0700 Subject: [PATCH 065/137] feat: pluggable API client --- src/ApiClient.ts | 28 ++++++++++++++++++- src/Client.ts | 25 +++++++++++------ src/authn/index.ts | 1 + src/conversations/Conversation.ts | 1 - src/index.ts | 17 ++++++++++- src/keystore/persistence/TopicPersistence.ts | 6 ++-- .../providers/NetworkKeystoreProvider.ts | 4 +-- src/keystore/providers/interfaces.ts | 4 +-- 8 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/ApiClient.ts b/src/ApiClient.ts index cbe3c29d0..80768ef07 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -115,11 +115,37 @@ const isAuthError = (err?: GrpcError | Error): boolean => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const isNotAuthError = (err?: Error): boolean => !isAuthError(err) +export interface IApiClient { + query( + params: QueryParams, + options: QueryAllOptions + ): Promise + queryIterator( + params: QueryParams, + options: QueryStreamOptions + ): AsyncGenerator + queryIteratePages( + params: QueryParams, + options: QueryStreamOptions + ): AsyncGenerator + subscribe( + params: SubscribeParams, + callback: SubscribeCallback, + onConnectionLost?: OnConnectionLostCallback + ): UnsubscribeFn + publish(messages: PublishParams[]): ReturnType + batchQuery(queries: Query[]): Promise + setAuthenticator( + authenticator: Authenticator, + cacheExpirySeconds?: number + ): void +} + /** * ApiClient provides a wrapper for calling the GRPC Gateway generated code. * It adds some helpers for dealing with paginated data and automatically retries idempotent calls */ -export default class ApiClient { +export default class ApiClient implements IApiClient { pathPrefix: string maxRetries: number private authCache?: AuthCache diff --git a/src/Client.ts b/src/Client.ts index 55ea8505f..08ba0a685 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -14,7 +14,12 @@ import { ContentTypeId, ContentCodec } from './MessageContent' import { compress } from './Compression' import { content as proto, messageApi, fetcher } from '@xmtp/proto' import { decodeContactBundle, encodeContactBundle } from './ContactBundle' -import ApiClient, { ApiUrls, PublishParams, SortDirection } from './ApiClient' +import ApiClient, { + ApiUrls, + IApiClient, + PublishParams, + SortDirection, +} from './ApiClient' import { KeystoreAuthenticator } from './authn' import { Flatten } from './utils/typedefs' import BackupClient, { BackupType } from './message-backup/BackupClient' @@ -105,6 +110,8 @@ export type NetworkOptions = { * a push notification. */ skipContactPublishing: boolean + + apiClientFactory: (options: NetworkOptions) => IApiClient } export type ContentOptions = { @@ -189,6 +196,8 @@ export function defaultOptions(opts?: Partial): ClientOptions { persistConversations: true, skipContactPublishing: false, keystoreProviders: defaultKeystoreProviders(), + apiClientFactory: (options: NetworkOptions) => + createApiClientFromOptions(options), } if (opts?.codecs) { opts.codecs = _defaultOptions.codecs.concat(opts.codecs) @@ -204,7 +213,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { export default class Client { address: string keystore: Keystore - apiClient: ApiClient + apiClient: IApiClient contacts: Set // address which we have connected to publicKeyBundle: PublicKeyBundle private knownPublicKeyBundles: Map< @@ -220,7 +229,7 @@ export default class Client { constructor( publicKeyBundle: PublicKeyBundle, - apiClient: ApiClient, + apiClient: IApiClient, backupClient: BackupClient, keystore: Keystore ) { @@ -266,7 +275,7 @@ export default class Client { opts?: Partial ): Promise { const options = defaultOptions(opts) - const apiClient = createApiClientFromOptions(options) + const apiClient = options.apiClientFactory(options) const keystore = await bootstrapKeystore(options, apiClient, wallet) const publicKeyBundle = new PublicKeyBundle( await keystore.getPublicKeyBundle() @@ -660,7 +669,7 @@ export default class Client { } } -function createApiClientFromOptions(options: ClientOptions): ApiClient { +function createApiClientFromOptions(options: NetworkOptions): ApiClient { const apiUrl = options.apiUrl || ApiUrls[options.env] return new ApiClient(apiUrl, { appVersion: options.appVersion }) } @@ -669,7 +678,7 @@ function createApiClientFromOptions(options: ClientOptions): ApiClient { * Retrieve a key bundle from given user's contact topic */ async function getUserContactFromNetwork( - apiClient: ApiClient, + apiClient: IApiClient, peerAddress: string ): Promise { const stream = apiClient.queryIterator( @@ -698,7 +707,7 @@ async function getUserContactFromNetwork( * Retrieve a list of key bundles given a list of user addresses */ async function getUserContactsFromNetwork( - apiClient: ApiClient, + apiClient: IApiClient, peerAddresses: string[] ): Promise<(PublicKeyBundle | SignedPublicKeyBundle | undefined)[]> { const userContactTopics = peerAddresses.map(buildUserContactTopic) @@ -762,7 +771,7 @@ export function defaultKeystoreProviders(): KeystoreProvider[] { */ async function bootstrapKeystore( opts: ClientOptions, - apiClient: ApiClient, + apiClient: IApiClient, wallet: Signer | null ): Promise { for (const provider of opts.keystoreProviders) { diff --git a/src/authn/index.ts b/src/authn/index.ts index 898a2b63d..b44778210 100644 --- a/src/authn/index.ts +++ b/src/authn/index.ts @@ -2,4 +2,5 @@ export { default as LocalAuthenticator } from './LocalAuthenticator' export { default as KeystoreAuthenticator } from './KeystoreAuthenticator' export { default as AuthData } from './AuthData' export { default as Token } from './Token' +export { default as AuthCache } from './AuthCache' export * from './interfaces' diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index abad3c9f8..3e32d9813 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -33,7 +33,6 @@ import { PreparedMessage } from '../PreparedMessage' import { sha256 } from '../crypto/encryption' import { buildDecryptV1Request, getResultOrThrow } from '../utils/keystore' import { ContentTypeText } from '../codecs/Text' -import { OnceBlockable } from 'ethers/lib/utils' /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ diff --git a/src/index.ts b/src/index.ts index f01755542..859ae77c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import { Authenticator } from './authn/interfaces' export { Message, DecodedMessage, @@ -55,7 +56,21 @@ export { CompositeCodec, ContentTypeComposite, } from './codecs/Composite' -export { ApiUrls, SortDirection } from './ApiClient' +export { + ApiUrls, + SortDirection, + IApiClient, + QueryParams, + QueryAllOptions, + QueryStreamOptions, + Query, + PublishParams, + SubscribeParams, + SubscribeCallback, + UnsubscribeFn, + OnConnectionLostCallback, +} from './ApiClient' +export { Authenticator, AuthCache } from './authn' export { nsToDate, dateToNs, diff --git a/src/keystore/persistence/TopicPersistence.ts b/src/keystore/persistence/TopicPersistence.ts index 7e17c3043..d9dede441 100644 --- a/src/keystore/persistence/TopicPersistence.ts +++ b/src/keystore/persistence/TopicPersistence.ts @@ -1,13 +1,13 @@ import { messageApi } from '@xmtp/proto' -import ApiClient from '../../ApiClient' +import type { IApiClient } from '../../ApiClient' import { Authenticator } from '../../authn' import { b64Decode } from '../../utils/bytes' import { buildUserPrivateStoreTopic } from '../../utils/topic' import { Persistence } from './interface' export default class TopicPersistence implements Persistence { - apiClient: ApiClient - constructor(apiClient: ApiClient) { + apiClient: IApiClient + constructor(apiClient: IApiClient) { this.apiClient = apiClient } diff --git a/src/keystore/providers/NetworkKeystoreProvider.ts b/src/keystore/providers/NetworkKeystoreProvider.ts index f8e3864d5..6880338cb 100644 --- a/src/keystore/providers/NetworkKeystoreProvider.ts +++ b/src/keystore/providers/NetworkKeystoreProvider.ts @@ -1,5 +1,5 @@ import { Signer } from './../../types/Signer' -import ApiClient from '../../ApiClient' +import type { IApiClient } from '../../ApiClient' import { KeystoreProvider, KeystoreProviderOptions } from './interfaces' import NetworkKeyLoader from './NetworkKeyManager' import { KeystoreProviderUnavailableError } from './errors' @@ -16,7 +16,7 @@ import { buildPersistenceFromOptions } from './helpers' export default class NetworkKeystoreProvider implements KeystoreProvider { async newKeystore( opts: KeystoreProviderOptions, - apiClient: ApiClient, + apiClient: IApiClient, wallet?: Signer ): Promise { if (!wallet) { diff --git a/src/keystore/providers/interfaces.ts b/src/keystore/providers/interfaces.ts index 47df1dee7..9837786a9 100644 --- a/src/keystore/providers/interfaces.ts +++ b/src/keystore/providers/interfaces.ts @@ -1,7 +1,7 @@ import type { XmtpEnv, PreEventCallbackOptions } from '../../Client' -import type ApiClient from '../../ApiClient' import type { Signer } from '../../types/Signer' import type { Keystore } from '../interfaces' +import type { IApiClient } from '../../ApiClient' export type KeystoreProviderOptions = { env: XmtpEnv @@ -16,7 +16,7 @@ export type KeystoreProviderOptions = { export interface KeystoreProvider { newKeystore( opts: KeystoreProviderOptions, - apiClient: ApiClient, + apiClient: IApiClient, wallet?: Signer ): Promise } From 699b21e2d1854ba819e685d03bf17539a5ae113d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 18 Aug 2023 20:38:26 -0700 Subject: [PATCH 066/137] feat: export PrivateKeyBundleV1 --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 859ae77c0..77553f796 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,8 @@ export { SignedPublicKeyBundle, PrivateKey, PrivateKeyBundle, + PrivateKeyBundleV1, + PrivateKeyBundleV2, Signature, encrypt, decrypt, From f49165d008a2e48fc9a723c3bb63e63a97e195b4 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 14:09:42 -0700 Subject: [PATCH 067/137] feat: make persistence pluggable --- src/Client.ts | 15 +++++++++++++++ src/keystore/providers/helpers.ts | 12 ++++++------ src/keystore/providers/interfaces.ts | 3 +++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 08ba0a685..30decbc21 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -32,6 +32,7 @@ import { NetworkKeystoreProvider, StaticKeystoreProvider, } from './keystore/providers' +import { LocalStoragePersistence, Persistence } from './keystore/persistence' const { Compression } = proto const { b64Decode } = fetcher @@ -144,6 +145,17 @@ export type KeyStoreOptions = { * A bundle can be retried using `Client.getKeys(...)` */ privateKeyOverride?: Uint8Array + + /** + * Override the base persistence provider. + * Defaults to LocalStoragePersistence, which is fine for most implementations + */ + basePersistence: Persistence + /** + * Whether or not the persistence provider should encrypt the values. + * Only disable if you are using a secure datastore that already has encryption + */ + disablePersistenceEncryption: boolean } export type LegacyOptions = { @@ -195,10 +207,13 @@ export function defaultOptions(opts?: Partial): ClientOptions { maxContentSize: MaxContentSize, persistConversations: true, skipContactPublishing: false, + basePersistence: new LocalStoragePersistence(), + disablePersistenceEncryption: false, keystoreProviders: defaultKeystoreProviders(), apiClientFactory: (options: NetworkOptions) => createApiClientFromOptions(options), } + if (opts?.codecs) { opts.codecs = _defaultOptions.codecs.concat(opts.codecs) } diff --git a/src/keystore/providers/helpers.ts b/src/keystore/providers/helpers.ts index 92b8f3a14..3911d9021 100644 --- a/src/keystore/providers/helpers.ts +++ b/src/keystore/providers/helpers.ts @@ -1,10 +1,6 @@ import { PrivateKeyBundleV2 } from './../../crypto/PrivateKeyBundle' import { PrivateKeyBundleV1 } from '../../crypto/PrivateKeyBundle' -import { - EncryptedPersistence, - LocalStoragePersistence, - PrefixedPersistence, -} from '../persistence' +import { EncryptedPersistence, PrefixedPersistence } from '../persistence' import { KeystoreProviderOptions } from './interfaces' export const buildPersistenceFromOptions = async ( @@ -16,9 +12,13 @@ export const buildPersistenceFromOptions = async ( } const address = await keys.identityKey.publicKey.walletSignatureAddress() const prefix = `xmtp/${opts.env}/${address}/` + const basePersistence = opts.basePersistence + const shouldEncrypt = !opts.disablePersistenceEncryption return new PrefixedPersistence( prefix, - new EncryptedPersistence(new LocalStoragePersistence(), keys.identityKey) + shouldEncrypt + ? new EncryptedPersistence(basePersistence, keys.identityKey) + : basePersistence ) } diff --git a/src/keystore/providers/interfaces.ts b/src/keystore/providers/interfaces.ts index 9837786a9..50570aaa8 100644 --- a/src/keystore/providers/interfaces.ts +++ b/src/keystore/providers/interfaces.ts @@ -2,11 +2,14 @@ import type { XmtpEnv, PreEventCallbackOptions } from '../../Client' import type { Signer } from '../../types/Signer' import type { Keystore } from '../interfaces' import type { IApiClient } from '../../ApiClient' +import { Persistence } from '../persistence' export type KeystoreProviderOptions = { env: XmtpEnv persistConversations: boolean privateKeyOverride?: Uint8Array + basePersistence: Persistence + disablePersistenceEncryption: boolean } & PreEventCallbackOptions /** From f9ecfee8e27689b99cc5a79ff74fdc8623548fe1 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 14:19:21 -0700 Subject: [PATCH 068/137] build: rename exported type --- src/ApiClient.ts | 4 +-- src/Client.ts | 32 +++++++++---------- src/index.ts | 3 +- .../providers/NetworkKeystoreProvider.ts | 4 +-- src/keystore/providers/interfaces.ts | 4 +-- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/ApiClient.ts b/src/ApiClient.ts index 80768ef07..5d5eb9f02 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -115,7 +115,7 @@ const isAuthError = (err?: GrpcError | Error): boolean => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const isNotAuthError = (err?: Error): boolean => !isAuthError(err) -export interface IApiClient { +export interface ApiClient { query( params: QueryParams, options: QueryAllOptions @@ -145,7 +145,7 @@ export interface IApiClient { * ApiClient provides a wrapper for calling the GRPC Gateway generated code. * It adds some helpers for dealing with paginated data and automatically retries idempotent calls */ -export default class ApiClient implements IApiClient { +export default class HttpApiClient implements ApiClient { pathPrefix: string maxRetries: number private authCache?: AuthCache diff --git a/src/Client.ts b/src/Client.ts index 08ba0a685..71717d012 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -14,9 +14,9 @@ import { ContentTypeId, ContentCodec } from './MessageContent' import { compress } from './Compression' import { content as proto, messageApi, fetcher } from '@xmtp/proto' import { decodeContactBundle, encodeContactBundle } from './ContactBundle' -import ApiClient, { +import HttpApiClient, { ApiUrls, - IApiClient, + ApiClient, PublishParams, SortDirection, } from './ApiClient' @@ -111,7 +111,7 @@ export type NetworkOptions = { */ skipContactPublishing: boolean - apiClientFactory: (options: NetworkOptions) => IApiClient + apiClientFactory: (options: NetworkOptions) => ApiClient } export type ContentOptions = { @@ -197,7 +197,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { skipContactPublishing: false, keystoreProviders: defaultKeystoreProviders(), apiClientFactory: (options: NetworkOptions) => - createApiClientFromOptions(options), + createHttpApiClientFromOptions(options), } if (opts?.codecs) { opts.codecs = _defaultOptions.codecs.concat(opts.codecs) @@ -213,7 +213,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { export default class Client { address: string keystore: Keystore - apiClient: IApiClient + apiClient: ApiClient contacts: Set // address which we have connected to publicKeyBundle: PublicKeyBundle private knownPublicKeyBundles: Map< @@ -229,7 +229,7 @@ export default class Client { constructor( publicKeyBundle: PublicKeyBundle, - apiClient: IApiClient, + apiClient: ApiClient, backupClient: BackupClient, keystore: Keystore ) { @@ -494,6 +494,9 @@ export default class Client { opts?: Partial ): Promise { const apiUrl = opts?.apiUrl || ApiUrls[opts?.env || 'dev'] + const apiClient = new HttpApiClient(apiUrl, { + appVersion: opts?.appVersion, + }) if (Array.isArray(peerAddress)) { const rawPeerAddresses: string[] = peerAddress @@ -504,7 +507,7 @@ export default class Client { // The getUserContactsFromNetwork will return false instead of throwing // on invalid envelopes const contacts = await getUserContactsFromNetwork( - new ApiClient(apiUrl, { appVersion: opts?.appVersion }), + apiClient, normalizedPeerAddresses ) return contacts.map((contact) => !!contact) @@ -514,10 +517,7 @@ export default class Client { } catch (e) { return false } - const keyBundle = await getUserContactFromNetwork( - new ApiClient(apiUrl, { appVersion: opts?.appVersion }), - peerAddress - ) + const keyBundle = await getUserContactFromNetwork(apiClient, peerAddress) return keyBundle !== undefined } @@ -669,16 +669,16 @@ export default class Client { } } -function createApiClientFromOptions(options: NetworkOptions): ApiClient { +function createHttpApiClientFromOptions(options: NetworkOptions): ApiClient { const apiUrl = options.apiUrl || ApiUrls[options.env] - return new ApiClient(apiUrl, { appVersion: options.appVersion }) + return new HttpApiClient(apiUrl, { appVersion: options.appVersion }) } /** * Retrieve a key bundle from given user's contact topic */ async function getUserContactFromNetwork( - apiClient: IApiClient, + apiClient: ApiClient, peerAddress: string ): Promise { const stream = apiClient.queryIterator( @@ -707,7 +707,7 @@ async function getUserContactFromNetwork( * Retrieve a list of key bundles given a list of user addresses */ async function getUserContactsFromNetwork( - apiClient: IApiClient, + apiClient: ApiClient, peerAddresses: string[] ): Promise<(PublicKeyBundle | SignedPublicKeyBundle | undefined)[]> { const userContactTopics = peerAddresses.map(buildUserContactTopic) @@ -771,7 +771,7 @@ export function defaultKeystoreProviders(): KeystoreProvider[] { */ async function bootstrapKeystore( opts: ClientOptions, - apiClient: IApiClient, + apiClient: ApiClient, wallet: Signer | null ): Promise { for (const provider of opts.keystoreProviders) { diff --git a/src/index.ts b/src/index.ts index 77553f796..cc9b66ec1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,9 +59,10 @@ export { ContentTypeComposite, } from './codecs/Composite' export { + default as HttpApiClient, ApiUrls, SortDirection, - IApiClient, + ApiClient, QueryParams, QueryAllOptions, QueryStreamOptions, diff --git a/src/keystore/providers/NetworkKeystoreProvider.ts b/src/keystore/providers/NetworkKeystoreProvider.ts index 6880338cb..798dff7b0 100644 --- a/src/keystore/providers/NetworkKeystoreProvider.ts +++ b/src/keystore/providers/NetworkKeystoreProvider.ts @@ -1,5 +1,5 @@ import { Signer } from './../../types/Signer' -import type { IApiClient } from '../../ApiClient' +import type { ApiClient } from '../../ApiClient' import { KeystoreProvider, KeystoreProviderOptions } from './interfaces' import NetworkKeyLoader from './NetworkKeyManager' import { KeystoreProviderUnavailableError } from './errors' @@ -16,7 +16,7 @@ import { buildPersistenceFromOptions } from './helpers' export default class NetworkKeystoreProvider implements KeystoreProvider { async newKeystore( opts: KeystoreProviderOptions, - apiClient: IApiClient, + apiClient: ApiClient, wallet?: Signer ): Promise { if (!wallet) { diff --git a/src/keystore/providers/interfaces.ts b/src/keystore/providers/interfaces.ts index 9837786a9..cebc5bd83 100644 --- a/src/keystore/providers/interfaces.ts +++ b/src/keystore/providers/interfaces.ts @@ -1,7 +1,7 @@ import type { XmtpEnv, PreEventCallbackOptions } from '../../Client' import type { Signer } from '../../types/Signer' import type { Keystore } from '../interfaces' -import type { IApiClient } from '../../ApiClient' +import type { ApiClient } from '../../ApiClient' export type KeystoreProviderOptions = { env: XmtpEnv @@ -16,7 +16,7 @@ export type KeystoreProviderOptions = { export interface KeystoreProvider { newKeystore( opts: KeystoreProviderOptions, - apiClient: IApiClient, + apiClient: ApiClient, wallet?: Signer ): Promise } From 8b106cb78069571b12d5e7b8f287fcd300887475 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 14:26:44 -0700 Subject: [PATCH 069/137] test: add test for pluggability --- src/Client.ts | 3 +-- test/Client.test.ts | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 71717d012..7abd3b8d5 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -196,8 +196,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { persistConversations: true, skipContactPublishing: false, keystoreProviders: defaultKeystoreProviders(), - apiClientFactory: (options: NetworkOptions) => - createHttpApiClientFromOptions(options), + apiClientFactory: createHttpApiClientFromOptions, } if (opts?.codecs) { opts.codecs = _defaultOptions.codecs.concat(opts.codecs) diff --git a/test/Client.test.ts b/test/Client.test.ts index 8117c22be..72e558379 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -5,16 +5,16 @@ import { newDevClient, waitForUserContact, newLocalHostClientWithCustomWallet, - sleep, } from './helpers' import { buildUserContactTopic } from '../src/utils' import Client, { ClientOptions } from '../src/Client' -import { Compression } from '../src' +import { Compression, HttpApiClient, PublishParams } from '../src' import NetworkKeyManager from '../src/keystore/providers/NetworkKeyManager' import TopicPersistence from '../src/keystore/persistence/TopicPersistence' import { PrivateKeyBundleV1 } from '../src/crypto' import { Wallet } from 'ethers' import { NetworkKeystoreProvider } from '../src/keystore/providers' +import { PublishResponse } from '@xmtp/proto/ts/dist/types/message_api/v1/message_api.pb' type TestCase = { name: string @@ -318,4 +318,22 @@ describe('ClientOptions', () => { }) }) }) + + describe('Pluggable API client', () => { + it('allows you to specify a custom API client factory', async () => { + const expectedError = new Error('CustomApiClient') + class CustomApiClient extends HttpApiClient { + publish(messages: PublishParams[]): Promise { + return Promise.reject(expectedError) + } + } + + const c = newLocalHostClient({ + apiClientFactory: (opts) => { + return new CustomApiClient('foo') + }, + }) + expect(c).rejects.toThrow(expectedError) + }) + }) }) From c563bd85fa7dbe037b0572492cc71289b003d210 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 14:42:33 -0700 Subject: [PATCH 070/137] fix: handle all base64 decoding in the ApiClient --- src/ApiClient.ts | 22 ++++++++++++++++---- src/Client.ts | 9 +++----- src/Invitation.ts | 7 ++----- src/conversations/Conversation.ts | 12 +++++------ src/conversations/Conversations.ts | 19 ++++++++++------- src/keystore/persistence/TopicPersistence.ts | 10 ++++----- test/conversations/Conversation.test.ts | 4 +--- 7 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/ApiClient.ts b/src/ApiClient.ts index 5d5eb9f02..7063d8132 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -1,6 +1,6 @@ import { messageApi } from '@xmtp/proto' import { NotifyStreamEntityArrival } from '@xmtp/proto/ts/dist/types/fetch.pb' -import { retry, sleep, toNanoString } from './utils' +import { b64Decode, retry, sleep, toNanoString } from './utils' import AuthCache from './authn/AuthCache' import { Authenticator } from './authn' import packageJson from '../package.json' @@ -141,6 +141,16 @@ export interface ApiClient { ): void } +const normalizeEnvelope = (env: messageApi.Envelope): messageApi.Envelope => { + if (!env.message || !env.message.length) { + return env + } + if (typeof env.message === 'string') { + env.message = b64Decode(env.message) + } + return env +} + /** * ApiClient provides a wrapper for calling the GRPC Gateway generated code. * It adds some helpers for dealing with paginated data and automatically retries idempotent calls @@ -360,7 +370,7 @@ export default class HttpApiClient implements ApiClient { }) if (result.envelopes?.length) { - yield result.envelopes + yield result.envelopes.map(normalizeEnvelope) } else { return } @@ -421,7 +431,7 @@ export default class HttpApiClient implements ApiClient { } for (const queryResponse of batchResponse.responses) { if (queryResponse.envelopes) { - allEnvelopes.push(queryResponse.envelopes) + allEnvelopes.push(queryResponse.envelopes.map(normalizeEnvelope)) } else { // If no envelopes provided, then add an empty list allEnvelopes.push([]) @@ -469,7 +479,11 @@ export default class HttpApiClient implements ApiClient { throw new Error('Must provide list of contentTopics to subscribe to') } - return this._subscribe(params, callback, onConnectionLost) + return this._subscribe( + params, + (env) => callback(normalizeEnvelope(env)), + onConnectionLost + ) } private getToken(): Promise { diff --git a/src/Client.ts b/src/Client.ts index 7abd3b8d5..80f789974 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -12,7 +12,7 @@ import { Conversations } from './conversations' import { ContentTypeText, TextCodec } from './codecs/Text' import { ContentTypeId, ContentCodec } from './MessageContent' import { compress } from './Compression' -import { content as proto, messageApi, fetcher } from '@xmtp/proto' +import { content as proto, messageApi } from '@xmtp/proto' import { decodeContactBundle, encodeContactBundle } from './ContactBundle' import HttpApiClient, { ApiUrls, @@ -33,7 +33,6 @@ import { StaticKeystoreProvider, } from './keystore/providers' const { Compression } = proto -const { b64Decode } = fetcher // eslint-disable @typescript-eslint/explicit-module-boundary-types // eslint-disable @typescript-eslint/no-explicit-any @@ -687,7 +686,7 @@ async function getUserContactFromNetwork( for await (const env of stream) { if (!env.message) continue - const keyBundle = decodeContactBundle(b64Decode(env.message.toString())) + const keyBundle = decodeContactBundle(env.message) let address: string | undefined try { address = await keyBundle?.walletSignatureAddress() @@ -729,9 +728,7 @@ async function getUserContactsFromNetwork( for (const env of envelopes) { if (!env.message) continue try { - const keyBundle = decodeContactBundle( - b64Decode(env.message.toString()) - ) + const keyBundle = decodeContactBundle(env.message) const signingAddress = await keyBundle?.walletSignatureAddress() if (address === signingAddress) { return keyBundle diff --git a/src/Invitation.ts b/src/Invitation.ts index 4dabc1b73..b9286d2b7 100644 --- a/src/Invitation.ts +++ b/src/Invitation.ts @@ -1,12 +1,11 @@ import Long from 'long' import { SignedPublicKeyBundle } from './crypto/PublicKeyBundle' -import { messageApi, invitation, fetcher } from '@xmtp/proto' +import { messageApi, invitation } from '@xmtp/proto' import crypto from './crypto/crypto' import Ciphertext from './crypto/Ciphertext' import { decrypt, encrypt } from './crypto' import { PrivateKeyBundleV2 } from './crypto/PrivateKeyBundle' import { dateToNs, buildDirectMessageTopicV2 } from './utils' -const { b64Decode } = fetcher export type InvitationContext = { conversationId: string @@ -205,9 +204,7 @@ export class SealedInvitation implements invitation.SealedInvitation { if (!env.message || !env.timestampNs) { throw new Error('invalid invitation envelope') } - const sealed = SealedInvitation.fromBytes( - b64Decode(env.message as unknown as string) - ) + const sealed = SealedInvitation.fromBytes(env.message) const envelopeTime = Long.fromString(env.timestampNs) const headerTime = sealed.v1?.header.createdNs if (!headerTime || !headerTime.equals(envelopeTime)) { diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 3e32d9813..2aa1b4e1d 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -4,7 +4,6 @@ import { buildDirectMessageTopic, dateToNs, concat, - b64Decode, toNanoString, } from '../utils' import { utils } from 'ethers' @@ -279,8 +278,10 @@ export class ConversationV1 implements Conversation { message, contentTopic, }: messageApi.Envelope): Promise { - const messageBytes = b64Decode(message as unknown as string) - const decoded = await MessageV1.fromBytes(messageBytes) + if (!message || !message.length) { + throw new Error('empty envelope') + } + const decoded = await MessageV1.fromBytes(message) const { senderAddress, recipientAddress } = decoded // Filter for topics @@ -716,8 +717,7 @@ export class ConversationV2 implements Conversation { if (!env.message || !env.contentTopic) { throw new Error('empty envelope') } - const messageBytes = b64Decode(env.message.toString()) - const msg = message.Message.decode(messageBytes) + const msg = message.Message.decode(env.message) if (!msg.v2) { throw new Error('unknown message version') @@ -728,7 +728,7 @@ export class ConversationV2 implements Conversation { throw new Error('topic mismatch') } - return MessageV2.create(msg, header, messageBytes) + return MessageV2.create(msg, header, env.message) } async decodeMessage(env: messageApi.Envelope): Promise { diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index e6e47aabf..dac749330 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -9,7 +9,6 @@ import { MessageV1, DecodedMessage } from '../Message' import Stream from '../Stream' import Client from '../Client' import { - b64Decode, buildUserIntroTopic, buildUserInviteTopic, dateToNs, @@ -191,7 +190,7 @@ export default class Conversations { ): Promise { const { responses } = await this.client.keystore.saveInvites({ requests: envelopes.map((env) => ({ - payload: b64Decode(env.message as unknown as string), + payload: env.message as Uint8Array, timestampNs: Long.fromString(env.timestampNs as string), contentTopic: env.contentTopic as string, })), @@ -257,8 +256,10 @@ export default class Conversations { const decodeConversation = async (env: messageApi.Envelope) => { if (env.contentTopic === introTopic) { - const messageBytes = b64Decode(env.message as unknown as string) - const msg = await MessageV1.fromBytes(messageBytes) + if (!env.message) { + throw new Error('empty envelope') + } + const msg = await MessageV1.fromBytes(env.message) const peerAddress = this.getPeerAddress(msg) if (!newPeer(peerAddress)) { return undefined @@ -308,13 +309,12 @@ export default class Conversations { env: messageApi.Envelope ): Promise => { const contentTopic = env.contentTopic - if (!contentTopic) { + if (!contentTopic || !env.message) { return null } if (contentTopic === introTopic) { - const messageBytes = b64Decode(env.message as unknown as string) - const msg = await MessageV1.fromBytes(messageBytes) + const msg = await MessageV1.fromBytes(env.message) if (!messageHasHeaders(msg)) { return null } @@ -420,7 +420,10 @@ export default class Conversations { const messages = await this.client.listEnvelopes( topic, (env) => { - return MessageV1.fromBytes(b64Decode(env.message as unknown as string)) + if (!env.message) { + throw new Error('empty envelope') + } + return MessageV1.fromBytes(env.message) }, opts ) diff --git a/src/keystore/persistence/TopicPersistence.ts b/src/keystore/persistence/TopicPersistence.ts index d9dede441..65fc04ca8 100644 --- a/src/keystore/persistence/TopicPersistence.ts +++ b/src/keystore/persistence/TopicPersistence.ts @@ -1,13 +1,12 @@ import { messageApi } from '@xmtp/proto' -import type { IApiClient } from '../../ApiClient' +import type { ApiClient } from '../../ApiClient' import { Authenticator } from '../../authn' -import { b64Decode } from '../../utils/bytes' import { buildUserPrivateStoreTopic } from '../../utils/topic' import { Persistence } from './interface' export default class TopicPersistence implements Persistence { - apiClient: IApiClient - constructor(apiClient: IApiClient) { + apiClient: ApiClient + constructor(apiClient: ApiClient) { this.apiClient = apiClient } @@ -22,8 +21,7 @@ export default class TopicPersistence implements Persistence { )) { if (!env.message) continue try { - const bytes = b64Decode(env.message.toString()) - return Uint8Array.from(bytes) + return Uint8Array.from(env.message) } catch (e) { console.log(e) } diff --git a/test/conversations/Conversation.test.ts b/test/conversations/Conversation.test.ts index 5f2fa4e45..d991511ff 100644 --- a/test/conversations/Conversation.test.ts +++ b/test/conversations/Conversation.test.ts @@ -352,9 +352,7 @@ describe('conversation', () => { }, { limit: 1 } ) - const messageBytes = fetcher.b64Decode( - envelopes[0].message as unknown as string - ) + const messageBytes = envelopes[0].message as Uint8Array const decoded = await MessageV1.fromBytes(messageBytes) const decrypted = await decoded.decrypt( alice.keystore, From 4ddf4f6911d9335c217a8a8ca7055e2f6b4a68f2 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 14:50:28 -0700 Subject: [PATCH 071/137] test: use wildcard matcher --- test/ApiClient.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ApiClient.test.ts b/test/ApiClient.test.ts index 1295e909c..c8691a0fb 100644 --- a/test/ApiClient.test.ts +++ b/test/ApiClient.test.ts @@ -258,7 +258,7 @@ describe('Subscribe', () => { const unsubscribeFn = client.subscribe(req, cb) await sleep(10) expect(numEnvelopes).toBe(2) - expect(subscribeMock).toBeCalledWith(req, cb, { + expect(subscribeMock).toBeCalledWith(req, expect.anything(), { pathPrefix: PATH_PREFIX, signal: expect.anything(), mode: 'cors', @@ -307,7 +307,7 @@ describe('Subscribe', () => { // Resubscribing triggers an info log expect(consoleInfo).toBeCalledTimes(1) expect(subscribeMock).toBeCalledTimes(2) - expect(subscribeMock).toBeCalledWith(req, cb, { + expect(subscribeMock).toBeCalledWith(req, expect.anything(), { pathPrefix: PATH_PREFIX, signal: expect.anything(), mode: 'cors', @@ -352,7 +352,7 @@ describe('Subscribe', () => { // Resubscribing triggers an info log expect(consoleInfo).toBeCalledTimes(1) expect(subscribeMock).toBeCalledTimes(2) - expect(subscribeMock).toBeCalledWith(req, cb, { + expect(subscribeMock).toBeCalledWith(req, expect.anything(), { pathPrefix: PATH_PREFIX, signal: expect.anything(), mode: 'cors', From ae32af8b87847a5e38f8a9242c4ce1d1e1c7abf5 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 15:06:47 -0700 Subject: [PATCH 072/137] test: use real ApiUrl --- test/Client.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Client.test.ts b/test/Client.test.ts index 72e558379..c326a0d42 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -8,7 +8,7 @@ import { } from './helpers' import { buildUserContactTopic } from '../src/utils' import Client, { ClientOptions } from '../src/Client' -import { Compression, HttpApiClient, PublishParams } from '../src' +import { ApiUrls, Compression, HttpApiClient, PublishParams } from '../src' import NetworkKeyManager from '../src/keystore/providers/NetworkKeyManager' import TopicPersistence from '../src/keystore/persistence/TopicPersistence' import { PrivateKeyBundleV1 } from '../src/crypto' @@ -330,7 +330,7 @@ describe('ClientOptions', () => { const c = newLocalHostClient({ apiClientFactory: (opts) => { - return new CustomApiClient('foo') + return new CustomApiClient(ApiUrls.local) }, }) expect(c).rejects.toThrow(expectedError) From d1ff3ebd7713f7af47675d07e1af175a79a69fb8 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 18:40:08 -0700 Subject: [PATCH 073/137] test: add base persistence --- test/keystore/providers/helpers.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/keystore/providers/helpers.ts b/test/keystore/providers/helpers.ts index 3e6d88a14..394812819 100644 --- a/test/keystore/providers/helpers.ts +++ b/test/keystore/providers/helpers.ts @@ -1,8 +1,13 @@ +import { LocalStoragePersistence } from '../../../src' + export const testProviderOptions = ( privateKeyOverride = undefined, - persistConversations = false + persistConversations = false, + basePersistence = new LocalStoragePersistence() ) => ({ env: 'local' as const, persistConversations, privateKeyOverride, + basePersistence, + disablePersistenceEncryption: false, }) From f49c83915fc8d02b99d3dfd79bcef4906730d13d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 21 Aug 2023 18:52:53 -0700 Subject: [PATCH 074/137] test: handle new provider options --- .../KeyGeneratorKeystoreProvider.test.ts | 8 ++--- .../providers/NetworkKeyManager.test.ts | 5 +-- .../providers/NetworkKeystoreProvider.test.ts | 8 ++--- .../providers/StaticKeystoreProvider.test.ts | 35 +++++++++++-------- test/keystore/providers/helpers.ts | 10 +++--- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/test/keystore/providers/KeyGeneratorKeystoreProvider.test.ts b/test/keystore/providers/KeyGeneratorKeystoreProvider.test.ts index 50f0716ca..bf9c409aa 100644 --- a/test/keystore/providers/KeyGeneratorKeystoreProvider.test.ts +++ b/test/keystore/providers/KeyGeneratorKeystoreProvider.test.ts @@ -18,7 +18,7 @@ describe('KeyGeneratorKeystoreProvider', () => { it('creates a key when wallet supplied', async () => { const provider = new KeyGeneratorKeystoreProvider() const keystore = await provider.newKeystore( - testProviderOptions(), + testProviderOptions({}), apiClient, wallet ) @@ -28,7 +28,7 @@ describe('KeyGeneratorKeystoreProvider', () => { it('throws KeystoreProviderUnavailableError when no wallet supplied', async () => { const provider = new KeyGeneratorKeystoreProvider() const prom = provider.newKeystore( - testProviderOptions(), + testProviderOptions({}), apiClient, undefined ) @@ -39,7 +39,7 @@ describe('KeyGeneratorKeystoreProvider', () => { const provider = new KeyGeneratorKeystoreProvider() const preCreateIdentityCallback = jest.fn() const keystore = await provider.newKeystore( - { ...testProviderOptions(), preCreateIdentityCallback }, + { ...testProviderOptions({}), preCreateIdentityCallback }, apiClient, wallet ) @@ -51,7 +51,7 @@ describe('KeyGeneratorKeystoreProvider', () => { const provider = new KeyGeneratorKeystoreProvider() const preEnableIdentityCallback = jest.fn() const keystore = await provider.newKeystore( - { ...testProviderOptions(), preEnableIdentityCallback }, + { ...testProviderOptions({}), preEnableIdentityCallback }, apiClient, wallet ) diff --git a/test/keystore/providers/NetworkKeyManager.test.ts b/test/keystore/providers/NetworkKeyManager.test.ts index 6ab6ebcf6..5ef0d414f 100644 --- a/test/keystore/providers/NetworkKeyManager.test.ts +++ b/test/keystore/providers/NetworkKeyManager.test.ts @@ -6,6 +6,7 @@ import { buildPersistenceFromOptions } from '../../../src/keystore/providers/hel import NetworkKeyManager from '../../../src/keystore/providers/NetworkKeyManager' import { Signer } from '../../../src/types/Signer' import { newWallet, pollFor, sleep, wrapAsLedgerWallet } from '../../helpers' +import { testProviderOptions } from './helpers' describe('NetworkKeyManager', () => { let wallet: Signer @@ -100,13 +101,13 @@ describe('NetworkKeyManager', () => { it('respects the options provided', async () => { const bundle = await PrivateKeyBundleV1.generate(wallet) const shouldBeUndefined = await buildPersistenceFromOptions( - { persistConversations: false, env: 'local' }, + testProviderOptions({ persistConversations: false }), bundle ) expect(shouldBeUndefined).toBeUndefined() const shouldBeDefined = await buildPersistenceFromOptions( - { persistConversations: true, env: 'local' }, + testProviderOptions({ persistConversations: true }), bundle ) expect(shouldBeDefined).toBeInstanceOf(PrefixedPersistence) diff --git a/test/keystore/providers/NetworkKeystoreProvider.test.ts b/test/keystore/providers/NetworkKeystoreProvider.test.ts index e3e0a33a6..51490dcaa 100644 --- a/test/keystore/providers/NetworkKeystoreProvider.test.ts +++ b/test/keystore/providers/NetworkKeystoreProvider.test.ts @@ -28,7 +28,7 @@ describe('NetworkKeystoreProvider', () => { it('fails gracefully when no keys are found', async () => { const provider = new NetworkKeystoreProvider() expect( - provider.newKeystore(testProviderOptions(), apiClient, wallet) + provider.newKeystore(testProviderOptions({}), apiClient, wallet) ).rejects.toThrow(KeystoreProviderUnavailableError) }) @@ -41,7 +41,7 @@ describe('NetworkKeystoreProvider', () => { const provider = new NetworkKeystoreProvider() const keystore = await provider.newKeystore( - testProviderOptions(), + testProviderOptions({}), apiClient, wallet ) @@ -74,7 +74,7 @@ describe('NetworkKeystoreProvider', () => { // Now try and load it const provider = new NetworkKeystoreProvider() const keystore = await provider.newKeystore( - testProviderOptions(), + testProviderOptions({}), apiClient, wallet ) @@ -91,7 +91,7 @@ describe('NetworkKeystoreProvider', () => { const provider = new NetworkKeystoreProvider() const mockNotifier = jest.fn() await provider.newKeystore( - { ...testProviderOptions(), preEnableIdentityCallback: mockNotifier }, + { ...testProviderOptions({}), preEnableIdentityCallback: mockNotifier }, apiClient, wallet ) diff --git a/test/keystore/providers/StaticKeystoreProvider.test.ts b/test/keystore/providers/StaticKeystoreProvider.test.ts index 880ec4159..c46b06288 100644 --- a/test/keystore/providers/StaticKeystoreProvider.test.ts +++ b/test/keystore/providers/StaticKeystoreProvider.test.ts @@ -1,6 +1,7 @@ import { privateKey } from '@xmtp/proto' import { PrivateKeyBundleV1 } from '../../../src/crypto' import { newWallet } from '../../helpers' +import { testProviderOptions } from './helpers' import StaticKeystoreProvider from '../../../src/keystore/providers/StaticKeystoreProvider' import { KeystoreProviderUnavailableError } from '../../../src/keystore/providers/errors' @@ -14,31 +15,37 @@ describe('StaticKeystoreProvider', () => { v2: undefined, }).finish() const provider = new StaticKeystoreProvider() - const keystore = await provider.newKeystore({ - privateKeyOverride: keyBytes, - env: ENV, - persistConversations: false, - }) + const keystore = await provider.newKeystore( + testProviderOptions({ + privateKeyOverride: keyBytes, + env: ENV, + persistConversations: false, + }) + ) expect(keystore).not.toBeNull() }) it('throws with an unset key', async () => { expect( - new StaticKeystoreProvider().newKeystore({ - env: ENV, - persistConversations: false, - }) + new StaticKeystoreProvider().newKeystore( + testProviderOptions({ + env: ENV, + persistConversations: false, + }) + ) ).rejects.toThrow(KeystoreProviderUnavailableError) }) it('fails with an invalid key', async () => { expect( - new StaticKeystoreProvider().newKeystore({ - privateKeyOverride: Uint8Array.from([1, 2, 3]), - env: ENV, - persistConversations: false, - }) + new StaticKeystoreProvider().newKeystore( + testProviderOptions({ + privateKeyOverride: Uint8Array.from([1, 2, 3]), + env: ENV, + persistConversations: false, + }) + ) ).rejects.toThrow() }) }) diff --git a/test/keystore/providers/helpers.ts b/test/keystore/providers/helpers.ts index 394812819..5b0ac5148 100644 --- a/test/keystore/providers/helpers.ts +++ b/test/keystore/providers/helpers.ts @@ -1,11 +1,13 @@ import { LocalStoragePersistence } from '../../../src' +import { KeystoreProviderOptions } from '../../../src/keystore/providers' -export const testProviderOptions = ( +export const testProviderOptions = ({ privateKeyOverride = undefined, persistConversations = false, - basePersistence = new LocalStoragePersistence() -) => ({ - env: 'local' as const, + basePersistence = new LocalStoragePersistence(), + env = 'local' as const, +}: Partial) => ({ + env, persistConversations, privateKeyOverride, basePersistence, From d1d49b1c3d82ba5c829d1dfd892db85cffe02cd8 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 22 Aug 2023 11:06:25 -0700 Subject: [PATCH 075/137] build: add retry fn --- src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index cc9b66ec1..6aea3fafa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -import { Authenticator } from './authn/interfaces' export { Message, DecodedMessage, @@ -73,10 +72,11 @@ export { UnsubscribeFn, OnConnectionLostCallback, } from './ApiClient' -export { Authenticator, AuthCache } from './authn' +export { Authenticator, AuthCache, LocalAuthenticator } from './authn' export { nsToDate, dateToNs, + retry, fromNanoString, toNanoString, mapPaginatedStream, From 0ffb6870629dcbd410f0f36bd4558a480d89a724 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 22 Aug 2023 11:07:49 -0700 Subject: [PATCH 076/137] feat: mark as breaking\nBREAKING CHANGE: alters return type of messages from ApiClient From be4b97ff1eda41ac877cfa3e91e5535a9c6ae3e7 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 22 Aug 2023 14:26:35 -0700 Subject: [PATCH 077/137] feat: add subscription manager BREAKING CHANGE: changes return type of subscribe API --- src/ApiClient.ts | 19 ++++++++++++++----- src/Stream.ts | 25 +++++++++++++++++-------- src/index.ts | 1 + test/ApiClient.test.ts | 12 ++++++------ 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/ApiClient.ts b/src/ApiClient.ts index 7063d8132..1859f6124 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -92,6 +92,13 @@ export type SubscribeCallback = NotifyStreamEntityArrival export type UnsubscribeFn = () => Promise +export type UpdateContentTopics = (topics: string[]) => Promise + +export type SubscriptionManager = { + unsubscribe: UnsubscribeFn + updateContentTopics?: UpdateContentTopics +} + export type OnConnectionLostCallback = () => void const isAbortError = (err?: Error): boolean => { @@ -132,7 +139,7 @@ export interface ApiClient { params: SubscribeParams, callback: SubscribeCallback, onConnectionLost?: OnConnectionLostCallback - ): UnsubscribeFn + ): SubscriptionManager publish(messages: PublishParams[]): ReturnType batchQuery(queries: Query[]): Promise setAuthenticator( @@ -256,7 +263,7 @@ export default class HttpApiClient implements ApiClient { req: messageApi.SubscribeRequest, cb: NotifyStreamEntityArrival, onConnectionLost?: OnConnectionLostCallback - ): UnsubscribeFn { + ): SubscriptionManager { const abortController = new AbortController() const doSubscribe = async () => { @@ -298,8 +305,10 @@ export default class HttpApiClient implements ApiClient { } doSubscribe() - return async () => { - abortController?.abort() + return { + unsubscribe: async () => { + abortController?.abort() + }, } } @@ -474,7 +483,7 @@ export default class HttpApiClient implements ApiClient { params: SubscribeParams, callback: SubscribeCallback, onConnectionLost?: OnConnectionLostCallback - ): UnsubscribeFn { + ): SubscriptionManager { if (!params.contentTopics.length) { throw new Error('Must provide list of contentTopics to subscribe to') } diff --git a/src/Stream.ts b/src/Stream.ts index 67b0d55a2..1beb2e194 100644 --- a/src/Stream.ts +++ b/src/Stream.ts @@ -1,4 +1,8 @@ -import { OnConnectionLostCallback, UnsubscribeFn } from './ApiClient' +import { + OnConnectionLostCallback, + SubscriptionManager, + UnsubscribeFn, +} from './ApiClient' import Client from './Client' import { messageApi } from '@xmtp/proto' @@ -23,7 +27,7 @@ export default class Stream { // if callback is undefined the stream is closed callback: ((env: messageApi.Envelope) => Promise) | undefined - unsubscribeFn?: UnsubscribeFn + subscriptionManager?: SubscriptionManager onConnectionLost?: OnConnectionLostCallback @@ -84,7 +88,7 @@ export default class Stream { throw new Error('Missing callback for stream') } - this.unsubscribeFn = this.client.apiClient.subscribe( + this.subscriptionManager = this.client.apiClient.subscribe( { contentTopics: this.topics, }, @@ -124,8 +128,8 @@ export default class Stream { // https://tc39.es/ecma262/#table-iterator-interface-optional-properties // Note that this means the Stream will be closed after it was used in a for-await-of or yield* or similar. async return(): Promise> { - if (this.unsubscribeFn) { - await this.unsubscribeFn() + if (this.subscriptionManager) { + await this.subscriptionManager.unsubscribe() } if (!this.callback) { return { value: undefined, done: true } @@ -156,12 +160,17 @@ export default class Stream { // Unsubscribe from the existing content topics and resubscribe to the given topics. private async resubscribeToTopics(topics: string[]): Promise { - if (!this.callback || !this.unsubscribeFn) { + if (!this.callback || !this.subscriptionManager) { throw new Error('Missing callback for stream') } - await this.unsubscribeFn() + + if (typeof this.subscriptionManager?.updateContentTopics === 'function') { + return this.subscriptionManager.updateContentTopics(topics) + } + + await this.subscriptionManager.unsubscribe() this.topics = topics - this.unsubscribeFn = this.client.apiClient.subscribe( + this.subscriptionManager = this.client.apiClient.subscribe( { contentTopics: this.topics, }, diff --git a/src/index.ts b/src/index.ts index cc9b66ec1..1fca3e0f1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -68,6 +68,7 @@ export { QueryStreamOptions, Query, PublishParams, + SubscriptionManager, SubscribeParams, SubscribeCallback, UnsubscribeFn, diff --git a/test/ApiClient.test.ts b/test/ApiClient.test.ts index c8691a0fb..698b0101b 100644 --- a/test/ApiClient.test.ts +++ b/test/ApiClient.test.ts @@ -255,7 +255,7 @@ describe('Subscribe', () => { numEnvelopes++ } const req = { contentTopics: [CONTENT_TOPIC] } - const unsubscribeFn = client.subscribe(req, cb) + const subscriptionManager = client.subscribe(req, cb) await sleep(10) expect(numEnvelopes).toBe(2) expect(subscribeMock).toBeCalledWith(req, expect.anything(), { @@ -266,7 +266,7 @@ describe('Subscribe', () => { 'X-Client-Version': 'xmtp-js/' + packageJson.version, }), }) - await unsubscribeFn() + await subscriptionManager.unsubscribe() }) it('should resubscribe on error', async () => { @@ -300,7 +300,7 @@ describe('Subscribe', () => { numDisconnects++ } const req = { contentTopics: [CONTENT_TOPIC] } - const unsubscribeFn = client.subscribe(req, cb, onDisconnect) + const subscriptionManager = client.subscribe(req, cb, onDisconnect) await sleep(1200) expect(numEnvelopes).toBe(2) expect(numDisconnects).toBe(1) @@ -316,7 +316,7 @@ describe('Subscribe', () => { }), }) consoleInfo.mockRestore() - await unsubscribeFn() + await subscriptionManager.unsubscribe() }) it('should resubscribe on completion', async () => { @@ -346,7 +346,7 @@ describe('Subscribe', () => { numEnvelopes++ } const req = { contentTopics: [CONTENT_TOPIC] } - const unsubscribeFn = client.subscribe(req, cb) + const subscriptionManager = client.subscribe(req, cb) await sleep(1200) expect(numEnvelopes).toBe(2) // Resubscribing triggers an info log @@ -361,7 +361,7 @@ describe('Subscribe', () => { }), }) consoleInfo.mockRestore() - await unsubscribeFn() + await subscriptionManager.unsubscribe() }) it('throws when no content topics returned', async () => { From e9dc1d330652567be5e61e67500959078fadd4ef Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 22 Aug 2023 14:33:27 -0700 Subject: [PATCH 078/137] chore: remove unused import --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 1fca3e0f1..929f75af3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,3 @@ -import { Authenticator } from './authn/interfaces' export { Message, DecodedMessage, From 413e02bd2e7ba62ca6d42f69496747d650779aa1 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 08:57:03 -0700 Subject: [PATCH 079/137] test: add a test to ensure persistence is used --- src/Client.ts | 18 +++++++++++++++--- test/Client.test.ts | 23 ++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index cfb718de9..12fc15e35 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -32,7 +32,11 @@ import { NetworkKeystoreProvider, StaticKeystoreProvider, } from './keystore/providers' -import { LocalStoragePersistence, Persistence } from './keystore/persistence' +import { + LocalStoragePersistence, + Persistence, + PrefixedPersistence, +} from './keystore/persistence' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types @@ -229,6 +233,7 @@ export default class Client { apiClient: ApiClient contacts: Set // address which we have connected to publicKeyBundle: PublicKeyBundle + persistence: Persistence private knownPublicKeyBundles: Map< string, PublicKeyBundle | SignedPublicKeyBundle @@ -244,7 +249,8 @@ export default class Client { publicKeyBundle: PublicKeyBundle, apiClient: ApiClient, backupClient: BackupClient, - keystore: Keystore + keystore: Keystore, + persistence: Persistence ) { this.contacts = new Set() this.knownPublicKeyBundles = new Map< @@ -255,6 +261,7 @@ export default class Client { this.keystore = keystore this.publicKeyBundle = publicKeyBundle this.address = publicKeyBundle.walletSignatureAddress() + this.persistence = persistence this._conversations = new Conversations(this) this._codecs = new Map() this._maxContentSize = MaxContentSize @@ -296,11 +303,16 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) + const persistence = new PrefixedPersistence( + `xmtp/${options.env}/${address}/`, + options.basePersistence + ) const client = new Client( publicKeyBundle, apiClient, backupClient, - keystore + keystore, + persistence ) await client.init(options) return client diff --git a/test/Client.test.ts b/test/Client.test.ts index c326a0d42..09d199c4f 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -8,7 +8,13 @@ import { } from './helpers' import { buildUserContactTopic } from '../src/utils' import Client, { ClientOptions } from '../src/Client' -import { ApiUrls, Compression, HttpApiClient, PublishParams } from '../src' +import { + ApiUrls, + Compression, + HttpApiClient, + LocalStoragePersistence, + PublishParams, +} from '../src' import NetworkKeyManager from '../src/keystore/providers/NetworkKeyManager' import TopicPersistence from '../src/keystore/persistence/TopicPersistence' import { PrivateKeyBundleV1 } from '../src/crypto' @@ -336,4 +342,19 @@ describe('ClientOptions', () => { expect(c).rejects.toThrow(expectedError) }) }) + + describe('pluggable persistence', () => { + it('allows for an override of the persistence engine', async () => { + class MyNewPersistence extends LocalStoragePersistence { + async getItem(key: string): Promise { + throw new Error('MyNewPersistence') + } + } + + const c = newLocalHostClient({ + basePersistence: new MyNewPersistence(), + }) + expect(c).rejects.toThrow('MyNewPersistence') + }) + }) }) From de94c3d3df879371d45ae3000b5e95612304efce Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 09:37:38 -0700 Subject: [PATCH 080/137] chore: remove persistence from client --- src/Client.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 12fc15e35..2b741728f 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -233,7 +233,6 @@ export default class Client { apiClient: ApiClient contacts: Set // address which we have connected to publicKeyBundle: PublicKeyBundle - persistence: Persistence private knownPublicKeyBundles: Map< string, PublicKeyBundle | SignedPublicKeyBundle @@ -249,8 +248,7 @@ export default class Client { publicKeyBundle: PublicKeyBundle, apiClient: ApiClient, backupClient: BackupClient, - keystore: Keystore, - persistence: Persistence + keystore: Keystore ) { this.contacts = new Set() this.knownPublicKeyBundles = new Map< @@ -261,7 +259,6 @@ export default class Client { this.keystore = keystore this.publicKeyBundle = publicKeyBundle this.address = publicKeyBundle.walletSignatureAddress() - this.persistence = persistence this._conversations = new Conversations(this) this._codecs = new Map() this._maxContentSize = MaxContentSize @@ -303,16 +300,11 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) - const persistence = new PrefixedPersistence( - `xmtp/${options.env}/${address}/`, - options.basePersistence - ) const client = new Client( publicKeyBundle, apiClient, backupClient, - keystore, - persistence + keystore ) await client.init(options) return client From d5f66fa0c33941bbfddfda77d2588331f5eda638 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 13:36:21 -0700 Subject: [PATCH 081/137] feat: persistence overhaul --- package-lock.json | 638 +++++++----------- src/Client.ts | 8 +- src/index.ts | 3 +- src/keystore/InMemoryKeystore.ts | 65 +- ...stence.ts => BrowserStoragePersistence.ts} | 17 +- .../persistence/InMemoryPersistence.ts | 8 + src/keystore/persistence/index.ts | 3 +- src/keystore/providers/helpers.ts | 6 +- src/keystore/utils.ts | 4 + test/Client.test.ts | 11 +- test/Message.test.ts | 37 +- test/keystore/InMemoryKeystore.test.ts | 110 +-- test/keystore/InviteStore.test.ts | 6 +- test/keystore/encryption.test.ts | 8 +- .../persistence/EncryptedPersistence.test.ts | 16 +- .../LocalStoragePersistence.test.ts | 6 +- .../persistence/PrefixedPersistence.test.ts | 4 +- .../providers/NetworkKeyManager.test.ts | 20 +- test/keystore/providers/helpers.ts | 4 +- 19 files changed, 455 insertions(+), 519 deletions(-) rename src/keystore/persistence/{LocalStoragePersistence.ts => BrowserStoragePersistence.ts} (53%) create mode 100644 src/keystore/persistence/InMemoryPersistence.ts diff --git a/package-lock.json b/package-lock.json index aa9141131..e17a8256d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -162,9 +162,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -214,9 +214,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -691,16 +691,16 @@ "dev": true }, "node_modules/@commitlint/cli": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-16.1.0.tgz", - "integrity": "sha512-x5L1knvA3isRWBRVQx+Q6D45pA9139a2aZQYpxkljMG0dj4UHZkCnsYWpnGalxPxASI7nrI0KedKfS2YeQ55cQ==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-16.3.0.tgz", + "integrity": "sha512-P+kvONlfsuTMnxSwWE1H+ZcPMY3STFaHb2kAacsqoIkNx66O0T7sTpBxpxkMrFPyhkJiLJnJWMhk4bbvYD3BMA==", "dev": true, "dependencies": { - "@commitlint/format": "^16.0.0", - "@commitlint/lint": "^16.0.0", - "@commitlint/load": "^16.1.0", - "@commitlint/read": "^16.0.0", - "@commitlint/types": "^16.0.0", + "@commitlint/format": "^16.2.1", + "@commitlint/lint": "^16.2.4", + "@commitlint/load": "^16.3.0", + "@commitlint/read": "^16.2.1", + "@commitlint/types": "^16.2.1", "lodash": "^4.17.19", "resolve-from": "5.0.0", "resolve-global": "1.0.0", @@ -726,12 +726,12 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-16.1.0.tgz", - "integrity": "sha512-2cHeZPNTuf1JWbMqyA46MkExor5HMSgv8JrdmzEakUbJHUreh35/wN00FJf57qGs134exQW2thiSQ1IJUsVx2Q==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-16.2.1.tgz", + "integrity": "sha512-hogSe0WGg7CKmp4IfNbdNES3Rq3UEI4XRPB8JL4EPgo/ORq5nrGTVzxJh78omibNuB8Ho4501Czb1Er1MoDWpw==", "dev": true, "dependencies": { - "@commitlint/types": "^16.0.0", + "@commitlint/types": "^16.2.1", "ajv": "^6.12.6" }, "engines": { @@ -739,12 +739,12 @@ } }, "node_modules/@commitlint/ensure": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-16.0.0.tgz", - "integrity": "sha512-WdMySU8DCTaq3JPf0tZFCKIUhqxaL54mjduNhu8v4D2AMUVIIQKYMGyvXn94k8begeW6iJkTf9cXBArayskE7Q==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-16.2.1.tgz", + "integrity": "sha512-/h+lBTgf1r5fhbDNHOViLuej38i3rZqTQnBTk+xEg+ehOwQDXUuissQ5GsYXXqI5uGy+261ew++sT4EA3uBJ+A==", "dev": true, "dependencies": { - "@commitlint/types": "^16.0.0", + "@commitlint/types": "^16.2.1", "lodash": "^4.17.19" }, "engines": { @@ -752,21 +752,21 @@ } }, "node_modules/@commitlint/execute-rule": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-16.0.0.tgz", - "integrity": "sha512-8edcCibmBb386x5JTHSPHINwA5L0xPkHQFY8TAuDEt5QyRZY/o5DF8OPHSa5Hx2xJvGaxxuIz4UtAT6IiRDYkw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-16.2.1.tgz", + "integrity": "sha512-oSls82fmUTLM6cl5V3epdVo4gHhbmBFvCvQGHBRdQ50H/690Uq1Dyd7hXMuKITCIdcnr9umyDkr8r5C6HZDF3g==", "dev": true, "engines": { "node": ">=v12" } }, "node_modules/@commitlint/format": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-16.0.0.tgz", - "integrity": "sha512-9yp5NCquXL1jVMKL0ZkRwJf/UHdebvCcMvICuZV00NQGYSAL89O398nhqrqxlbjBhM5EZVq0VGcV5+7r3D4zAA==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-16.2.1.tgz", + "integrity": "sha512-Yyio9bdHWmNDRlEJrxHKglamIk3d6hC0NkEUW6Ti6ipEh2g0BAhy8Od6t4vLhdZRa1I2n+gY13foy+tUgk0i1Q==", "dev": true, "dependencies": { - "@commitlint/types": "^16.0.0", + "@commitlint/types": "^16.2.1", "chalk": "^4.0.0" }, "engines": { @@ -774,46 +774,47 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-16.0.0.tgz", - "integrity": "sha512-gmAQcwIGC/R/Lp0CEb2b5bfGC7MT5rPe09N8kOGjO/NcdNmfFSZMquwrvNJsq9hnAP0skRdHIsqwlkENkN4Lag==", + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-16.2.4.tgz", + "integrity": "sha512-Lxdq9aOAYCOOOjKi58ulbwK/oBiiKz+7Sq0+/SpFIEFwhHkIVugvDvWjh2VRBXmRC/x5lNcjDcYEwS/uYUvlYQ==", "dev": true, "dependencies": { - "@commitlint/types": "^16.0.0", - "semver": "7.3.5" + "@commitlint/types": "^16.2.1", + "semver": "7.3.7" }, "engines": { "node": ">=v12" } }, "node_modules/@commitlint/lint": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-16.0.0.tgz", - "integrity": "sha512-HNl15bRC0h+pLzbMzQC3tM0j1aESXsLYhElqKnXcf5mnCBkBkHzu6WwJW8rZbfxX+YwJmNljN62cPhmdBo8x0A==", + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-16.2.4.tgz", + "integrity": "sha512-AUDuwOxb2eGqsXbTMON3imUGkc1jRdtXrbbohiLSCSk3jFVXgJLTMaEcr39pR00N8nE9uZ+V2sYaiILByZVmxQ==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^16.0.0", - "@commitlint/parse": "^16.0.0", - "@commitlint/rules": "^16.0.0", - "@commitlint/types": "^16.0.0" + "@commitlint/is-ignored": "^16.2.4", + "@commitlint/parse": "^16.2.1", + "@commitlint/rules": "^16.2.4", + "@commitlint/types": "^16.2.1" }, "engines": { "node": ">=v12" } }, "node_modules/@commitlint/load": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-16.1.0.tgz", - "integrity": "sha512-MtlEhKjP8jAF85jjX4mw8DUUwCxKsCgAc865hhpnwxjrfBcmGP7Up2AFE/M3ZMGDmSl1X1TMybQk/zohj8Cqdg==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-16.3.0.tgz", + "integrity": "sha512-3tykjV/iwbkv2FU9DG+NZ/JqmP0Nm3b7aDwgCNQhhKV5P74JAuByULkafnhn+zsFGypG1qMtI5u+BZoa9APm0A==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^16.1.0", - "@commitlint/execute-rule": "^16.0.0", - "@commitlint/resolve-extends": "^16.1.0", - "@commitlint/types": "^16.0.0", + "@commitlint/config-validator": "^16.2.1", + "@commitlint/execute-rule": "^16.2.1", + "@commitlint/resolve-extends": "^16.2.1", + "@commitlint/types": "^16.2.1", + "@types/node": ">=12", "chalk": "^4.0.0", "cosmiconfig": "^7.0.0", - "cosmiconfig-typescript-loader": "^1.0.0", + "cosmiconfig-typescript-loader": "^2.0.0", "lodash": "^4.17.19", "resolve-from": "^5.0.0", "typescript": "^4.4.3" @@ -823,21 +824,21 @@ } }, "node_modules/@commitlint/message": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.0.0.tgz", - "integrity": "sha512-CmK2074SH1Ws6kFMEKOKH/7hMekGVbOD6vb4alCOo2+33ZSLUIX8iNkDYyrw38Jwg6yWUhLjyQLUxREeV+QIUA==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.2.1.tgz", + "integrity": "sha512-2eWX/47rftViYg7a3axYDdrgwKv32mxbycBJT6OQY/MJM7SUfYNYYvbMFOQFaA4xIVZt7t2Alyqslbl6blVwWw==", "dev": true, "engines": { "node": ">=v12" } }, "node_modules/@commitlint/parse": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-16.0.0.tgz", - "integrity": "sha512-F9EjFlMw4MYgBEqoRrWZZKQBzdiJzPBI0qFDFqwUvfQsMmXEREZ242T4R5bFwLINWaALFLHEIa/FXEPa6QxCag==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-16.2.1.tgz", + "integrity": "sha512-2NP2dDQNL378VZYioLrgGVZhWdnJO4nAxQl5LXwYb08nEcN+cgxHN1dJV8OLJ5uxlGJtDeR8UZZ1mnQ1gSAD/g==", "dev": true, "dependencies": { - "@commitlint/types": "^16.0.0", + "@commitlint/types": "^16.2.1", "conventional-changelog-angular": "^5.0.11", "conventional-commits-parser": "^3.2.2" }, @@ -846,13 +847,13 @@ } }, "node_modules/@commitlint/read": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-16.0.0.tgz", - "integrity": "sha512-H4T2zsfmYQK9B+JtoQaCXWBHUhgIJyOzWZjSfuIV9Ce69/OgHoffNpLZPF2lX6yKuDrS1SQFhI/kUCjVc/e4ew==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-16.2.1.tgz", + "integrity": "sha512-tViXGuaxLTrw2r7PiYMQOFA2fueZxnnt0lkOWqKyxT+n2XdEMGYcI9ID5ndJKXnfPGPppD0w/IItKsIXlZ+alw==", "dev": true, "dependencies": { - "@commitlint/top-level": "^16.0.0", - "@commitlint/types": "^16.0.0", + "@commitlint/top-level": "^16.2.1", + "@commitlint/types": "^16.2.1", "fs-extra": "^10.0.0", "git-raw-commits": "^2.0.0" }, @@ -861,13 +862,13 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-16.1.0.tgz", - "integrity": "sha512-8182s6AFoUFX6+FT1PgQDt15nO2ogdR/EN8SYVAdhNXw1rLz8kT5saB/ICw567GuRAUgFTUMGCXy3ctMOXPEDg==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-16.2.1.tgz", + "integrity": "sha512-NbbCMPKTFf2J805kwfP9EO+vV+XvnaHRcBy6ud5dF35dxMsvdJqke54W3XazXF1ZAxC4a3LBy4i/GNVBAthsEg==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^16.1.0", - "@commitlint/types": "^16.0.0", + "@commitlint/config-validator": "^16.2.1", + "@commitlint/types": "^16.2.1", "import-fresh": "^3.0.0", "lodash": "^4.17.19", "resolve-from": "^5.0.0", @@ -878,15 +879,15 @@ } }, "node_modules/@commitlint/rules": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-16.0.0.tgz", - "integrity": "sha512-AOl0y2SBTdJ1bvIv8nwHvQKRT/jC1xb09C5VZwzHoT8sE8F54KDeEzPCwHQFgUcWdGLyS10kkOTAH2MyA8EIlg==", + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-16.2.4.tgz", + "integrity": "sha512-rK5rNBIN2ZQNQK+I6trRPK3dWa0MtaTN4xnwOma1qxa4d5wQMQJtScwTZjTJeallFxhOgbNOgr48AMHkdounVg==", "dev": true, "dependencies": { - "@commitlint/ensure": "^16.0.0", - "@commitlint/message": "^16.0.0", - "@commitlint/to-lines": "^16.0.0", - "@commitlint/types": "^16.0.0", + "@commitlint/ensure": "^16.2.1", + "@commitlint/message": "^16.2.1", + "@commitlint/to-lines": "^16.2.1", + "@commitlint/types": "^16.2.1", "execa": "^5.0.0" }, "engines": { @@ -894,18 +895,18 @@ } }, "node_modules/@commitlint/to-lines": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-16.0.0.tgz", - "integrity": "sha512-iN/qU38TCKU7uKOg6RXLpD49wNiuI0TqMqybHbjefUeP/Jmzxa8ishryj0uLyVdrAl1ZjGeD1ukXGMTtvqz8iA==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-16.2.1.tgz", + "integrity": "sha512-9/VjpYj5j1QeY3eiog1zQWY6axsdWAc0AonUUfyZ7B0MVcRI0R56YsHAfzF6uK/g/WwPZaoe4Lb1QCyDVnpVaQ==", "dev": true, "engines": { "node": ">=v12" } }, "node_modules/@commitlint/top-level": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-16.0.0.tgz", - "integrity": "sha512-/Jt6NLxyFkpjL5O0jxurZPCHURZAm7cQCqikgPCwqPAH0TLgwqdHjnYipl8J+AGnAMGDip4FNLoYrtgIpZGBYw==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-16.2.1.tgz", + "integrity": "sha512-lS6GSieHW9y6ePL73ied71Z9bOKyK+Ib9hTkRsB8oZFAyQZcyRwq2w6nIa6Fngir1QW51oKzzaXfJL94qwImyw==", "dev": true, "dependencies": { "find-up": "^5.0.0" @@ -976,9 +977,9 @@ } }, "node_modules/@commitlint/types": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-16.0.0.tgz", - "integrity": "sha512-+0FvYOAS39bJ4aKjnYn/7FD4DfWkmQ6G/06I4F0Gvu4KS5twirEg8mIcLhmeRDOOKn4Tp8PwpLwBiSA6npEMQA==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-16.2.1.tgz", + "integrity": "sha512-7/z7pA7BM0i8XvMSBynO7xsB3mVQPUZbVn6zMIlp/a091XJ3qAXRXc+HwLYhiIdzzS5fuxxNIHZMGHVD4HJxdA==", "dev": true, "dependencies": { "chalk": "^4.0.0" @@ -3563,21 +3564,6 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/parser": { "version": "5.38.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz", @@ -3689,21 +3675,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils": { "version": "5.38.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz", @@ -4732,9 +4703,9 @@ } }, "node_modules/conventional-changelog-writer/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -4786,9 +4757,9 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", @@ -4802,13 +4773,13 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.5.tgz", - "integrity": "sha512-FL/YR1nb8hyN0bAcP3MBaIoZravfZtVsN/RuPnoo6UVjqIrDxSNIpXHCGgJe0ZWy5yImpyD6jq5wCJ5f1nUv8g==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", + "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", "dev": true, "dependencies": { "cosmiconfig": "^7", - "ts-node": "^10.5.0" + "ts-node": "^10.8.1" }, "engines": { "node": ">=12", @@ -5981,22 +5952,6 @@ "node": ">=4" } }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -6042,9 +5997,9 @@ } }, "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6940,7 +6895,7 @@ "node_modules/global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", "dev": true, "dependencies": { "ini": "^1.3.4" @@ -7744,9 +7699,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -9007,9 +8962,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -9471,15 +9426,17 @@ } }, "node_modules/npm": { - "version": "9.7.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-9.7.1.tgz", - "integrity": "sha512-kxMviaiLX4Lfnjy2dt7EWB87v5QdLiGpy04S2ORdKLmPqFhgy8g4cgJjQfnWob4mJIaNHjBO+hk45CvLlsZZ8g==", + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.8.1.tgz", + "integrity": "sha512-AfDvThQzsIXhYgk9zhbk5R+lh811lKkLAeQMMhSypf1BM7zUafeIIBzMzespeuVEJ0+LvY36oRQYf7IKLzU3rw==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", "@npmcli/config", + "@npmcli/fs", "@npmcli/map-workspaces", "@npmcli/package-json", + "@npmcli/promise-spawn", "@npmcli/run-script", "abbrev", "archy", @@ -9533,6 +9490,7 @@ "semver", "sigstore", "ssri", + "supports-color", "tar", "text-table", "tiny-relative-date", @@ -9544,46 +9502,48 @@ "dev": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.2.9", - "@npmcli/config": "^6.2.0", + "@npmcli/arborist": "^6.3.0", + "@npmcli/config": "^6.2.1", + "@npmcli/fs": "^3.1.0", "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^3.1.1", + "@npmcli/package-json": "^4.0.1", + "@npmcli/promise-spawn": "^6.0.2", "@npmcli/run-script": "^6.0.2", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^17.1.2", - "chalk": "^5.2.0", + "cacache": "^17.1.3", + "chalk": "^5.3.0", "ci-info": "^3.8.0", "cli-columns": "^4.0.0", "cli-table3": "^0.6.3", "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.2", - "glob": "^10.2.4", + "glob": "^10.2.7", "graceful-fs": "^4.2.11", "hosted-git-info": "^6.1.1", - "ini": "^4.1.0", + "ini": "^4.1.1", "init-package-json": "^5.0.0", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.17", - "libnpmexec": "^6.0.0", - "libnpmfund": "^4.0.17", + "libnpmdiff": "^5.0.19", + "libnpmexec": "^6.0.3", + "libnpmfund": "^4.0.19", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.4", - "libnpmpack": "^5.0.17", - "libnpmpublish": "^7.3.0", + "libnpmpack": "^5.0.19", + "libnpmpublish": "^7.5.0", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", "libnpmversion": "^4.0.2", "make-fetch-happen": "^11.1.1", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "minipass": "^5.0.0", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^9.3.1", - "nopt": "^7.1.0", + "node-gyp": "^9.4.0", + "nopt": "^7.2.0", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.1.1", "npm-package-arg": "^10.1.0", @@ -9593,15 +9553,16 @@ "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", - "pacote": "^15.1.3", + "pacote": "^15.2.0", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", "read": "^2.1.0", - "semver": "^7.5.1", - "sigstore": "^1.5.0", + "semver": "^7.5.4", + "sigstore": "^1.7.0", "ssri": "^10.0.4", - "tar": "^6.1.14", + "supports-color": "^9.4.0", + "tar": "^6.1.15", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -9642,7 +9603,6 @@ "node_modules/npm/node_modules/@gar/promisify": { "version": "1.1.3", "dev": true, - "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/@isaacs/cliui": { @@ -9698,7 +9658,7 @@ } }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.0.1", + "version": "7.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -9719,7 +9679,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "6.2.9", + "version": "6.3.0", "dev": true, "inBundle": true, "license": "ISC", @@ -9731,7 +9691,7 @@ "@npmcli/metavuln-calculator": "^5.0.0", "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^3.0.0", + "@npmcli/package-json": "^4.0.0", "@npmcli/query": "^3.0.0", "@npmcli/run-script": "^6.0.0", "bin-links": "^4.0.1", @@ -9766,12 +9726,13 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "6.2.0", + "version": "6.2.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^3.8.0", "ini": "^4.1.0", "nopt": "^7.0.0", "proc-log": "^3.0.0", @@ -9875,7 +9836,6 @@ "node_modules/npm/node_modules/@npmcli/move-file": { "version": "2.0.1", "dev": true, - "inBundle": true, "license": "MIT", "dependencies": { "mkdirp": "^1.0.4", @@ -9904,17 +9864,18 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "3.1.1", + "version": "4.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/git": "^4.1.0", "glob": "^10.2.2", + "hosted-git-info": "^6.1.1", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.1", - "proc-log": "^3.0.0" + "proc-log": "^3.0.0", + "semver": "^7.5.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -9979,6 +9940,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/@tootallnate/once": { "version": "2.0.0", "dev": true, @@ -10146,7 +10120,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { - "version": "4.0.1", + "version": "4.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -10212,7 +10186,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "17.1.2", + "version": "17.1.3", "dev": true, "inBundle": true, "license": "ISC", @@ -10235,7 +10209,7 @@ } }, "node_modules/npm/node_modules/chalk": { - "version": "5.2.0", + "version": "5.3.0", "dev": true, "inBundle": true, "license": "MIT", @@ -10550,6 +10524,12 @@ "node": ">=0.8.x" } }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.16", "dev": true, @@ -10619,15 +10599,15 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "10.2.4", + "version": "10.2.7", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0 || ^6.0.0", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", "path-scurry": "^1.7.0" }, "bin": { @@ -10784,7 +10764,6 @@ "node_modules/npm/node_modules/infer-owner": { "version": "1.0.4", "dev": true, - "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/inflight": { @@ -10804,7 +10783,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/ini": { - "version": "4.1.0", + "version": "4.1.1", "dev": true, "inBundle": true, "license": "ISC", @@ -10858,7 +10837,7 @@ } }, "node_modules/npm/node_modules/is-core-module": { - "version": "2.12.0", + "version": "2.12.1", "dev": true, "inBundle": true, "license": "MIT", @@ -10891,7 +10870,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { - "version": "2.2.0", + "version": "2.2.1", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", @@ -10961,12 +10940,12 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "5.0.17", + "version": "5.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.3.0", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", @@ -10981,12 +10960,12 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "6.0.0", + "version": "6.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.3.0", "@npmcli/run-script": "^6.0.0", "ci-info": "^3.7.1", "npm-package-arg": "^10.1.0", @@ -11003,12 +10982,12 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "4.0.17", + "version": "4.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9" + "@npmcli/arborist": "^6.3.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -11041,12 +11020,12 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "5.0.17", + "version": "5.0.19", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.2.9", + "@npmcli/arborist": "^6.3.0", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" @@ -11056,7 +11035,7 @@ } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "7.3.0", + "version": "7.5.0", "dev": true, "inBundle": true, "license": "ISC", @@ -11151,7 +11130,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.0", + "version": "9.0.3", "dev": true, "inBundle": true, "license": "ISC", @@ -11371,15 +11350,16 @@ } }, "node_modules/npm/node_modules/node-gyp": { - "version": "9.3.1", + "version": "9.4.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^11.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", @@ -11394,19 +11374,6 @@ "node": "^12.13 || ^14.13 || >=16" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/node-gyp/node_modules/abbrev": { "version": "1.1.1", "dev": true, @@ -11436,87 +11403,6 @@ "concat-map": "0.0.1" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache": { - "version": "16.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/fs-minipass": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { "version": "4.0.4", "dev": true, @@ -11556,33 +11442,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "10.2.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", "dev": true, @@ -11595,35 +11454,6 @@ "node": "*" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/minipass": { - "version": "3.3.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { "version": "6.0.0", "dev": true, @@ -11674,42 +11504,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/node-gyp/node_modules/ssri": { - "version": "9.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/unique-filename": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/unique-slug": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/node-gyp/node_modules/which": { "version": "2.0.2", "dev": true, @@ -11726,7 +11520,7 @@ } }, "node_modules/npm/node_modules/nopt": { - "version": "7.1.0", + "version": "7.2.0", "dev": true, "inBundle": true, "license": "ISC", @@ -11919,7 +11713,7 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "15.1.3", + "version": "15.2.0", "dev": true, "inBundle": true, "license": "ISC", @@ -11983,13 +11777,13 @@ } }, "node_modules/npm/node_modules/path-scurry": { - "version": "1.9.1", + "version": "1.9.2", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.0" + "minipass": "^5.0.0 || ^6.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -12117,7 +11911,7 @@ } }, "node_modules/npm/node_modules/read-package-json": { - "version": "6.0.3", + "version": "6.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -12226,8 +12020,22 @@ } }, "node_modules/npm/node_modules/safe-buffer": { - "version": "5.1.2", + "version": "5.2.1", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "inBundle": true, "license": "MIT" }, @@ -12239,7 +12047,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.5.1", + "version": "7.5.4", "dev": true, "inBundle": true, "license": "ISC", @@ -12305,14 +12113,14 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "1.5.2", + "version": "1.7.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.1.0", - "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.1.3" + "@sigstore/tuf": "^1.0.1", + "make-fetch-happen": "^11.0.1" }, "bin": { "sigstore": "bin/sigstore.js" @@ -12404,12 +12212,12 @@ } }, "node_modules/npm/node_modules/string_decoder": { - "version": "1.1.1", + "version": "1.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, "node_modules/npm/node_modules/string-width": { @@ -12466,8 +12274,20 @@ "node": ">=8" } }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/npm/node_modules/tar": { - "version": "6.1.14", + "version": "6.1.15", "dev": true, "inBundle": true, "license": "ISC", @@ -12529,14 +12349,14 @@ } }, "node_modules/npm/node_modules/tuf-js": { - "version": "1.1.6", + "version": "1.1.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@tufjs/models": "1.0.4", "debug": "^4.3.4", - "make-fetch-happen": "^11.1.0" + "make-fetch-happen": "^11.1.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -12716,7 +12536,7 @@ } }, "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.0.1", + "version": "7.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -13517,9 +13337,9 @@ } }, "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -14231,9 +14051,9 @@ } }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" diff --git a/src/Client.ts b/src/Client.ts index 2b741728f..18555d2b9 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -33,7 +33,8 @@ import { StaticKeystoreProvider, } from './keystore/providers' import { - LocalStoragePersistence, + BrowserStoragePersistence, + InMemoryPersistence, Persistence, PrefixedPersistence, } from './keystore/persistence' @@ -210,7 +211,10 @@ export function defaultOptions(opts?: Partial): ClientOptions { maxContentSize: MaxContentSize, persistConversations: true, skipContactPublishing: false, - basePersistence: new LocalStoragePersistence(), + basePersistence: + typeof localStorage === 'undefined' + ? InMemoryPersistence.create() + : BrowserStoragePersistence.create(), disablePersistenceEncryption: false, keystoreProviders: defaultKeystoreProviders(), apiClientFactory: createHttpApiClientFromOptions, diff --git a/src/index.ts b/src/index.ts index 151d035b0..0876e7bfa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -98,7 +98,8 @@ export { } from './keystore/providers' export { EncryptedPersistence, - LocalStoragePersistence, + BrowserStoragePersistence, + InMemoryPersistence, PrefixedPersistence, Persistence, } from './keystore/persistence' diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 0407930e6..20d5d1919 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -30,6 +30,8 @@ import LocalAuthenticator from '../authn/LocalAuthenticator' import { hmacSha256Sign } from '../crypto/ecies' import crypto from '../crypto/crypto' import { bytesToHex } from '../crypto/utils' +import Long from 'long' +import { SetRefreshJobResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' const { ErrorCode } = keystore // Constant, 32 byte salt @@ -58,16 +60,26 @@ export default class InMemoryKeystore implements Keystore { private inviteStore: InviteStore private authenticator: LocalAuthenticator private accountAddress: string | undefined + private jobStatePersistence: Persistence - constructor(keys: PrivateKeyBundleV1, inviteStore: InviteStore) { + constructor( + keys: PrivateKeyBundleV1, + inviteStore: InviteStore, + persistence: Persistence + ) { this.v1Keys = keys this.v2Keys = PrivateKeyBundleV2.fromLegacyBundle(keys) this.inviteStore = inviteStore this.authenticator = new LocalAuthenticator(keys.identityKey) + this.jobStatePersistence = persistence } - static async create(keys: PrivateKeyBundleV1, persistence?: Persistence) { - return new InMemoryKeystore(keys, await InviteStore.create(persistence)) + static async create(keys: PrivateKeyBundleV1, persistence: Persistence) { + return new InMemoryKeystore( + keys, + await InviteStore.create(persistence), + persistence + ) } async decryptV1( @@ -398,6 +410,53 @@ export default class InMemoryKeystore implements Keystore { return this.accountAddress } + async getRefreshJob({ + jobType, + }: keystore.GetRefreshJobRequest): Promise { + if (jobType === keystore.JobType.JOB_TYPE_UNSPECIFIED) { + throw new KeystoreError( + ErrorCode.ERROR_CODE_INVALID_INPUT, + 'invalid job type' + ) + } + + const lastRunTime = await this.getLastRunTime(jobType) + + return keystore.GetRefreshJobResponse.fromPartial({ + lastRunNs: lastRunTime || Long.fromNumber(0), + }) + } + + async setRefreshJob({ + jobType, + lastRunNs, + }: keystore.SetRefeshJobRequest): Promise { + const key = await this.buildJobStorageKey(jobType) + await this.jobStatePersistence.setItem( + key, + Uint8Array.from(lastRunNs.toBytes()) + ) + + return {} + } + + private buildJobStorageKey(jobType: keystore.JobType): string { + return `refreshJob/${jobType.toString()}` + } + + private async getLastRunTime( + jobType: keystore.JobType + ): Promise { + const bytes = await this.jobStatePersistence.getItem( + this.buildJobStorageKey(jobType) + ) + if (!bytes || !bytes.length) { + return + } + + return Long.fromBytes([...bytes]) + } + // This method is not defined as part of the standard Keystore API, but is available // on the InMemoryKeystore to support legacy use-cases. lookupTopic(topic: string) { diff --git a/src/keystore/persistence/LocalStoragePersistence.ts b/src/keystore/persistence/BrowserStoragePersistence.ts similarity index 53% rename from src/keystore/persistence/LocalStoragePersistence.ts rename to src/keystore/persistence/BrowserStoragePersistence.ts index 133d473dd..ef4d82db4 100644 --- a/src/keystore/persistence/LocalStoragePersistence.ts +++ b/src/keystore/persistence/BrowserStoragePersistence.ts @@ -1,13 +1,16 @@ import { Persistence } from './interface' -import LocalStoragePonyfill from './LocalStoragePonyfill' -export default class LocalStoragePersistence implements Persistence { +export default class BrowserStoragePersistence implements Persistence { storage: Storage - constructor() { - this.storage = - typeof localStorage !== 'undefined' - ? localStorage - : new LocalStoragePonyfill() + constructor(storage: Storage) { + this.storage = storage + } + + static create(): BrowserStoragePersistence { + if (typeof localStorage === 'undefined') { + throw new Error('Missing LocalStorage. Use ephemeralPersistence instead') + } + return new BrowserStoragePersistence(localStorage) } async getItem(key: string): Promise { diff --git a/src/keystore/persistence/InMemoryPersistence.ts b/src/keystore/persistence/InMemoryPersistence.ts new file mode 100644 index 000000000..c16c0f317 --- /dev/null +++ b/src/keystore/persistence/InMemoryPersistence.ts @@ -0,0 +1,8 @@ +import BrowserStoragePersistence from './BrowserStoragePersistence' +import LocalStoragePonyfill from './LocalStoragePonyfill' + +export default class InMemoryPersistence extends BrowserStoragePersistence { + static create() { + return new BrowserStoragePersistence(new LocalStoragePonyfill()) + } +} diff --git a/src/keystore/persistence/index.ts b/src/keystore/persistence/index.ts index 47b2b1258..15ccee364 100644 --- a/src/keystore/persistence/index.ts +++ b/src/keystore/persistence/index.ts @@ -1,4 +1,5 @@ export * from './interface' -export { default as LocalStoragePersistence } from './LocalStoragePersistence' +export { default as BrowserStoragePersistence } from './BrowserStoragePersistence' +export { default as InMemoryPersistence } from './InMemoryPersistence' export { default as PrefixedPersistence } from './PrefixedPersistence' export { default as EncryptedPersistence } from './EncryptedPersistence' diff --git a/src/keystore/providers/helpers.ts b/src/keystore/providers/helpers.ts index 3911d9021..5707dc8ed 100644 --- a/src/keystore/providers/helpers.ts +++ b/src/keystore/providers/helpers.ts @@ -2,16 +2,18 @@ import { PrivateKeyBundleV2 } from './../../crypto/PrivateKeyBundle' import { PrivateKeyBundleV1 } from '../../crypto/PrivateKeyBundle' import { EncryptedPersistence, PrefixedPersistence } from '../persistence' import { KeystoreProviderOptions } from './interfaces' +import { buildPersistenceKey } from '../utils' +import EphemeralPersistence from '../persistence/InMemoryPersistence' export const buildPersistenceFromOptions = async ( opts: KeystoreProviderOptions, keys: PrivateKeyBundleV1 | PrivateKeyBundleV2 ) => { if (!opts.persistConversations) { - return undefined + return EphemeralPersistence.create() } const address = await keys.identityKey.publicKey.walletSignatureAddress() - const prefix = `xmtp/${opts.env}/${address}/` + const prefix = buildPersistenceKey(opts.env, address) const basePersistence = opts.basePersistence const shouldEncrypt = !opts.disablePersistenceEncryption diff --git a/src/keystore/utils.ts b/src/keystore/utils.ts index 6e1d43bef..534953ba9 100644 --- a/src/keystore/utils.ts +++ b/src/keystore/utils.ts @@ -8,6 +8,7 @@ import { import { PublicKeyBundle, SignedPublicKeyBundle } from '../crypto' import { KeystoreError } from './errors' import { WithoutUndefined } from '../utils/typedefs' +import { XmtpEnv } from '../Client' export const convertError = ( e: Error, @@ -134,3 +135,6 @@ export const typeSafeTopicMap = ( } return out } + +export const buildPersistenceKey = (env: XmtpEnv, walletAddress: string) => + `xmtp/${env}/${walletAddress}/` diff --git a/test/Client.test.ts b/test/Client.test.ts index 09d199c4f..1ef7e5247 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -12,7 +12,7 @@ import { ApiUrls, Compression, HttpApiClient, - LocalStoragePersistence, + InMemoryPersistence, PublishParams, } from '../src' import NetworkKeyManager from '../src/keystore/providers/NetworkKeyManager' @@ -21,6 +21,7 @@ import { PrivateKeyBundleV1 } from '../src/crypto' import { Wallet } from 'ethers' import { NetworkKeystoreProvider } from '../src/keystore/providers' import { PublishResponse } from '@xmtp/proto/ts/dist/types/message_api/v1/message_api.pb' +import LocalStoragePonyfill from '../src/keystore/persistence/LocalStoragePonyfill' type TestCase = { name: string @@ -345,14 +346,14 @@ describe('ClientOptions', () => { describe('pluggable persistence', () => { it('allows for an override of the persistence engine', async () => { - class MyNewPersistence extends LocalStoragePersistence { - async getItem(key: string): Promise { - throw new Error('MyNewPersistence') + class MyNewPersistence extends InMemoryPersistence { + getItem(key: string): Promise { + return Promise.reject(new Error('MyNewPersistence')) } } const c = newLocalHostClient({ - basePersistence: new MyNewPersistence(), + basePersistence: new MyNewPersistence(new LocalStoragePonyfill()), }) expect(c).rejects.toThrow('MyNewPersistence') }) diff --git a/test/Message.test.ts b/test/Message.test.ts index cb6800862..919b2a2d0 100644 --- a/test/Message.test.ts +++ b/test/Message.test.ts @@ -6,7 +6,7 @@ import { PrivateKeyBundleV1 } from '../src/crypto/PrivateKeyBundle' import { bytesToHex, equalBytes } from '../src/crypto/utils' import { sha256 } from '../src/crypto/encryption' import { InMemoryKeystore, InviteStore, KeystoreError } from '../src/keystore' -import { Client, ContentTypeText } from '../src' +import { Client, ContentTypeText, InMemoryPersistence } from '../src' import { Wallet } from 'ethers' import { ContentTypeTestKey, TestKeyCodec } from './ContentTypeTestKey' @@ -31,10 +31,16 @@ describe('Message', function () { const bobWalletAddress = bob .getPublicKeyBundle() .identityKey.walletSignatureAddress() - const bobKeystore = new InMemoryKeystore(bob, new InviteStore()) + const bobKeystore = await InMemoryKeystore.create( + bob, + InMemoryPersistence.create() + ) // Alice encodes message for Bob const content = new TextEncoder().encode('Yo!') - const aliceKeystore = new InMemoryKeystore(alice, new InviteStore()) + const aliceKeystore = await InMemoryKeystore.create( + alice, + InMemoryPersistence.create() + ) const msg1 = await MessageV1.encode( aliceKeystore, @@ -65,8 +71,14 @@ describe('Message', function () { it('undecodable returns with undefined decrypted value', async () => { const eve = await PrivateKeyBundleV1.generate(newWallet()) - const aliceKeystore = new InMemoryKeystore(alice, new InviteStore()) - const eveKeystore = new InMemoryKeystore(eve, new InviteStore()) + const aliceKeystore = await InMemoryKeystore.create( + alice, + InMemoryPersistence.create() + ) + const eveKeystore = await InMemoryKeystore.create( + eve, + InMemoryPersistence.create() + ) const msg = await MessageV1.encode( aliceKeystore, new TextEncoder().encode('Hi'), @@ -81,7 +93,10 @@ describe('Message', function () { it('Message create throws error for sender without wallet', async () => { const amal = await PrivateKeyBundleV1.generate() - const keystore = new InMemoryKeystore(bob, new InviteStore()) + const keystore = await InMemoryKeystore.create( + bob, + InMemoryPersistence.create() + ) expect( MessageV1.encode( @@ -96,7 +111,10 @@ describe('Message', function () { it('recipientAddress throws error without wallet', async () => { const charlie = await PrivateKeyBundleV1.generate() - const keystore = new InMemoryKeystore(alice, new InviteStore()) + const keystore = await InMemoryKeystore.create( + alice, + InMemoryPersistence.create() + ) const msg = await MessageV1.encode( keystore, new TextEncoder().encode('hi'), @@ -111,7 +129,10 @@ describe('Message', function () { }) it('id returns bytes as hex string of sha256 hash', async () => { - const keystore = new InMemoryKeystore(alice, new InviteStore()) + const keystore = await InMemoryKeystore.create( + alice, + InMemoryPersistence.create() + ) const msg = await MessageV1.encode( keystore, new TextEncoder().encode('hi'), diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index 5d296f33f..eb7a69ac0 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -14,7 +14,7 @@ import { equalBytes } from '../../src/crypto/utils' import { InvitationV1, SealedInvitation } from '../../src/Invitation' import { buildProtoEnvelope, newWallet } from '../helpers' import { dateToNs, nsToDate } from '../../src/utils/date' -import { LocalStoragePersistence } from '../../src/keystore/persistence' +import { InMemoryPersistence } from '../../src/keystore/persistence' import Token from '../../src/authn/Token' import Long from 'long' import { CreateInviteResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' @@ -23,19 +23,20 @@ import { ethers } from 'ethers' describe('InMemoryKeystore', () => { let aliceKeys: PrivateKeyBundleV1 let aliceKeystore: InMemoryKeystore - let aliceKeystoreWithPersistence: InMemoryKeystore let bobKeys: PrivateKeyBundleV1 let bobKeystore: InMemoryKeystore beforeEach(async () => { aliceKeys = await PrivateKeyBundleV1.generate(newWallet()) - aliceKeystore = await InMemoryKeystore.create(aliceKeys) - aliceKeystoreWithPersistence = await InMemoryKeystore.create( + aliceKeystore = await InMemoryKeystore.create( aliceKeys, - new LocalStoragePersistence() + InMemoryPersistence.create() ) bobKeys = await PrivateKeyBundleV1.generate(newWallet()) - bobKeystore = await InMemoryKeystore.create(bobKeys) + bobKeystore = await InMemoryKeystore.create( + bobKeys, + InMemoryPersistence.create() + ) }) const buildInvite = async (context?: InvitationContext) => { @@ -219,30 +220,29 @@ describe('InMemoryKeystore', () => { describe('saveInvites', () => { it('can save a batch of valid envelopes', async () => { - for (const keystore of [aliceKeystore, aliceKeystoreWithPersistence]) { - const { invite, created, sealed } = await buildInvite() + const keystore = aliceKeystore + const { invite, created, sealed } = await buildInvite() - const sealedBytes = sealed.toBytes() - const envelope = buildProtoEnvelope(sealedBytes, 'foo', created) - const { responses } = await keystore.saveInvites({ - requests: [envelope], - }) + const sealedBytes = sealed.toBytes() + const envelope = buildProtoEnvelope(sealedBytes, 'foo', created) + const { responses } = await keystore.saveInvites({ + requests: [envelope], + }) - expect(responses).toHaveLength(1) - const firstResult = responses[0] - if (firstResult.error) { - throw firstResult.error - } - expect( - nsToDate(firstResult.result!.conversation!.createdNs).getTime() - ).toEqual(created.getTime()) - expect(firstResult.result!.conversation!.topic).toEqual(invite.topic) - expect(firstResult.result!.conversation?.context).toBeUndefined() - - const conversations = await keystore.getV2Conversations() - expect(conversations).toHaveLength(1) - expect(conversations[0].topic).toBe(invite.topic) + expect(responses).toHaveLength(1) + const firstResult = responses[0] + if (firstResult.error) { + throw firstResult.error } + expect( + nsToDate(firstResult.result!.conversation!.createdNs).getTime() + ).toEqual(created.getTime()) + expect(firstResult.result!.conversation!.topic).toEqual(invite.topic) + expect(firstResult.result!.conversation?.context).toBeUndefined() + + const conversations = await keystore.getV2Conversations() + expect(conversations).toHaveLength(1) + expect(conversations[0].topic).toBe(invite.topic) }) it('can save received invites', async () => { @@ -313,34 +313,33 @@ describe('InMemoryKeystore', () => { describe('encryptV2/decryptV2', () => { it('encrypts using a saved envelope', async () => { - for (const keystore of [aliceKeystore, aliceKeystoreWithPersistence]) { - const { invite, created, sealed } = await buildInvite() - - const sealedBytes = sealed.toBytes() - const envelope = buildProtoEnvelope(sealedBytes, 'foo', created) - await keystore.saveInvites({ requests: [envelope] }) - - const payload = new TextEncoder().encode('Hello, world!') - const headerBytes = new Uint8Array(10) - - const { - responses: [encrypted], - } = await keystore.encryptV2({ - requests: [ - { - contentTopic: invite.topic, - payload, - headerBytes, - }, - ], - }) + const keystore = aliceKeystore + const { invite, created, sealed } = await buildInvite() - if (encrypted.error) { - throw encrypted - } + const sealedBytes = sealed.toBytes() + const envelope = buildProtoEnvelope(sealedBytes, 'foo', created) + await keystore.saveInvites({ requests: [envelope] }) + + const payload = new TextEncoder().encode('Hello, world!') + const headerBytes = new Uint8Array(10) - expect(encrypted.result?.encrypted).toBeTruthy() + const { + responses: [encrypted], + } = await keystore.encryptV2({ + requests: [ + { + contentTopic: invite.topic, + payload, + headerBytes, + }, + ], + }) + + if (encrypted.error) { + throw encrypted } + + expect(encrypted.result?.encrypted).toBeTruthy() }) it('round trips using a created invite', async () => { @@ -537,7 +536,10 @@ describe('InMemoryKeystore', () => { ) ).v1! ) - aliceKeystore = await InMemoryKeystore.create(aliceKeys) + aliceKeystore = await InMemoryKeystore.create( + aliceKeys, + InMemoryPersistence.create() + ) bobKeys = new PrivateKeyBundleV1( privateKey.PrivateKeyBundle.decode( ethers.utils.arrayify( @@ -623,7 +625,7 @@ describe('InMemoryKeystore', () => { it('creates an auth token', async () => { const authToken = new Token(await aliceKeystore.createAuthToken({})) expect(authToken.authDataBytes).toBeDefined() - expect(authToken.authData.createdNs).toBeInstanceOf(Long) + expect(Long.isLong(authToken.authData.createdNs)).toBeTruthy() expect(authToken.authDataSignature).toBeDefined() expect(authToken.identityKey?.secp256k1Uncompressed).toBeDefined() expect(authToken.identityKey?.signature).toBeDefined() diff --git a/test/keystore/InviteStore.test.ts b/test/keystore/InviteStore.test.ts index 5479c69e2..a6686239d 100644 --- a/test/keystore/InviteStore.test.ts +++ b/test/keystore/InviteStore.test.ts @@ -1,6 +1,6 @@ import crypto from '../../src/crypto/crypto' import { InviteStore, TopicData } from '../../src/keystore' -import { LocalStoragePersistence } from '../../src/keystore/persistence' +import { InMemoryPersistence } from '../../src/keystore/persistence' import { dateToNs } from '../../src/utils' const buildTopicData = (): TopicData => ({ @@ -30,7 +30,7 @@ describe('InviteStore', () => { }) it('can add and retrieve invites with persistence', async () => { - const store = await InviteStore.create(new LocalStoragePersistence()) + const store = await InviteStore.create(InMemoryPersistence.create()) const topicData = buildTopicData() await store.add([topicData]) @@ -45,7 +45,7 @@ describe('InviteStore', () => { }) it('persists data between instances', async () => { - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const store = await InviteStore.create(persistence) const topicData = buildTopicData() await store.add([topicData]) diff --git a/test/keystore/encryption.test.ts b/test/keystore/encryption.test.ts index 8d7c5ddf1..b3246b086 100644 --- a/test/keystore/encryption.test.ts +++ b/test/keystore/encryption.test.ts @@ -6,7 +6,8 @@ import { MessageV1 } from '../../src/Message' import { Wallet } from 'ethers' import { equalBytes } from '../../src/crypto/utils' import { newWallet } from '../helpers' -import { InMemoryKeystore, InviteStore } from '../../src/keystore' +import { InMemoryKeystore } from '../../src/keystore' +import { InMemoryPersistence } from '../../src' describe('encryption primitives', () => { let aliceKeys: PrivateKeyBundleV1 @@ -18,7 +19,10 @@ describe('encryption primitives', () => { beforeEach(async () => { aliceWallet = newWallet() aliceKeys = await PrivateKeyBundleV1.generate(aliceWallet) - aliceKeystore = new InMemoryKeystore(aliceKeys, new InviteStore()) + aliceKeystore = await InMemoryKeystore.create( + aliceKeys, + InMemoryPersistence.create() + ) bobWallet = newWallet() bobKeys = await PrivateKeyBundleV1.generate(bobWallet) }) diff --git a/test/keystore/persistence/EncryptedPersistence.test.ts b/test/keystore/persistence/EncryptedPersistence.test.ts index 4de7da7cc..246855314 100644 --- a/test/keystore/persistence/EncryptedPersistence.test.ts +++ b/test/keystore/persistence/EncryptedPersistence.test.ts @@ -2,7 +2,7 @@ import crypto from '../../../src/crypto/crypto' import { PrivateKeyBundleV1 } from './../../../src/crypto/PrivateKeyBundle' import { EncryptedPersistence, - LocalStoragePersistence, + InMemoryPersistence, } from '../../../src/keystore/persistence' import { PrivateKey, SignedEciesCiphertext } from '../../../src/crypto' @@ -19,7 +19,7 @@ describe('EncryptedPersistence', () => { it('can encrypt and decrypt a value', async () => { const data = crypto.getRandomValues(new Uint8Array(128)) - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey @@ -41,7 +41,7 @@ describe('EncryptedPersistence', () => { ] for (const input of inputs) { const encryptedPersistence = new EncryptedPersistence( - new LocalStoragePersistence(), + InMemoryPersistence.create(), privateKey ) @@ -53,7 +53,7 @@ describe('EncryptedPersistence', () => { it('uses random values to encrypt repeatedly', async () => { const data = crypto.getRandomValues(new Uint8Array(128)) - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey @@ -70,7 +70,7 @@ describe('EncryptedPersistence', () => { }) it('catches garbage values', async () => { - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey @@ -87,7 +87,7 @@ describe('EncryptedPersistence', () => { it('detects bad mac', async () => { const data = crypto.getRandomValues(new Uint8Array(128)) - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey @@ -116,7 +116,7 @@ describe('EncryptedPersistence', () => { }) it('detects bad signature', async () => { - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey @@ -139,7 +139,7 @@ describe('EncryptedPersistence', () => { }) it('signed correctly and encrypted incorrectly', async () => { - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const encryptedPersistence = new EncryptedPersistence( persistence, privateKey diff --git a/test/keystore/persistence/LocalStoragePersistence.test.ts b/test/keystore/persistence/LocalStoragePersistence.test.ts index baf0d5029..156bf69e5 100644 --- a/test/keystore/persistence/LocalStoragePersistence.test.ts +++ b/test/keystore/persistence/LocalStoragePersistence.test.ts @@ -1,12 +1,12 @@ -import LocalStoragePersistence from '../../../src/keystore/persistence/LocalStoragePersistence' +import { InMemoryPersistence } from '../../../src/keystore/persistence' import { decodePrivateKeyBundle, PrivateKeyBundleV1 } from '../../../src/crypto' describe('Persistence', () => { describe('LocalStoragePersistence', () => { - let persistence: LocalStoragePersistence + let persistence: InMemoryPersistence const key = 'test' beforeEach(async () => { - persistence = new LocalStoragePersistence() + persistence = InMemoryPersistence.create() }) it('can store and retrieve proto objects', async () => { diff --git a/test/keystore/persistence/PrefixedPersistence.test.ts b/test/keystore/persistence/PrefixedPersistence.test.ts index cc6cab00a..6da7f22a8 100644 --- a/test/keystore/persistence/PrefixedPersistence.test.ts +++ b/test/keystore/persistence/PrefixedPersistence.test.ts @@ -1,11 +1,11 @@ import { - LocalStoragePersistence, + InMemoryPersistence, PrefixedPersistence, } from '../../../src/keystore/persistence' describe('PrefixedPersistence', () => { it('correctly adds a prefix to keys', async () => { - const persistence = new LocalStoragePersistence() + const persistence = InMemoryPersistence.create() const prefixedPersistence = new PrefixedPersistence('foo', persistence) await prefixedPersistence.setItem('bar', new Uint8Array([1, 2, 3])) diff --git a/test/keystore/providers/NetworkKeyManager.test.ts b/test/keystore/providers/NetworkKeyManager.test.ts index 5ef0d414f..4e6bd25c7 100644 --- a/test/keystore/providers/NetworkKeyManager.test.ts +++ b/test/keystore/providers/NetworkKeyManager.test.ts @@ -1,6 +1,6 @@ +import { BrowserStoragePersistence, PrefixedPersistence } from '../../../src' import ApiClient, { ApiUrls } from '../../../src/ApiClient' import { PrivateKeyBundleV1 } from '../../../src/crypto/PrivateKeyBundle' -import PrefixedPersistence from '../../../src/keystore/persistence/PrefixedPersistence' import TopicPersistence from '../../../src/keystore/persistence/TopicPersistence' import { buildPersistenceFromOptions } from '../../../src/keystore/providers/helpers' import NetworkKeyManager from '../../../src/keystore/providers/NetworkKeyManager' @@ -100,17 +100,23 @@ describe('NetworkKeyManager', () => { it('respects the options provided', async () => { const bundle = await PrivateKeyBundleV1.generate(wallet) - const shouldBeUndefined = await buildPersistenceFromOptions( - testProviderOptions({ persistConversations: false }), + const shouldBePrefixed = await buildPersistenceFromOptions( + testProviderOptions({ + disablePersistenceEncryption: true, + persistConversations: false, + }), bundle ) - expect(shouldBeUndefined).toBeUndefined() + expect(shouldBePrefixed).toBeInstanceOf(BrowserStoragePersistence) - const shouldBeDefined = await buildPersistenceFromOptions( - testProviderOptions({ persistConversations: true }), + const shouldBeEncrypted = await buildPersistenceFromOptions( + testProviderOptions({ + disablePersistenceEncryption: false, + persistConversations: true, + }), bundle ) - expect(shouldBeDefined).toBeInstanceOf(PrefixedPersistence) + expect(shouldBeEncrypted).toBeInstanceOf(PrefixedPersistence) }) it('calls notifier on store', async () => { diff --git a/test/keystore/providers/helpers.ts b/test/keystore/providers/helpers.ts index 5b0ac5148..f6a052503 100644 --- a/test/keystore/providers/helpers.ts +++ b/test/keystore/providers/helpers.ts @@ -1,10 +1,10 @@ -import { LocalStoragePersistence } from '../../../src' +import { InMemoryPersistence } from '../../../src' import { KeystoreProviderOptions } from '../../../src/keystore/providers' export const testProviderOptions = ({ privateKeyOverride = undefined, persistConversations = false, - basePersistence = new LocalStoragePersistence(), + basePersistence = InMemoryPersistence.create(), env = 'local' as const, }: Partial) => ({ env, From 55f5127cd07c4d1c0ce01549d66b81ef667c92fa Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 13:47:38 -0700 Subject: [PATCH 082/137] test: add required tests --- src/keystore/interfaces.ts | 12 ++++++ test/keystore/InMemoryKeystore.test.ts | 60 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index e220f2dd9..30a947193 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -50,6 +50,18 @@ export interface Keystore { * Sign the provided digest with either the `IdentityKey` or a specified `PreKey` */ signDigest(req: keystore.SignDigestRequest): Promise + /** + * Get a refresh job from the persistence + */ + getRefreshJob( + req: keystore.GetRefreshJobRequest + ): Promise + /** + * Sets the time of a refresh job + */ + setRefreshJob( + req: keystore.SetRefeshJobRequest + ): Promise /** * Get a list of V2 conversations */ diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index eb7a69ac0..e10dd8af1 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -692,4 +692,64 @@ describe('InMemoryKeystore', () => { expect(lookupResult).toBeUndefined() }) }) + + describe('getRefreshJob/setRefreshJob', () => { + it('returns 0 value when empty', async () => { + const job = await aliceKeystore.getRefreshJob( + keystore.GetRefreshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + }) + ) + expect(job.lastRunNs.equals(Long.fromNumber(0))).toBeTruthy() + }) + + it('returns a value when set', async () => { + const lastRunNs = dateToNs(new Date()) + await aliceKeystore.setRefreshJob( + keystore.SetRefeshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + lastRunNs, + }) + ) + + const result = await aliceKeystore.getRefreshJob( + keystore.GetRefreshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + }) + ) + expect(result.lastRunNs.equals(lastRunNs)).toBeTruthy() + + const otherJob = await aliceKeystore.getRefreshJob( + keystore.GetRefreshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V2, + }) + ) + expect(otherJob.lastRunNs.equals(Long.fromNumber(0))).toBeTruthy() + }) + + it('overwrites a value when set', async () => { + const lastRunNs = dateToNs(new Date()) + await aliceKeystore.setRefreshJob( + keystore.SetRefeshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + lastRunNs: Long.fromNumber(5), + }) + ) + await aliceKeystore.setRefreshJob( + keystore.SetRefeshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + lastRunNs, + }) + ) + expect( + ( + await aliceKeystore.getRefreshJob( + keystore.GetRefreshJobRequest.fromPartial({ + jobType: keystore.JobType.JOB_TYPE_REFRESH_V1, + }) + ) + ).lastRunNs.equals(lastRunNs) + ).toBeTruthy() + }) + }) }) From 3682e98cb2484d3d29b3010f10d032698339d7cb Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 13:48:32 -0700 Subject: [PATCH 083/137] chore: remove unused import --- src/Client.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 2b741728f..cfb718de9 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -32,11 +32,7 @@ import { NetworkKeystoreProvider, StaticKeystoreProvider, } from './keystore/providers' -import { - LocalStoragePersistence, - Persistence, - PrefixedPersistence, -} from './keystore/persistence' +import { LocalStoragePersistence, Persistence } from './keystore/persistence' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types From c90aa10c77e056a4ae1408d41d83e447c75799a9 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 13:53:26 -0700 Subject: [PATCH 084/137] feat: make persistence mandatory --- src/keystore/InviteStore.ts | 27 +++++++++++---------------- test/keystore/InviteStore.test.ts | 4 ++-- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/keystore/InviteStore.ts b/src/keystore/InviteStore.ts index 4176ee277..38d20bd77 100644 --- a/src/keystore/InviteStore.ts +++ b/src/keystore/InviteStore.ts @@ -10,12 +10,12 @@ const INVITE_KEY = 'invitations/v1' * InviteStore holds a simple map of topic -> TopicData and writes to the persistence layer on changes */ export default class InviteStore { - private persistence?: Persistence + private persistence: Persistence private mutex: Mutex private topicMap: Map constructor( - persistence?: Persistence, + persistence: Persistence, initialData: Map = new Map() ) { this.persistence = persistence @@ -23,20 +23,15 @@ export default class InviteStore { this.topicMap = initialData } - static async create(persistence?: Persistence): Promise { - if (persistence) { - const rawData = await persistence.getItem(INVITE_KEY) - if (rawData) { - try { - const inviteMap = typeSafeTopicMap(keystore.TopicMap.decode(rawData)) - // Create an InviteStore with data preloaded - return new InviteStore( - persistence, - new Map(Object.entries(inviteMap)) - ) - } catch (e) { - console.warn(`Error loading invites from store: ${e}`) - } + static async create(persistence: Persistence): Promise { + const rawData = await persistence.getItem(INVITE_KEY) + if (rawData) { + try { + const inviteMap = typeSafeTopicMap(keystore.TopicMap.decode(rawData)) + // Create an InviteStore with data preloaded + return new InviteStore(persistence, new Map(Object.entries(inviteMap))) + } catch (e) { + console.warn(`Error loading invites from store: ${e}`) } } return new InviteStore(persistence) diff --git a/test/keystore/InviteStore.test.ts b/test/keystore/InviteStore.test.ts index a6686239d..493fd0d9d 100644 --- a/test/keystore/InviteStore.test.ts +++ b/test/keystore/InviteStore.test.ts @@ -20,7 +20,7 @@ const buildTopicData = (): TopicData => ({ describe('InviteStore', () => { it('can add and retrieve invites without persistence', async () => { - const store = await InviteStore.create() + const store = await InviteStore.create(InMemoryPersistence.create()) const topicData = buildTopicData() await store.add([topicData]) @@ -39,7 +39,7 @@ describe('InviteStore', () => { }) it('returns undefined when no match exists', async () => { - const store = await InviteStore.create() + const store = await InviteStore.create(InMemoryPersistence.create()) const result = store.lookup('foo') expect(result).toBeUndefined() }) From 6bcc61aae77d9c5a81d263c673de92d375bf5ecc Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 17:40:56 -0700 Subject: [PATCH 085/137] feat: add and use JobRunner --- src/Client.ts | 3 +- src/Compression.ts | 2 +- src/conversations/Conversations.ts | 130 +++++++++-------------- src/conversations/JobRunner.ts | 67 ++++++++++++ src/keystore/InMemoryKeystore.ts | 40 ++++++- src/keystore/LegacyStore.ts | 76 +++++++++++++ src/keystore/interfaces.ts | 10 ++ src/keystore/utils.ts | 8 ++ test/conversations/Conversations.test.ts | 48 --------- test/keystore/LegacyStore.test.ts | 41 +++++++ 10 files changed, 294 insertions(+), 131 deletions(-) create mode 100644 src/conversations/JobRunner.ts create mode 100644 src/keystore/LegacyStore.ts create mode 100644 test/keystore/LegacyStore.test.ts diff --git a/src/Client.ts b/src/Client.ts index 18555d2b9..c3ace3e56 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -36,7 +36,6 @@ import { BrowserStoragePersistence, InMemoryPersistence, Persistence, - PrefixedPersistence, } from './keystore/persistence' const { Compression } = proto @@ -243,7 +242,7 @@ export default class Client { > // addresses and key bundles that we have witnessed private _backupClient: BackupClient - private _conversations: Conversations + private readonly _conversations: Conversations // eslint-disable-next-line @typescript-eslint/no-explicit-any private _codecs: Map> private _maxContentSize: number diff --git a/src/Compression.ts b/src/Compression.ts index 452f2e456..1c4c66da6 100644 --- a/src/Compression.ts +++ b/src/Compression.ts @@ -34,7 +34,7 @@ export async function compress(encoded: proto.EncodedContent): Promise { encoded.content = sink.bytes } -function compressionIdFromCode(code: proto.Compression): string { +function compressionIdFromCode(code: proto.Compression) { if (code === proto.Compression.COMPRESSION_GZIP) { return 'gzip' } diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index dac749330..f8ca95364 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -9,6 +9,7 @@ import { MessageV1, DecodedMessage } from '../Message' import Stream from '../Stream' import Client from '../Client' import { + buildDirectMessageTopic, buildUserIntroTopic, buildUserInviteTopic, dateToNs, @@ -17,6 +18,7 @@ import { import { PublicKeyBundle } from '../crypto' import { SortDirection } from '../ApiClient' import Long from 'long' +import JobRunner from './JobRunner' const CLOCK_SKEW_OFFSET_MS = 10000 @@ -24,64 +26,18 @@ const messageHasHeaders = (msg: MessageV1): boolean => { return Boolean(msg.recipientAddress && msg.senderAddress) } -type CacheLoader = (args: { - latestSeen: Date | undefined - existing: Conversation[] -}) => Promise - -export class ConversationCache { - private conversations: Conversation[] - private mutex: Mutex - private latestSeen?: Date - private seenTopics: Set - - constructor() { - this.conversations = [] - this.mutex = new Mutex() - this.seenTopics = new Set() - } - - async load(loader: CacheLoader) { - const release = await this.mutex.acquire() - try { - const newConvos = await loader({ - latestSeen: this.latestSeen, - existing: this.conversations, - }) - for (const convo of newConvos) { - if (!this.seenTopics.has(convo.topic)) { - this.seenTopics.add(convo.topic) - this.conversations.push(convo) - if (!this.latestSeen || convo.createdAt > this.latestSeen) { - this.latestSeen = convo.createdAt - } - } - } - // No catch block so that errors still bubble - } finally { - release() - } - - return [...this.conversations] - } - - list() { - return [...this.conversations] - } -} - /** * Conversations allows you to view ongoing 1:1 messaging sessions with another wallet */ export default class Conversations { private client: Client - private v1Cache: ConversationCache - private v2Mutex: Mutex + private v1JobRunner: JobRunner + private v2JobRunner: JobRunner constructor(client: Client) { this.client = client - this.v1Cache = new ConversationCache() - this.v2Mutex = new Mutex() + this.v1JobRunner = new JobRunner('v1', client.keystore) + this.v2JobRunner = new JobRunner('v2', client.keystore) } /** @@ -104,8 +60,10 @@ export default class Conversations { * conversations on the network. */ async listFromCache(): Promise { - const v1Convos = this.v1Cache.list() - const v2Convos = await this.getV2ConversationsFromKeystore() + const [v1Convos, v2Convos]: Conversation[][] = await Promise.all([ + this.getV1ConversationsFromKeystore(), + this.getV2ConversationsFromKeystore(), + ]) const conversations = v1Convos.concat(v2Convos) conversations.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()) @@ -113,7 +71,7 @@ export default class Conversations { } private async listV1Conversations(): Promise { - return this.v1Cache.load(async ({ latestSeen }) => { + return this.v1JobRunner.run(async (latestSeen) => { const seenPeers = await this.getIntroductionPeers({ startTime: latestSeen ? new Date(+latestSeen - CLOCK_SKEW_OFFSET_MS) @@ -121,10 +79,20 @@ export default class Conversations { direction: SortDirection.SORT_DIRECTION_ASCENDING, }) - return Array.from(seenPeers).map( - ([peerAddress, sent]) => - new ConversationV1(this.client, peerAddress, sent) - ) + await this.client.keystore.saveV1Conversations({ + conversations: Array.from(seenPeers).map( + ([peerAddress, createdAt]) => ({ + peerAddress, + createdNs: dateToNs(createdAt), + topic: buildDirectMessageTopic(peerAddress, this.client.address), + context: undefined, + }) + ), + }) + + return ( + await this.client.keystore.getV1Conversations() + ).conversations.map(this.conversationReferenceToV1.bind(this)) }) } @@ -132,23 +100,11 @@ export default class Conversations { * List all V2 conversations */ private async listV2Conversations(): Promise { - return this.v2Mutex.runExclusive(async () => { + return this.v2JobRunner.run(async (lastRun) => { // Get all conversations already in the KeyStore const existing = await this.getV2ConversationsFromKeystore() - const latestConversation = existing.reduce( - (memo: ConversationV2 | undefined, curr: ConversationV2) => { - if (!memo || +curr.createdAt > +memo.createdAt) { - return curr - } - return memo - }, - undefined - ) - // Load all conversations started after the newest conversation found - const newConversations = await this.updateV2Conversations( - latestConversation?.createdAt - ) + const newConversations = await this.updateV2Conversations(lastRun) // Create a Set of all the existing topics to ensure no duplicates are added const existingTopics = new Set(existing.map((c) => c.topic)) @@ -172,6 +128,12 @@ export default class Conversations { ) } + private async getV1ConversationsFromKeystore(): Promise { + return (await this.client.keystore.getV1Conversations()).conversations.map( + this.conversationReferenceToV1.bind(this) + ) + } + // Called in listV2Conversations and in newConversation async updateV2Conversations(startTime?: Date): Promise { const envelopes = await this.client.listInvitations({ @@ -233,6 +195,16 @@ export default class Conversations { ) } + private conversationReferenceToV1( + convoRef: conversationReference.ConversationReference + ): ConversationV1 { + return new ConversationV1( + this.client, + convoRef.peerAddress, + nsToDate(convoRef.createdNs) + ) + } + /** * Returns a stream of any newly created conversations. * Will dedupe to not return the same conversation twice in the same stream. @@ -514,14 +486,14 @@ export default class Conversations { convo.peerAddress === peerAddress && isMatchingContext(context, convo.context ?? undefined) - return this.v2Mutex.runExclusive(async () => { - const existing = await this.getV2ConversationsFromKeystore() - const existingMatch = existing.find(matcherFn) - if (existingMatch) { - return existingMatch - } - const latestSeen = existing[existing.length - 1]?.createdAt - const newItems = await this.updateV2Conversations(latestSeen) + const existing = await this.getV2ConversationsFromKeystore() + const existingMatch = existing.find(matcherFn) + if (existingMatch) { + return existingMatch + } + + return this.v2JobRunner.run(async (lastRun) => { + const newItems = await this.updateV2Conversations(lastRun) const newItemMatch = newItems.find(matcherFn) // If one of those matches, return it to update the cache if (newItemMatch) { diff --git a/src/conversations/JobRunner.ts b/src/conversations/JobRunner.ts new file mode 100644 index 000000000..00e83c83d --- /dev/null +++ b/src/conversations/JobRunner.ts @@ -0,0 +1,67 @@ +import { keystore } from '@xmtp/proto' +import { Mutex } from 'async-mutex' +import { Keystore } from '../keystore' +import Long from 'long' +import { dateToNs, nsToDate } from '../utils' + +type JobType = 'v1' | 'v2' + +type UpdateJob = (lastRun: Date | undefined) => Promise + +export default class JobRunner { + readonly jobType: JobType + readonly mutex: Mutex + readonly keystore: Keystore + + constructor(jobType: JobType, keystore: Keystore) { + this.jobType = jobType + this.mutex = new Mutex() + this.keystore = keystore + } + + get protoJobType(): keystore.JobType { + return getProtoJobType(this.jobType) + } + + async run(callback: UpdateJob): Promise { + return this.mutex.runExclusive(async () => { + const lastRun = await this.getLastRunTime() + const startTime = new Date() + const result = await callback(lastRun) + await this.setLastRunTime(startTime) + return result + }) + } + + private async getLastRunTime(): Promise { + const { lastRunNs } = await this.keystore.getRefreshJob( + keystore.GetRefreshJobRequest.fromPartial({ + jobType: this.protoJobType, + }) + ) + if (lastRunNs.equals(Long.fromNumber(0))) { + return undefined + } + return nsToDate(lastRunNs) + } + + private async setLastRunTime(lastRun: Date): Promise { + await this.keystore.setRefreshJob({ + jobType: this.protoJobType, + lastRunNs: dateToNs(lastRun), + }) + } +} + +function getProtoJobType(jobType: 'v1' | 'v2'): keystore.JobType { + const protoJobType = { + v1: keystore.JobType.JOB_TYPE_REFRESH_V1, + v2: keystore.JobType.JOB_TYPE_REFRESH_V2, + }[jobType] + + if (!protoJobType) { + throw new Error(`unknown job type: ${jobType}`) + } + + return protoJobType +} diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 20d5d1919..c17221655 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -23,7 +23,11 @@ import { getKeyMaterial, topicDataToConversationReference, } from './utils' -import { nsToDate, buildDirectMessageTopicV2 } from '../utils' +import { + nsToDate, + buildDirectMessageTopicV2, + buildDirectMessageTopic, +} from '../utils' import InviteStore from './InviteStore' import { Persistence } from './persistence' import LocalAuthenticator from '../authn/LocalAuthenticator' @@ -32,6 +36,7 @@ import crypto from '../crypto/crypto' import { bytesToHex } from '../crypto/utils' import Long from 'long' import { SetRefreshJobResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' +import LegacyStore from './LegacyStore' const { ErrorCode } = keystore // Constant, 32 byte salt @@ -58,6 +63,7 @@ export default class InMemoryKeystore implements Keystore { private v1Keys: PrivateKeyBundleV1 private v2Keys: PrivateKeyBundleV2 // Do I need this? private inviteStore: InviteStore + private v1Store: LegacyStore private authenticator: LocalAuthenticator private accountAddress: string | undefined private jobStatePersistence: Persistence @@ -65,11 +71,13 @@ export default class InMemoryKeystore implements Keystore { constructor( keys: PrivateKeyBundleV1, inviteStore: InviteStore, + v1Store: LegacyStore, persistence: Persistence ) { this.v1Keys = keys this.v2Keys = PrivateKeyBundleV2.fromLegacyBundle(keys) this.inviteStore = inviteStore + this.v1Store = v1Store this.authenticator = new LocalAuthenticator(keys.identityKey) this.jobStatePersistence = persistence } @@ -78,10 +86,15 @@ export default class InMemoryKeystore implements Keystore { return new InMemoryKeystore( keys, await InviteStore.create(persistence), + await LegacyStore.create(persistence), persistence ) } + get walletAddress(): string { + return this.v1Keys.identityKey.publicKey.walletSignatureAddress() + } + async decryptV1( req: keystore.DecryptV1Request ): Promise { @@ -380,6 +393,31 @@ export default class InMemoryKeystore implements Keystore { return key.sign(digest) } + async saveV1Conversations({ + conversations, + }: keystore.SaveV1ConversationsRequest): Promise { + await this.v1Store.add( + conversations.map((convo) => ({ + peerAddress: convo.peerAddress, + createdNs: convo.createdNs, + invitation: undefined, + })) + ) + + return {} + } + + async getV1Conversations(): Promise { + const convos = this.v1Store.entries.map((reference) => ({ + peerAddress: reference.peerAddress, + createdNs: reference.createdNs, + topic: buildDirectMessageTopic(reference.peerAddress, this.walletAddress), + context: undefined, + })) + + return { conversations: convos } + } + async getV2Conversations(): Promise< conversationReference.ConversationReference[] > { diff --git a/src/keystore/LegacyStore.ts b/src/keystore/LegacyStore.ts new file mode 100644 index 000000000..6dbda2aa4 --- /dev/null +++ b/src/keystore/LegacyStore.ts @@ -0,0 +1,76 @@ +import { keystore } from '@xmtp/proto' +import { Persistence } from './persistence/interface' +import { Mutex } from 'async-mutex' +import Long from 'long' +import { topicDataToMap } from './utils' + +const LEGACY_KEY = 'legacy-convos/v1' + +type Entry = { + peerAddress: string + createdNs: Long + invitation: undefined +} + +/** + * InviteStore holds a simple map of topic -> TopicData and writes to the persistence layer on changes + */ +export default class LegacyStore { + private persistence: Persistence + private mutex: Mutex + private topicMap: Map + + constructor( + persistence: Persistence, + initialData: Map = new Map() + ) { + this.persistence = persistence + this.mutex = new Mutex() + this.topicMap = initialData + } + + static async create(persistence: Persistence): Promise { + const rawData = await persistence.getItem(LEGACY_KEY) + if (rawData) { + try { + const topicMap = keystore.TopicMap.decode(rawData) + // Create an InviteStore with data preloaded + return new LegacyStore( + persistence, + topicDataToMap(topicMap) as Map + ) + } catch (e) { + console.warn(`Error loading invites from store: ${e}`) + } + } + return new LegacyStore(persistence) + } + + async add(topicData: Entry[]): Promise { + await this.mutex.runExclusive(async () => { + let isDirty = false + for (const row of topicData) { + // This will not overwrite any existing values. First invite found in the store for a given topic will always be used + // Duplicates do not throw errors + if (!this.topicMap.has(row.peerAddress)) { + this.topicMap.set(row.peerAddress, row) + isDirty = true + } + } + // Only write to persistence once, and only if we have added new invites + if (isDirty) { + await this.persistence.setItem(LEGACY_KEY, this.toBytes()) + } + }) + } + + get entries(): Entry[] { + return [...this.topicMap.values()] + } + + private toBytes(): Uint8Array { + return keystore.TopicMap.encode({ + topics: Object.fromEntries(this.topicMap), + }).finish() + } +} diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index 30a947193..0e9089559 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -62,6 +62,16 @@ export interface Keystore { setRefreshJob( req: keystore.SetRefeshJobRequest ): Promise + /** + * Save V1 Conversations + */ + saveV1Conversations( + req: keystore.SaveV1ConversationsRequest + ): Promise + /** + * Get a list of V1 conversations + */ + getV1Conversations(): Promise /** * Get a list of V2 conversations */ diff --git a/src/keystore/utils.ts b/src/keystore/utils.ts index 534953ba9..7cb86ff40 100644 --- a/src/keystore/utils.ts +++ b/src/keystore/utils.ts @@ -136,5 +136,13 @@ export const typeSafeTopicMap = ( return out } +export const topicDataToMap = (topicMap: keystore.TopicMap) => { + const out = new Map() + for (const [k, v] of Object.entries(topicMap.topics)) { + out.set(k, v) + } + return out +} + export const buildPersistenceKey = (env: XmtpEnv, walletAddress: string) => `xmtp/${env}/${walletAddress}/` diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index c1be581ae..24cb5edf8 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -2,7 +2,6 @@ import { ConversationV1, ConversationV2, } from './../../src/conversations/Conversation' -import { ConversationCache } from '../../src/conversations/Conversations' import { newLocalHostClient, newWallet, waitForUserContact } from './../helpers' import { Client } from '../../src' import { @@ -113,53 +112,6 @@ describe('conversations', () => { const aliceConversations3 = await alice.conversations.list() expect(aliceConversations3).toHaveLength(2) }) - - it('caches results and updates the latestSeen date', async () => { - const cache = new ConversationCache() - const convoDate = new Date() - const firstConvo = new ConversationV1(alice, bob.address, convoDate) - - const results = await cache.load(async () => { - return [firstConvo] - }) - expect(results[0]).toBe(firstConvo) - - // Should dedupe repeated result - const results2 = await cache.load(async ({ latestSeen }) => { - expect(latestSeen).toBe(convoDate) - return [firstConvo] - }) - - expect(results2).toHaveLength(1) - }) - - it('bubbles up errors in loader', async () => { - const cache = new ConversationCache() - await expect( - cache.load(async () => { - throw new Error('test') - }) - ).rejects.toThrow('test') - }) - - it('waits for one request to finish before the second one starts', async () => { - const cache = new ConversationCache() - const convoDate = new Date() - const firstConvo = new ConversationV1(alice, bob.address, convoDate) - const promise1 = cache.load(async ({ latestSeen }) => { - expect(latestSeen).toBeUndefined() - return [firstConvo] - }) - - const promise2 = cache.load(async ({ latestSeen }) => { - expect(latestSeen).toBe(convoDate) - return [] - }) - - const [result1, result2] = await Promise.all([promise1, promise2]) - expect(result1).toHaveLength(1) - expect(result2).toHaveLength(1) - }) }) it('streams conversations', async () => { diff --git a/test/keystore/LegacyStore.test.ts b/test/keystore/LegacyStore.test.ts new file mode 100644 index 000000000..ee2d147d5 --- /dev/null +++ b/test/keystore/LegacyStore.test.ts @@ -0,0 +1,41 @@ +import Long from 'long' +import { InMemoryPersistence, dateToNs } from '../../src' +import LegacyStore from '../../src/keystore/LegacyStore' +import { getRandomValues } from 'crypto' + +const buildConvoReference = ({ + peerAddress, + createdNs, +}: { + peerAddress?: string + createdNs?: Long +}) => ({ + peerAddress: + peerAddress || + Buffer.from(getRandomValues(new Uint8Array(32))).toString('hex'), + createdNs: dateToNs(new Date()).toUnsigned(), + invitation: undefined, +}) + +describe('LegacyStore', () => { + it('round trips', async () => { + const convo = buildConvoReference({}) + const store = await LegacyStore.create(InMemoryPersistence.create()) + await store.add([convo]) + expect(store.entries).toEqual([convo]) + }) + + it('persists correctly', async () => { + const convos = [buildConvoReference({}), buildConvoReference({})] + const persistence = InMemoryPersistence.create() + const store = await LegacyStore.create(persistence) + await store.add(convos) + expect(store.entries).toEqual(convos) + + const store2 = await LegacyStore.create(persistence) + console.log(store.entries, store2.entries) + expect(store2.entries).toEqual(store.entries) + + expect(await persistence.getItem('legacy-convos/v1')).toBeDefined() + }) +}) From 9e4160af2a61c2b2b549c0822578f660e9fae94b Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Wed, 23 Aug 2023 23:13:27 -0700 Subject: [PATCH 086/137] feat: remove group chat stuff --- src/Client.ts | 21 --- src/Compression.ts | 2 +- src/codecs/GroupChatMemberAdded.ts | 35 ----- src/codecs/GroupChatTitleChanged.ts | 35 ----- src/codecs/TypingNotification.ts | 50 ------- src/conversations/Conversations.ts | 158 +---------------------- src/conversations/GroupChat.ts | 119 ----------------- src/conversations/GroupConversation.ts | 97 -------------- src/index.ts | 16 --- src/keystore/InMemoryKeystore.ts | 99 +------------- src/keystore/interfaces.ts | 20 +-- src/utils/topic.ts | 4 - test/conversations/Conversations.test.ts | 126 ------------------ 13 files changed, 7 insertions(+), 775 deletions(-) delete mode 100644 src/codecs/GroupChatMemberAdded.ts delete mode 100644 src/codecs/GroupChatTitleChanged.ts delete mode 100644 src/codecs/TypingNotification.ts delete mode 100644 src/conversations/GroupChat.ts delete mode 100644 src/conversations/GroupConversation.ts diff --git a/src/Client.ts b/src/Client.ts index fb556eaab..cfb718de9 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -5,7 +5,6 @@ import { mapPaginatedStream, EnvelopeMapper, buildUserInviteTopic, - buildUserGroupInviteTopic, } from './utils' import { utils } from 'ethers' import { Signer } from './types/Signer' @@ -240,7 +239,6 @@ export default class Client { // eslint-disable-next-line @typescript-eslint/no-explicit-any private _codecs: Map> private _maxContentSize: number - private _isGroupChatEnabled = false constructor( publicKeyBundle: PublicKeyBundle, @@ -264,10 +262,6 @@ export default class Client { this._backupClient = backupClient } - get isGroupChatEnabled(): boolean { - return this._isGroupChatEnabled - } - /** * @type {Conversations} */ @@ -354,11 +348,6 @@ export default class Client { } } - enableGroupChat() { - GroupChat.registerCodecs(this) - this._isGroupChatEnabled = true - } - // gracefully shut down the client async close(): Promise { return undefined @@ -633,16 +622,6 @@ export default class Client { ) } - listGroupInvitations( - opts?: ListMessagesOptions - ): Promise { - return this.listEnvelopes( - buildUserGroupInviteTopic(this.address), - async (env) => env, - opts - ) - } - /** * List stored messages from the specified topic. * diff --git a/src/Compression.ts b/src/Compression.ts index 452f2e456..1c4c66da6 100644 --- a/src/Compression.ts +++ b/src/Compression.ts @@ -34,7 +34,7 @@ export async function compress(encoded: proto.EncodedContent): Promise { encoded.content = sink.bytes } -function compressionIdFromCode(code: proto.Compression): string { +function compressionIdFromCode(code: proto.Compression) { if (code === proto.Compression.COMPRESSION_GZIP) { return 'gzip' } diff --git a/src/codecs/GroupChatMemberAdded.ts b/src/codecs/GroupChatMemberAdded.ts deleted file mode 100644 index 758faf89e..000000000 --- a/src/codecs/GroupChatMemberAdded.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' - -export const ContentTypeGroupChatMemberAdded = new ContentTypeId({ - typeId: 'groupChatMemberAdded', - authorityId: 'xmtp.org', - versionMajor: 1, - versionMinor: 0, -}) - -export type GroupChatMemberAdded = { - member: string -} - -export class GroupChatMemberAddedCodec - implements ContentCodec -{ - contentType = ContentTypeGroupChatMemberAdded - - encode(content: GroupChatMemberAdded): EncodedContent { - if (content.member.length !== 42) { - throw new Error('Invalid member address') - } - - return { - type: ContentTypeGroupChatMemberAdded, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - } - } - - decode(encodedContent: EncodedContent): GroupChatMemberAdded { - const json = new TextDecoder().decode(encodedContent.content) - return JSON.parse(json) - } -} diff --git a/src/codecs/GroupChatTitleChanged.ts b/src/codecs/GroupChatTitleChanged.ts deleted file mode 100644 index a4baa68ff..000000000 --- a/src/codecs/GroupChatTitleChanged.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' - -export const ContentTypeGroupChatTitleChanged = new ContentTypeId({ - typeId: 'groupChatTitleChanged', - authorityId: 'xmtp.org', - versionMajor: 1, - versionMinor: 0, -}) - -export type GroupChatTitleChanged = { - newTitle: string -} - -export class GroupChatTitleChangedCodec - implements ContentCodec -{ - contentType = ContentTypeGroupChatTitleChanged - - encode(content: GroupChatTitleChanged): EncodedContent { - if (content.newTitle.length === 0 || content.newTitle.length > 256) { - throw new Error('Invalid newTitle') - } - - return { - type: ContentTypeGroupChatTitleChanged, - parameters: {}, - content: new TextEncoder().encode(JSON.stringify(content)), - } - } - - decode(encodedContent: EncodedContent): GroupChatTitleChanged { - const json = new TextDecoder().decode(encodedContent.content) - return JSON.parse(json) - } -} diff --git a/src/codecs/TypingNotification.ts b/src/codecs/TypingNotification.ts deleted file mode 100644 index de3e89df5..000000000 --- a/src/codecs/TypingNotification.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ContentTypeId, ContentCodec, EncodedContent } from '../MessageContent' - -// xmtp.org/typingNotification -// -// This content type is used for typing notifications -export const ContentTypeTypingNotification = new ContentTypeId({ - authorityId: 'xmtp.com', - typeId: 'typingNotification', - versionMajor: 1, - versionMinor: 0, -}) - -export type TypingNotification = { - timestamp: Date - typerAddress: string - isFinished: boolean -} - -// Important: Typing Notifications should only be sent on ephemeral topics. -export class TypingNotificationCodec - implements ContentCodec -{ - get contentType(): ContentTypeId { - return ContentTypeTypingNotification - } - - encode(content: TypingNotification): EncodedContent { - return { - type: ContentTypeTypingNotification, - parameters: { - timestamp: content.timestamp.toISOString(), - typerAddress: content.typerAddress, - isFinished: content.isFinished ? 'true' : 'false', - }, - content: new Uint8Array(), - } - } - - decode(content: EncodedContent): TypingNotification { - const timestamp = new Date(content.parameters.timestamp) - const typerAddress = content.parameters.senderAddress - const isFinished = content.parameters.isFinished === 'true' - - return { - timestamp, - typerAddress, - isFinished, - } - } -} diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 48a1656a1..7746e2f93 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -18,7 +18,6 @@ import { PublicKeyBundle } from '../crypto' import { SortDirection } from '../ApiClient' import Long from 'long' import { toSignedPublicKeyBundle } from '../keystore/utils' -import { GroupConversation } from './GroupConversation' import { bytesToHex } from '../crypto/utils' import crypto from '../crypto/crypto' @@ -151,30 +150,10 @@ export default class Conversations { ) // Load all conversations started after the newest conversation found - let newConversations = await this.updateV2Conversations( + const newConversations = await this.updateV2Conversations( latestConversation?.createdAt ) - if (this.client.isGroupChatEnabled) { - const groupConversations = - await this.getGroupConversationsFromKeystore() - const latestGroupConversation = groupConversations.reduce( - (memo: GroupConversation | undefined, curr: GroupConversation) => { - if (!memo || +curr.createdAt > +memo.createdAt) { - return curr - } - return memo - }, - undefined - ) - - newConversations = newConversations.concat( - await this.updateGroupConversations( - latestGroupConversation?.createdAt - ) - ) - } - // Create a Set of all the existing topics to ensure no duplicates are added const existingTopics = new Set(existing.map((c) => c.topic)) // Add all new conversations to the existing list @@ -209,32 +188,6 @@ export default class Conversations { return this.decodeInvites(envelopes) } - private async getGroupConversationsFromKeystore(): Promise< - GroupConversation[] - > { - return ( - await this.client.keystore.getGroupConversations() - ).conversations.map((ref) => { - return GroupConversation.from(this.conversationReferenceToV2(ref)) - }) - } - - // Called in listV2Conversations and in newConversation - async updateGroupConversations( - startTime?: Date - ): Promise { - const envelopes = await this.client.listGroupInvitations({ - startTime: startTime - ? new Date(+startTime - CLOCK_SKEW_OFFSET_MS) - : undefined, - direction: SortDirection.SORT_DIRECTION_ASCENDING, - }) - - return (await this.decodeInvites(envelopes)).map((conversation) => - GroupConversation.from(conversation) - ) - } - private async decodeInvites( envelopes: messageApi.Envelope[], shouldThrow = false @@ -294,7 +247,6 @@ export default class Conversations { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) - const groupInviteTopic = buildUserGroupInviteTopic(this.client.address) const newPeer = (peerAddress: string): boolean => { // Check if we have seen the peer already in this stream @@ -318,23 +270,13 @@ export default class Conversations { await msg.decrypt(this.client.keystore, this.client.publicKeyBundle) return new ConversationV1(this.client, peerAddress, msg.sent) } - if ( - env.contentTopic === inviteTopic || - env.contentTopic === groupInviteTopic - ) { + if (env.contentTopic === inviteTopic) { const results = await this.decodeInvites([env], true) if (results.length) { return results[0] } } - if (env.contentTopic === groupInviteTopic) { - const results = await this.decodeInvites([env], true) - if (results.length) { - const result = results[0] - result.isGroup = true - return result - } - } + throw new Error('unrecognized invite topic') } @@ -361,14 +303,9 @@ export default class Conversations { ): Promise> { const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) - const groupInviteTopic = buildUserGroupInviteTopic(this.client.address) const topics = new Set([introTopic, inviteTopic]) - if (this.client.isGroupChatEnabled) { - topics.add(groupInviteTopic) - } - const convoMap = new Map() for (const conversation of await this.list()) { @@ -528,95 +465,6 @@ export default class Conversations { return seenPeers } - async newGroupConversation( - initialMembers: string[] - ): Promise { - if (!this.client.isGroupChatEnabled) { - throw new Error('Group chat is not enabled for client') - } - - initialMembers = [...new Set(initialMembers)].filter( - (address) => address !== this.client.address - ) - - if (initialMembers.length === 0) { - throw new Error('No initial members provided') - } - - const groupID = bytesToHex(crypto.getRandomValues(new Uint8Array(32))) - const context = { - conversationId: `xmtp.org/groups/${groupID}`, - metadata: { - initialMembers: [ - ...new Set(initialMembers.concat(this.client.address)), - ].join(','), - }, - } - - const timestamp = new Date() - const members = await Promise.all( - initialMembers.map(async (member) => { - let contact = await this.client.getUserContact(member) - if (!contact) { - throw new Error(`Recipient ${member} is not on the XMTP network`) - } - - // Coerce the contact into a V2 bundle - if (contact instanceof PublicKeyBundle) { - contact = SignedPublicKeyBundle.fromLegacyBundle(contact) - } - - return toSignedPublicKeyBundle(contact) - }) - ) - - const inviteResponses = await this.client.keystore.createInvites({ - recipients: members, - context, - createdNs: dateToNs(timestamp), - }) - - const envelopes = inviteResponses.map((response) => { - if (!response.conversation) { - throw new Error( - 'no conversation for response: ' + JSON.stringify(response) - ) - } - - return { - contentTopic: buildUserGroupInviteTopic( - response.conversation?.peerAddress - ), - message: response.payload, - timestamp, - } - }) - - // Copy one of the invites to use for the creator. We do this to avoid having - // to self Diffie-Hellman which is problematic, security wise. - // - // This approach works because sealed invitation decrypting is sender/recipient - // agnostic. - // - // See https://github.com/xmtp/xmtp-js/blob/829257c10947618c34a66aa3857ca3557d4b52b6/src/Invitation.ts#L148-L160 - const creatorEnvelope = { ...envelopes[0] } - creatorEnvelope.contentTopic = buildUserGroupInviteTopic( - this.client.address - ) - - const envelopesToPublish = [creatorEnvelope, ...envelopes] - - await this.client.publishEnvelopes(envelopesToPublish) - - const conversation = inviteResponses[0].conversation - - if (!conversation) { - throw new Error('no conversation for response') - } - - return GroupConversation.from(this.conversationReferenceToV2(conversation)) - } - /** * Creates a new conversation for the given address. Will throw an error if the peer is not found in the XMTP network */ diff --git a/src/conversations/GroupChat.ts b/src/conversations/GroupChat.ts deleted file mode 100644 index 1c83ffa5e..000000000 --- a/src/conversations/GroupChat.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - Client, - Conversation, - GroupConversation, - SortDirection, -} from '../index' -import { - ContentTypeGroupChatMemberAdded, - GroupChatMemberAdded, - GroupChatMemberAddedCodec, -} from '../codecs/GroupChatMemberAdded' -import { - ContentTypeGroupChatTitleChanged, - GroupChatTitleChanged, - GroupChatTitleChangedCodec, -} from '../codecs/GroupChatTitleChanged' - -type RebuildOptions = { - since: Date -} - -export class GroupChat { - static codecs = [ - new GroupChatMemberAddedCodec(), - new GroupChatTitleChangedCodec(), - ] - - static registerCodecs(client: Client) { - for (const codec of GroupChat.codecs) { - client.registerCodec(codec) - } - } - - title = '' - memberClient: Client - conversation: Conversation - _members: string[] = [] - _memberConversation: Conversation | undefined - - get members(): string[] { - return [...new Set(this._members)] - } - - set members(members: string[]) { - this._members = [...new Set(members)] - } - - constructor(memberClient: Client, conversation: Conversation) { - this.memberClient = memberClient - this.conversation = conversation - } - - static async fromConversation( - client: Client, - conversation: Conversation - ): Promise { - const groupChat = new GroupChat(client, conversation) - await groupChat.rebuild() - - return groupChat - } - - async rebuild(opts?: RebuildOptions | undefined) { - const members = - this.conversation.context?.metadata.initialMembers.split(',') - - if (!members) { - throw new Error('Conversation is not a group chat') - } - - this._members = members - - const startTime = opts?.since - - const messages = startTime - ? await this.conversation.messages({ - startTime, - direction: SortDirection.SORT_DIRECTION_ASCENDING, - }) - : await this.conversation.messages() - - for (const message of messages) { - if (message.contentType.sameAs(ContentTypeGroupChatMemberAdded)) { - const groupChatMemberAdded = message.content as GroupChatMemberAdded - this._members.push(groupChatMemberAdded.member) - } else if (message.contentType.sameAs(ContentTypeGroupChatTitleChanged)) { - const groupChatTitleChanged = message.content as GroupChatTitleChanged - this.title = groupChatTitleChanged.newTitle - } - } - } - - async changeTitle(newTitle: string) { - const titleChange: GroupChatTitleChanged = { - newTitle, - } - - await this.conversation.send(titleChange, { - contentType: ContentTypeGroupChatTitleChanged, - contentFallback: `${this.memberClient.address} changed the group title to ${newTitle}`, - }) - } - - async addMember(newMemberAddress: string) { - const memberAdded: GroupChatMemberAdded = { - member: newMemberAddress, - } - - this._members.push(newMemberAddress) - - const conversation = GroupConversation.from(this.conversation, this.members) - await conversation.addMember(newMemberAddress) - - await this.conversation.send(memberAdded, { - contentType: ContentTypeGroupChatMemberAdded, - contentFallback: `${this.memberClient.address} added ${newMemberAddress} to the group`, - }) - } -} diff --git a/src/conversations/GroupConversation.ts b/src/conversations/GroupConversation.ts deleted file mode 100644 index fa7f11be5..000000000 --- a/src/conversations/GroupConversation.ts +++ /dev/null @@ -1,97 +0,0 @@ -import Client from '../Client' -import { Conversation, ConversationV2 } from './Conversation' -import { InvitationContext } from '../Invitation' -import { PublicKeyBundle, SignedPublicKeyBundle } from '../crypto' -import { toSignedPublicKeyBundle } from '../keystore/utils' -import { buildUserInviteTopic, dateToNs } from '../utils' - -export class GroupConversation extends ConversationV2 implements Conversation { - client: Client - peerAddress: string - topic: string - createdAt: Date - memberAddresses: string[] = [] - isGroup = true - - constructor( - client: Client, - topic: string, - peerAddress: string, - createdAt: Date, - context: InvitationContext | undefined, - membersAddresses: string[] - ) { - super(client, topic, peerAddress, createdAt, context) - this.topic = topic - this.createdAt = createdAt - this.context = context - this.client = client - this.peerAddress = peerAddress - this.memberAddresses = membersAddresses - } - - static from( - conversation: Conversation, - members?: string[] - ): GroupConversation { - if (!(conversation instanceof ConversationV2)) { - throw new Error('Conversation is not a V2 conversation') - } - - const memberAddresses = - members || - conversation.context?.metadata?.initialMembers?.split(',') || - [] - - if (memberAddresses.length === 0) { - throw new Error('Conversation has no member addresses') - } - - return new GroupConversation( - conversation.client, - conversation.topic, - conversation.peerAddress, - conversation.createdAt, - conversation.context, - memberAddresses - ) - } - - async addMember(newMemberAddress: string) { - const timestamp = new Date() - - let contact = await this.client.getUserContact(newMemberAddress) - if (!contact) { - throw new Error( - `Recipient ${newMemberAddress} is not on the XMTP network` - ) - } - - // Coerce the contact into a V2 bundle - if (contact instanceof PublicKeyBundle) { - contact = SignedPublicKeyBundle.fromLegacyBundle(contact) - } - - const recipient = toSignedPublicKeyBundle(contact) - - const inviteResponse = await this.client.keystore.createInviteFromTopic({ - contentTopic: this.topic, - recipient, - createdNs: dateToNs(timestamp), - }) - - if (!inviteResponse.conversation) { - throw new Error( - 'no conversation for response: ' + JSON.stringify(inviteResponse) - ) - } - - const envelope = { - contentTopic: buildUserInviteTopic(newMemberAddress), - message: inviteResponse.payload, - timestamp, - } - - await this.client.publishEnvelopes([envelope]) - } -} diff --git a/src/index.ts b/src/index.ts index c07ae0d38..cc0920850 100644 --- a/src/index.ts +++ b/src/index.ts @@ -49,11 +49,6 @@ export { ContentTypeFallback, } from './MessageContent' export { TextCodec, ContentTypeText } from './codecs/Text' -export { - TypingNotification, - TypingNotificationCodec, - ContentTypeTypingNotification, -} from './codecs/TypingNotification' export { Composite, CompositeCodec, @@ -112,14 +107,3 @@ export { } from './keystore/persistence' export { InvitationContext, SealedInvitation } from './Invitation' export { decodeContactBundle } from './ContactBundle' -export { GroupChat } from './conversations/GroupChat' -export { - GroupChatMemberAdded, - GroupChatMemberAddedCodec, - ContentTypeGroupChatMemberAdded, -} from './codecs/GroupChatMemberAdded' -export { - GroupChatTitleChanged, - GroupChatTitleChangedCodec, - ContentTypeGroupChatTitleChanged, -} from './codecs/GroupChatTitleChanged' diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 1d962813c..285048fb9 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -318,87 +318,6 @@ export default class InMemoryKeystore implements Keystore { } } - async createInvites( - req: keystore.CreateInvitesRequest - ): Promise { - try { - if (!validateObject(req, ['recipients'], [])) { - throw new KeystoreError( - ErrorCode.ERROR_CODE_INVALID_INPUT, - 'missing recipients' - ) - } - - const invitation = InvitationV1.createRandom(req.context) - const created = nsToDate(req.createdNs) - const recipients = req.recipients.map(toSignedPublicKeyBundle) - - return Promise.all( - recipients.map(async (recipient) => { - return await this.makeInvite( - this.v2Keys, - recipient, - created, - req.createdNs, - invitation - ) - }) - ) - } catch (e) { - throw convertError(e as Error, ErrorCode.ERROR_CODE_INVALID_INPUT) - } - } - - async createInviteFromTopic( - req: keystore.CreateInviteFromTopicRequest - ): Promise { - try { - if (!validateObject(req, ['contentTopic'], [])) { - throw new KeystoreError( - ErrorCode.ERROR_CODE_INVALID_INPUT, - 'missing topic' - ) - } - - if (!validateObject(req, ['createdNs'], [])) { - throw new KeystoreError( - ErrorCode.ERROR_CODE_INVALID_INPUT, - 'missing createdNs' - ) - } - - let topicData = this.inviteStore.lookup(req.contentTopic) - if (!topicData) { - throw new KeystoreError( - ErrorCode.ERROR_CODE_INVALID_INPUT, - 'missing topic data' - ) - } - - topicData = { ...topicData } - - const invitation = new InvitationV1({ - context: topicData.invitation.context, - topic: req.contentTopic, - aes256GcmHkdfSha256: topicData.invitation.aes256GcmHkdfSha256, - }) - - const recipient = toSignedPublicKeyBundle(req.recipient) - - topicData.createdNs = req.createdNs - - return await this.makeInvite( - this.v2Keys, - recipient, - nsToDate(req.createdNs), - topicData.createdNs, - invitation - ) - } catch (e) { - throw convertError(e as Error, ErrorCode.ERROR_CODE_INVALID_INPUT) - } - } - private async makeInvite( senderKeys: PrivateKeyBundleV2, recipient: SignedPublicKeyBundle, @@ -468,7 +387,7 @@ export default class InMemoryKeystore implements Keystore { return key.sign(digest) } - async getV2Conversations(): Promise { + async getV2Conversations(): Promise { const convos = this.inviteStore.topics.map((invite) => topicDataToConversationReference(invite) ) @@ -476,21 +395,7 @@ export default class InMemoryKeystore implements Keystore { convos.sort((a, b) => a.createdNs.div(1_000_000).sub(b.createdNs.div(1_000_000)).toNumber() ) - return keystore.GetV2ConversationsResponse.fromPartial({ - conversations: convos, - }) - } - - async getGroupConversations(): Promise { - const convos = this.inviteStore.groupTopics.map((invite) => - topicDataToConversationReference(invite) - ) - - convos.sort((a, b) => - a.createdNs.div(1_000_000).sub(b.createdNs.div(1_000_000)).toNumber() - ) - - return keystore.GetV2ConversationsResponse.fromPartial({ + return keystore.GetConversationsResponse.fromPartial({ conversations: convos, }) } diff --git a/src/keystore/interfaces.ts b/src/keystore/interfaces.ts index bc3991b7c..bf3bc0253 100644 --- a/src/keystore/interfaces.ts +++ b/src/keystore/interfaces.ts @@ -35,20 +35,6 @@ export interface Keystore { createInvite( req: keystore.CreateInviteRequest ): Promise - /** - * Create multiple sealed/encrypted invites and store the Topic keys in the Keystore for later use. - * The returned invite payload must be sent to the network for the other party to be able to communicate. - */ - createInvites( - req: keystore.CreateInvitesRequest - ): Promise - /** - * Create a sealed/encrypted invite for the given topic and store the Topic keys in the Keystore for later use. - * The returned invite payload must be sent to the network for the other party to be able to communicate. - */ - createInviteFromTopic( - req: keystore.CreateInviteFromTopicRequest - ): Promise /** * Create an XMTP auth token to be used as a header on XMTP API requests */ @@ -60,11 +46,7 @@ export interface Keystore { /** * Get a list of V2 conversations */ - getV2Conversations(): Promise - /** - * Get a list of group conversations - */ - getGroupConversations(): Promise + getV2Conversations(): Promise /** * Get the `PublicKeyBundle` associated with the Keystore's private keys */ diff --git a/src/utils/topic.ts b/src/utils/topic.ts index 9f2c174a4..5290cbf51 100644 --- a/src/utils/topic.ts +++ b/src/utils/topic.ts @@ -27,10 +27,6 @@ export const buildUserIntroTopic = (walletAddr: string): string => { return buildContentTopic(`intro-${utils.getAddress(walletAddr)}`) } -export const buildUserGroupInviteTopic = (walletAddr: string): string => { - return buildContentTopic(`groupInvite-${utils.getAddress(walletAddr)}`) -} - export const buildUserInviteTopic = (walletAddr: string): string => { // EIP55 normalize the address case. return buildContentTopic(`invite-${utils.getAddress(walletAddr)}`) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index c2bac7f31..8f6c77da2 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -117,53 +117,6 @@ describe('conversations', () => { expect(aliceConversations3).toHaveLength(2) }) - it('loads group chats when group chat is enabled after first load', async () => { - const aliceConversations1 = await alice.conversations.list() - expect(aliceConversations1).toHaveLength(0) - alice.enableGroupChat() - - const groupConvo = await alice.conversations.newGroupConversation([ - bob.address, - ]) - await sleep(100) - const bobConversations = await bob.conversations.list() - - // Group Chat isn't enabled for this client so we're not checking the group chat - // topic. As a result this should be empty. - expect(bobConversations).toHaveLength(0) - - // Make sure bob doesn't have group chat enabled - expect(bob.isGroupChatEnabled).toBeFalsy() - // Make sure creating a group chat from a client without it enabled fails - expect( - bob.conversations.newGroupConversation([ - '0x0000000000000000000000000000000000000000', - ]) - ).rejects.toThrow('Group chat is not enabled for client') - - // Create a 1:1 convo for bob - const conversation = await bob.conversations.newConversation( - alice.address, - { - conversationId: 'foo', - metadata: {}, - } - ) - await sleep(100) - const bobConversations2 = await bob.conversations.list() - expect(bobConversations2).toHaveLength(1) - expect(bobConversations2[0].topic).toBe(conversation.topic) - - // Enable group chat for bob - bob.enableGroupChat() - - // Make sure group chat loads for bob - const bobConversations3 = await bob.conversations.list() - expect(bobConversations3).toHaveLength(2) - expect(bobConversations3[0].topic).toBe(groupConvo.topic) - expect(bobConversations3[0].isGroup).toBe(true) - }) - it('caches results and updates the latestSeen date', async () => { const cache = new ConversationCache() const convoDate = new Date() @@ -227,33 +180,6 @@ describe('conversations', () => { await stream.return() }) - it('streams group conversations', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - - const stream = await alice.conversations.stream() - - // make sure it works with 1:1 convo - await alice.conversations.newConversation(bob.address, { - conversationId: 'foo', - metadata: {}, - }) - - const conversation = await alice.conversations.newGroupConversation([ - bob.address, - ]) - await conversation.send('hi bob') - - let numConversations = 0 - for await (const conversation of stream) { - numConversations++ - expect(conversation.peerAddress).toBe(bob.address) - if (numConversations == 2) break - } - expect(numConversations).toBe(2) - await stream.return() - }) - it('streams all conversation messages from empty state', async () => { const aliceCharlie = await alice.conversations.newConversation( charlie.address @@ -329,38 +255,6 @@ describe('conversations', () => { await stream.return(undefined) }) - it('streams all conversation messages from group conversations', async () => { - alice.enableGroupChat() - charlie.enableGroupChat() - - const aliceCharlie = await alice.conversations.newGroupConversation([ - charlie.address, - ]) - const bobAlice = await bob.conversations.newConversation(alice.address) - - const stream = await alice.conversations.streamAllMessages() - await aliceCharlie.send('gm alice -charlie') - - let numMessages = 0 - for await (const message of stream) { - numMessages++ - if (numMessages == 1) { - expect(message.content).toBe('gm alice -charlie') - await bobAlice.send('gm alice -bob') - } - if (numMessages == 2) { - expect(message.content).toBe('gm alice -bob') - await aliceCharlie.send('gm charlie -alice') - } - if (numMessages == 3) { - expect(message.content).toBe('gm charlie -alice') - break - } - } - expect(numMessages).toBe(3) - await stream.return(undefined) - }) - it('dedupes conversations when multiple messages are in the introduction topic', async () => { const aliceConversation = await alice.conversations.newConversation( bob.address @@ -518,24 +412,4 @@ describe('conversations', () => { expect(invites).toHaveLength(1) }) }) - - describe('newGroupConversation', () => { - it('sends invites to recipients', async () => { - bob.enableGroupChat() - - await bob.conversations.newGroupConversation([ - alice.address, - charlie.address, - ]) - - let invites = await alice.listGroupInvitations() - expect(invites).toHaveLength(1) - - invites = await charlie.listGroupInvitations() - expect(invites).toHaveLength(1) - - invites = await bob.listGroupInvitations() - expect(invites).toHaveLength(1) - }) - }) }) From 8efda3c14f0634c98a89442d60ea454008185e9c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 24 Aug 2023 12:13:48 -0700 Subject: [PATCH 087/137] chore: refactor to a single base conversation store --- src/keystore/InMemoryKeystore.ts | 64 +++++++----- src/keystore/InviteStore.ts | 71 ------------- src/keystore/LegacyStore.ts | 76 -------------- src/keystore/conversationStores.ts | 121 +++++++++++++++++++++++ src/keystore/index.ts | 2 +- src/keystore/utils.ts | 11 +-- test/Message.test.ts | 2 +- test/keystore/InMemoryKeystore.test.ts | 6 +- test/keystore/InviteStore.test.ts | 60 ----------- test/keystore/LegacyStore.test.ts | 41 -------- test/keystore/conversationStores.test.ts | 106 ++++++++++++++++++++ 11 files changed, 273 insertions(+), 287 deletions(-) delete mode 100644 src/keystore/InviteStore.ts delete mode 100644 src/keystore/LegacyStore.ts create mode 100644 src/keystore/conversationStores.ts delete mode 100644 test/keystore/InviteStore.test.ts delete mode 100644 test/keystore/LegacyStore.test.ts create mode 100644 test/keystore/conversationStores.test.ts diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index c17221655..b41fb2ac6 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -21,14 +21,14 @@ import { toSignedPublicKeyBundle, validateObject, getKeyMaterial, - topicDataToConversationReference, + topicDataToV2ConversationReference, } from './utils' import { nsToDate, buildDirectMessageTopicV2, buildDirectMessageTopic, } from '../utils' -import InviteStore from './InviteStore' +import { AddRequest, V1Store, V2Store } from './conversationStores' import { Persistence } from './persistence' import LocalAuthenticator from '../authn/LocalAuthenticator' import { hmacSha256Sign } from '../crypto/ecies' @@ -36,7 +36,7 @@ import crypto from '../crypto/crypto' import { bytesToHex } from '../crypto/utils' import Long from 'long' import { SetRefreshJobResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' -import LegacyStore from './LegacyStore' + const { ErrorCode } = keystore // Constant, 32 byte salt @@ -62,22 +62,22 @@ async function deriveKey( export default class InMemoryKeystore implements Keystore { private v1Keys: PrivateKeyBundleV1 private v2Keys: PrivateKeyBundleV2 // Do I need this? - private inviteStore: InviteStore - private v1Store: LegacyStore + private v1Store: V1Store + private v2Store: V2Store private authenticator: LocalAuthenticator private accountAddress: string | undefined private jobStatePersistence: Persistence constructor( keys: PrivateKeyBundleV1, - inviteStore: InviteStore, - v1Store: LegacyStore, + v1Store: V1Store, + v2Store: V2Store, persistence: Persistence ) { this.v1Keys = keys this.v2Keys = PrivateKeyBundleV2.fromLegacyBundle(keys) - this.inviteStore = inviteStore this.v1Store = v1Store + this.v2Store = v2Store this.authenticator = new LocalAuthenticator(keys.identityKey) this.jobStatePersistence = persistence } @@ -85,8 +85,8 @@ export default class InMemoryKeystore implements Keystore { static async create(keys: PrivateKeyBundleV1, persistence: Persistence) { return new InMemoryKeystore( keys, - await InviteStore.create(persistence), - await LegacyStore.create(persistence), + await V1Store.create(persistence), + await V2Store.create(persistence), persistence ) } @@ -140,7 +140,7 @@ export default class InMemoryKeystore implements Keystore { } const { payload, headerBytes, contentTopic } = req - const topicData = this.inviteStore.lookup(contentTopic) + const topicData = this.v2Store.lookup(contentTopic) if (!topicData) { // This is the wrong error type. Will add to the proto repo later throw new KeystoreError( @@ -219,7 +219,7 @@ export default class InMemoryKeystore implements Keystore { const { payload, headerBytes, contentTopic } = req - const topicData = this.inviteStore.lookup(contentTopic) + const topicData = this.v2Store.lookup(contentTopic) if (!topicData) { throw new KeystoreError( ErrorCode.ERROR_CODE_NO_MATCHING_PREKEY, @@ -246,7 +246,7 @@ export default class InMemoryKeystore implements Keystore { async saveInvites( req: keystore.SaveInvitesRequest ): Promise { - const toAdd: TopicData[] = [] + const toAdd: AddRequest[] = [] const responses = await mapAndConvertErrors( req.requests, @@ -270,16 +270,16 @@ export default class InMemoryKeystore implements Keystore { ? await sealed.v1.header.recipient.walletSignatureAddress() : await sealed.v1.header.sender.walletSignatureAddress(), } - toAdd.push(topicData) + toAdd.push({ ...topicData, topic: invitation.topic }) return { - conversation: topicDataToConversationReference(topicData), + conversation: topicDataToV2ConversationReference(topicData), } } }, ErrorCode.ERROR_CODE_INVALID_INPUT ) - await this.inviteStore.add(toAdd) + await this.v2Store.add(toAdd) return keystore.SaveInvitesResponse.fromPartial({ responses, @@ -344,13 +344,14 @@ export default class InMemoryKeystore implements Keystore { }) const topicData = { invitation, + topic: invitation.topic, createdNs: req.createdNs, peerAddress: await recipient.walletSignatureAddress(), } - await this.inviteStore.add([topicData]) + await this.v2Store.add([topicData]) return keystore.CreateInviteResponse.fromPartial({ - conversation: topicDataToConversationReference(topicData), + conversation: topicDataToV2ConversationReference(topicData), payload: sealed.toBytes(), }) } catch (e) { @@ -398,6 +399,7 @@ export default class InMemoryKeystore implements Keystore { }: keystore.SaveV1ConversationsRequest): Promise { await this.v1Store.add( conversations.map((convo) => ({ + topic: buildDirectMessageTopic(convo.peerAddress, this.walletAddress), peerAddress: convo.peerAddress, createdNs: convo.createdNs, invitation: undefined, @@ -408,12 +410,9 @@ export default class InMemoryKeystore implements Keystore { } async getV1Conversations(): Promise { - const convos = this.v1Store.entries.map((reference) => ({ - peerAddress: reference.peerAddress, - createdNs: reference.createdNs, - topic: buildDirectMessageTopic(reference.peerAddress, this.walletAddress), - context: undefined, - })) + const convos = this.v1Store.topics.map( + this.topicDataToV1ConversationReference.bind(this) + ) return { conversations: convos } } @@ -421,8 +420,8 @@ export default class InMemoryKeystore implements Keystore { async getV2Conversations(): Promise< conversationReference.ConversationReference[] > { - const convos = this.inviteStore.topics.map((invite) => - topicDataToConversationReference(invite) + const convos = this.v2Store.topics.map((invite) => + topicDataToV2ConversationReference(invite as TopicData) ) convos.sort((a, b) => @@ -478,6 +477,17 @@ export default class InMemoryKeystore implements Keystore { return {} } + private topicDataToV1ConversationReference( + data: keystore.TopicMap_TopicData + ) { + return { + peerAddress: data.peerAddress, + createdNs: data.createdNs, + topic: buildDirectMessageTopic(data.peerAddress, this.walletAddress), + context: undefined, + } + } + private buildJobStorageKey(jobType: keystore.JobType): string { return `refreshJob/${jobType.toString()}` } @@ -498,6 +508,6 @@ export default class InMemoryKeystore implements Keystore { // This method is not defined as part of the standard Keystore API, but is available // on the InMemoryKeystore to support legacy use-cases. lookupTopic(topic: string) { - return this.inviteStore.lookup(topic) + return this.v2Store.lookup(topic) } } diff --git a/src/keystore/InviteStore.ts b/src/keystore/InviteStore.ts deleted file mode 100644 index 38d20bd77..000000000 --- a/src/keystore/InviteStore.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { keystore } from '@xmtp/proto' -import { Persistence } from './persistence/interface' -import type { TopicData } from './interfaces' -import { Mutex } from 'async-mutex' -import { typeSafeTopicMap } from './utils' - -const INVITE_KEY = 'invitations/v1' - -/** - * InviteStore holds a simple map of topic -> TopicData and writes to the persistence layer on changes - */ -export default class InviteStore { - private persistence: Persistence - private mutex: Mutex - private topicMap: Map - - constructor( - persistence: Persistence, - initialData: Map = new Map() - ) { - this.persistence = persistence - this.mutex = new Mutex() - this.topicMap = initialData - } - - static async create(persistence: Persistence): Promise { - const rawData = await persistence.getItem(INVITE_KEY) - if (rawData) { - try { - const inviteMap = typeSafeTopicMap(keystore.TopicMap.decode(rawData)) - // Create an InviteStore with data preloaded - return new InviteStore(persistence, new Map(Object.entries(inviteMap))) - } catch (e) { - console.warn(`Error loading invites from store: ${e}`) - } - } - return new InviteStore(persistence) - } - - async add(topicData: TopicData[]): Promise { - await this.mutex.runExclusive(async () => { - let isDirty = false - for (const row of topicData) { - // This will not overwrite any existing values. First invite found in the store for a given topic will always be used - // Duplicates do not throw errors - if (!this.topicMap.has(row.invitation.topic)) { - this.topicMap.set(row.invitation.topic, row) - isDirty = true - } - } - // Only write to persistence once, and only if we have added new invites - if (isDirty && this.persistence) { - await this.persistence.setItem(INVITE_KEY, this.toBytes()) - } - }) - } - - get topics(): TopicData[] { - return [...this.topicMap.values()] - } - - lookup(topic: string): TopicData | undefined { - return this.topicMap.get(topic) - } - - private toBytes(): Uint8Array { - return keystore.TopicMap.encode({ - topics: Object.fromEntries(this.topicMap), - }).finish() - } -} diff --git a/src/keystore/LegacyStore.ts b/src/keystore/LegacyStore.ts deleted file mode 100644 index 6dbda2aa4..000000000 --- a/src/keystore/LegacyStore.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { keystore } from '@xmtp/proto' -import { Persistence } from './persistence/interface' -import { Mutex } from 'async-mutex' -import Long from 'long' -import { topicDataToMap } from './utils' - -const LEGACY_KEY = 'legacy-convos/v1' - -type Entry = { - peerAddress: string - createdNs: Long - invitation: undefined -} - -/** - * InviteStore holds a simple map of topic -> TopicData and writes to the persistence layer on changes - */ -export default class LegacyStore { - private persistence: Persistence - private mutex: Mutex - private topicMap: Map - - constructor( - persistence: Persistence, - initialData: Map = new Map() - ) { - this.persistence = persistence - this.mutex = new Mutex() - this.topicMap = initialData - } - - static async create(persistence: Persistence): Promise { - const rawData = await persistence.getItem(LEGACY_KEY) - if (rawData) { - try { - const topicMap = keystore.TopicMap.decode(rawData) - // Create an InviteStore with data preloaded - return new LegacyStore( - persistence, - topicDataToMap(topicMap) as Map - ) - } catch (e) { - console.warn(`Error loading invites from store: ${e}`) - } - } - return new LegacyStore(persistence) - } - - async add(topicData: Entry[]): Promise { - await this.mutex.runExclusive(async () => { - let isDirty = false - for (const row of topicData) { - // This will not overwrite any existing values. First invite found in the store for a given topic will always be used - // Duplicates do not throw errors - if (!this.topicMap.has(row.peerAddress)) { - this.topicMap.set(row.peerAddress, row) - isDirty = true - } - } - // Only write to persistence once, and only if we have added new invites - if (isDirty) { - await this.persistence.setItem(LEGACY_KEY, this.toBytes()) - } - }) - } - - get entries(): Entry[] { - return [...this.topicMap.values()] - } - - private toBytes(): Uint8Array { - return keystore.TopicMap.encode({ - topics: Object.fromEntries(this.topicMap), - }).finish() - } -} diff --git a/src/keystore/conversationStores.ts b/src/keystore/conversationStores.ts new file mode 100644 index 000000000..396ac6543 --- /dev/null +++ b/src/keystore/conversationStores.ts @@ -0,0 +1,121 @@ +import Long from 'long' +import { keystore, invitation } from '@xmtp/proto' +import { Persistence } from './persistence/interface' +import { Mutex } from 'async-mutex' +import { isCompleteTopicData, topicDataToMap, typeSafeTopicMap } from './utils' + +export type AddRequest = { + topic: string + createdNs: Long + peerAddress: string + invitation: invitation.InvitationV1 | undefined +} + +const INVITE_STORAGE_KEY = 'invitations/v1' +const V1_STORAGE_KEY = 'conversation-v1/v1' + +/** + * V2Store holds a simple map of topic -> TopicData and writes to the persistence layer on changes + */ +export class V2Store { + private readonly persistence: Persistence + private readonly persistenceKey: string + private readonly mutex: Mutex + private readonly topicMap: Map + + constructor( + persistence: Persistence, + persistenceKey: string, + initialData: Map = new Map() + ) { + this.persistenceKey = persistenceKey + this.persistence = persistence + this.mutex = new Mutex() + this.topicMap = initialData + } + + static async create(persistence: Persistence): Promise { + const persistenceKey = INVITE_STORAGE_KEY + const rawData = await persistence.getItem(persistenceKey) + if (rawData) { + try { + const inviteMap = typeSafeTopicMap(keystore.TopicMap.decode(rawData)) + // Create an InviteStore with data preloaded + return new V2Store(persistence, persistenceKey, inviteMap) + } catch (e) { + console.warn(`Error loading invites from store: ${e}`) + } + } + return new V2Store(persistence, persistenceKey) + } + + protected validate(topicData: AddRequest): boolean { + return ( + !!topicData.topic && + topicData.topic.length > 0 && + isCompleteTopicData(topicData) + ) + } + + async add(topicData: AddRequest[]): Promise { + await this.mutex.runExclusive(async () => { + let isDirty = false + for (const row of topicData) { + if (!this.validate(row)) { + console.warn('Invalid topic data', row) + continue + } + const { topic, ...data } = row + // This will not overwrite any existing values. First invite found in the store for a given topic will always be used + // Duplicates do not throw errors + if (!this.topicMap.has(topic)) { + this.topicMap.set(topic, data) + isDirty = true + } + } + // Only write to persistence once, and only if we have added new invites + if (isDirty) { + await this.persistence.setItem(this.persistenceKey, this.toBytes()) + } + }) + } + + get topics(): keystore.TopicMap_TopicData[] { + return [...this.topicMap.values()] + } + + lookup(topic: string): keystore.TopicMap_TopicData | undefined { + return this.topicMap.get(topic) + } + + private toBytes(): Uint8Array { + return keystore.TopicMap.encode({ + topics: Object.fromEntries(this.topicMap), + }).finish() + } +} + +export class V1Store extends V2Store { + static async create(persistence: Persistence): Promise { + const persistenceKey = V1_STORAGE_KEY + const rawData = await persistence.getItem(persistenceKey) + if (rawData) { + try { + const inviteMap = topicDataToMap(keystore.TopicMap.decode(rawData)) + // Create an InviteStore with data preloaded + return new V1Store(persistence, persistenceKey, inviteMap) + } catch (e) { + console.warn(`Error loading invites from store: ${e}`) + } + } + return new V1Store(persistence, persistenceKey) + } + + protected override validate(topicData: AddRequest) { + return !!( + topicData.topic && + topicData.topic.length && + topicData.peerAddress?.length > 0 + ) + } +} diff --git a/src/keystore/index.ts b/src/keystore/index.ts index 8d26f995e..22cdb0d1d 100644 --- a/src/keystore/index.ts +++ b/src/keystore/index.ts @@ -1,5 +1,5 @@ export { default as InMemoryKeystore } from './InMemoryKeystore' -export { default as InviteStore } from './InviteStore' +export { V1Store, V2Store } from './conversationStores' export * from './encryption' export * from './errors' export * from './interfaces' diff --git a/src/keystore/utils.ts b/src/keystore/utils.ts index 7cb86ff40..83a33dd18 100644 --- a/src/keystore/utils.ts +++ b/src/keystore/utils.ts @@ -106,7 +106,7 @@ export const getKeyMaterial = ( return invite.aes256GcmHkdfSha256.keyMaterial } -export const topicDataToConversationReference = ({ +export const topicDataToV2ConversationReference = ({ invitation, createdNs, peerAddress, @@ -123,14 +123,11 @@ export const isCompleteTopicData = ( export const typeSafeTopicMap = ( topicMap: keystore.TopicMap -): { [k: string]: TopicData } => { - const out: { [k: string]: TopicData } = {} +): Map => { + const out = new Map() for (const [topic, topicData] of Object.entries(topicMap.topics)) { if (isCompleteTopicData(topicData)) { - out[topic] = topicData - } else { - // This should only happen if bad data somehow snuck through validation - console.warn('Invitation missing from topic data') + out.set(topic, topicData) } } return out diff --git a/test/Message.test.ts b/test/Message.test.ts index 919b2a2d0..c37c13f36 100644 --- a/test/Message.test.ts +++ b/test/Message.test.ts @@ -5,7 +5,7 @@ import { MessageV1, DecodedMessage } from '../src/Message' import { PrivateKeyBundleV1 } from '../src/crypto/PrivateKeyBundle' import { bytesToHex, equalBytes } from '../src/crypto/utils' import { sha256 } from '../src/crypto/encryption' -import { InMemoryKeystore, InviteStore, KeystoreError } from '../src/keystore' +import { InMemoryKeystore, KeystoreError } from '../src/keystore' import { Client, ContentTypeText, InMemoryPersistence } from '../src' import { Wallet } from 'ethers' import { ContentTypeTestKey, TestKeyCodec } from './ContentTypeTestKey' diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index e10dd8af1..7c778601d 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -682,9 +682,9 @@ describe('InMemoryKeystore', () => { } const lookupResult = aliceKeystore.lookupTopic(invite.topic) - expect(lookupResult?.invitation.aes256GcmHkdfSha256?.keyMaterial).toEqual( - invite.aes256GcmHkdfSha256.keyMaterial - ) + expect( + lookupResult?.invitation?.aes256GcmHkdfSha256?.keyMaterial + ).toEqual(invite.aes256GcmHkdfSha256.keyMaterial) }) it('returns undefined for non-existent topic', async () => { diff --git a/test/keystore/InviteStore.test.ts b/test/keystore/InviteStore.test.ts deleted file mode 100644 index 493fd0d9d..000000000 --- a/test/keystore/InviteStore.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import crypto from '../../src/crypto/crypto' -import { InviteStore, TopicData } from '../../src/keystore' -import { InMemoryPersistence } from '../../src/keystore/persistence' -import { dateToNs } from '../../src/utils' - -const buildTopicData = (): TopicData => ({ - createdNs: dateToNs(new Date()).toUnsigned(), - peerAddress: crypto.getRandomValues(new Uint8Array(42)).toString(), - invitation: { - topic: crypto.getRandomValues(new Uint8Array(32)).toString(), - aes256GcmHkdfSha256: { - keyMaterial: crypto.getRandomValues(new Uint8Array(32)), - }, - context: { - conversationId: 'foo', - metadata: {}, - }, - }, -}) - -describe('InviteStore', () => { - it('can add and retrieve invites without persistence', async () => { - const store = await InviteStore.create(InMemoryPersistence.create()) - const topicData = buildTopicData() - await store.add([topicData]) - - const result = store.lookup(topicData.invitation.topic) - expect(result).not.toBeNull() - expect(result).toEqual(topicData) - }) - - it('can add and retrieve invites with persistence', async () => { - const store = await InviteStore.create(InMemoryPersistence.create()) - const topicData = buildTopicData() - await store.add([topicData]) - - const result = store.lookup(topicData.invitation.topic) - expect(result).toEqual(topicData) - }) - - it('returns undefined when no match exists', async () => { - const store = await InviteStore.create(InMemoryPersistence.create()) - const result = store.lookup('foo') - expect(result).toBeUndefined() - }) - - it('persists data between instances', async () => { - const persistence = InMemoryPersistence.create() - const store = await InviteStore.create(persistence) - const topicData = buildTopicData() - await store.add([topicData]) - - const result = store.lookup(topicData.invitation.topic) - expect(result).toEqual(topicData) - - const store2 = await InviteStore.create(persistence) - const result2 = store2.lookup(topicData.invitation.topic) - expect(result2).toEqual(topicData) - }) -}) diff --git a/test/keystore/LegacyStore.test.ts b/test/keystore/LegacyStore.test.ts deleted file mode 100644 index ee2d147d5..000000000 --- a/test/keystore/LegacyStore.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import Long from 'long' -import { InMemoryPersistence, dateToNs } from '../../src' -import LegacyStore from '../../src/keystore/LegacyStore' -import { getRandomValues } from 'crypto' - -const buildConvoReference = ({ - peerAddress, - createdNs, -}: { - peerAddress?: string - createdNs?: Long -}) => ({ - peerAddress: - peerAddress || - Buffer.from(getRandomValues(new Uint8Array(32))).toString('hex'), - createdNs: dateToNs(new Date()).toUnsigned(), - invitation: undefined, -}) - -describe('LegacyStore', () => { - it('round trips', async () => { - const convo = buildConvoReference({}) - const store = await LegacyStore.create(InMemoryPersistence.create()) - await store.add([convo]) - expect(store.entries).toEqual([convo]) - }) - - it('persists correctly', async () => { - const convos = [buildConvoReference({}), buildConvoReference({})] - const persistence = InMemoryPersistence.create() - const store = await LegacyStore.create(persistence) - await store.add(convos) - expect(store.entries).toEqual(convos) - - const store2 = await LegacyStore.create(persistence) - console.log(store.entries, store2.entries) - expect(store2.entries).toEqual(store.entries) - - expect(await persistence.getItem('legacy-convos/v1')).toBeDefined() - }) -}) diff --git a/test/keystore/conversationStores.test.ts b/test/keystore/conversationStores.test.ts new file mode 100644 index 000000000..10261334c --- /dev/null +++ b/test/keystore/conversationStores.test.ts @@ -0,0 +1,106 @@ +import crypto from '../../src/crypto/crypto' +import { V2Store, TopicData } from '../../src/keystore' +import { AddRequest, V1Store } from '../../src/keystore/conversationStores' +import { InMemoryPersistence } from '../../src/keystore/persistence' +import { dateToNs } from '../../src/utils' + +const INVITE_KEY = 'invitations/v1' + +const buildAddRequest = (): AddRequest => { + const topic = crypto.getRandomValues(new Uint8Array(32)).toString() + return { + topic, + createdNs: dateToNs(new Date()).toUnsigned(), + peerAddress: crypto.getRandomValues(new Uint8Array(42)).toString(), + invitation: { + topic, + aes256GcmHkdfSha256: { + keyMaterial: crypto.getRandomValues(new Uint8Array(32)), + }, + context: { + conversationId: 'foo', + metadata: {}, + }, + }, + } +} + +describe('V2Store', () => { + it('can add and retrieve invites without persistence', async () => { + const store = await V2Store.create(InMemoryPersistence.create()) + const addRequest = buildAddRequest() + await store.add([addRequest]) + + const result = store.lookup(addRequest.topic) + expect(result).not.toBeNull() + const { topic, ...topicData } = addRequest + expect(result).toEqual(topicData) + }) + + it('can add and retrieve invites with persistence', async () => { + const store = await V2Store.create(InMemoryPersistence.create()) + const topicData = buildAddRequest() + await store.add([topicData]) + + const result = store.lookup(topicData.topic) + expect(result?.invitation).toEqual(topicData.invitation) + expect(result?.peerAddress).toEqual(topicData.peerAddress) + expect(result?.createdNs.eq(topicData.createdNs)).toBeTruthy() + }) + + it('returns undefined when no match exists', async () => { + const store = await V2Store.create(InMemoryPersistence.create()) + const result = store.lookup('foo') + expect(result).toBeUndefined() + }) + + it('persists data between instances', async () => { + const persistence = InMemoryPersistence.create() + const store = await V2Store.create(persistence) + const topicData = buildAddRequest() + await store.add([topicData]) + + const result = store.lookup(topicData.topic) + expect(result?.invitation).toEqual(topicData.invitation) + expect(result?.createdNs.eq(topicData.createdNs)).toBeTruthy() + expect(result?.peerAddress).toEqual(topicData.peerAddress) + + const store2 = await V2Store.create(persistence) + const result2 = store2.lookup(topicData.topic) + expect(result2).toEqual(result) + }) +}) + +describe('v1Store', () => { + const buildV1 = (): AddRequest => { + const peerAddress = crypto.getRandomValues(new Uint8Array(32)).toString() + return { + peerAddress, + createdNs: dateToNs(new Date()).toUnsigned(), + invitation: undefined, + topic: `xmtp/${peerAddress}}`, + } + } + + it('can add and retrieve v1 convos', async () => { + const store = await V1Store.create(InMemoryPersistence.create()) + const addReq = buildV1() + await store.add([addReq]) + + const value = store.lookup(addReq.topic) + expect(value).toBeTruthy() + }) + + it('can round trip to persistence', async () => { + const persistence = InMemoryPersistence.create() + const store = await V1Store.create(persistence) + const requests = [buildV1(), buildV1()] + await store.add(requests) + const valuesFromFirstStore = store.topics + expect(valuesFromFirstStore).toHaveLength(2) + + const store2 = await V1Store.create(persistence) + const valuesFromSecondStore = store2.topics + expect(valuesFromFirstStore).toEqual(valuesFromSecondStore) + }) +}) From aee88a15fc4e5de704766078520e90a4be0eae4f Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Thu, 24 Aug 2023 15:31:47 -0700 Subject: [PATCH 088/137] build: update xmtp/proto to a compatible version --- package-lock.json | 30 ++++-------------------------- package.json | 2 +- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index e17a8256d..7a580b80d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", + "@xmtp/proto": "^3.28.0-beta.1", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", @@ -3726,9 +3726,9 @@ } }, "node_modules/@xmtp/proto": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.24.0.tgz", - "integrity": "sha512-RPzv+E7TOttY3Xs6+LE2ctQxzVLcdZLMzSeS+MEG2vBO8Dl/bhojGs/MehJorZzWHCLtL5VDPq0IY164RLqC7w==", + "version": "3.28.0-beta.1", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.28.0-beta.1.tgz", + "integrity": "sha512-gbDQ1FXKZe0j9RZxBK0Ohyy8C4z5I+ko58xmHk+QGO4QYb+cGsJyDSe0Re3oUa1tlnNudV0fkTR4nxcq4D+oIw==", "dependencies": { "long": "^5.2.0", "protobufjs": "^7.0.0", @@ -9600,11 +9600,6 @@ "node": ">=0.1.90" } }, - "node_modules/npm/node_modules/@gar/promisify": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, "node_modules/npm/node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -9833,18 +9828,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "2.0.0", "dev": true, @@ -10761,11 +10744,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "license": "ISC" - }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", "dev": true, diff --git a/package.json b/package.json index 973508016..2b4b1879d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ }, "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", + "@xmtp/proto": "^3.28.0-beta.1", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", From 2dd98f6d3e77870697e385f2c5f980c54e847970 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 25 Aug 2023 13:04:12 -0700 Subject: [PATCH 089/137] feat: add revision tracking --- package-lock.json | 30 ++------- package.json | 2 +- src/keystore/InMemoryKeystore.ts | 3 +- src/keystore/conversationStores.ts | 82 ++++++++++++++++++------ src/utils/bytes.ts | 20 ++++++ test/conversations/Conversations.test.ts | 2 +- test/keystore/conversationStores.test.ts | 26 ++++++++ 7 files changed, 114 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index e17a8256d..7a580b80d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", + "@xmtp/proto": "^3.28.0-beta.1", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", @@ -3726,9 +3726,9 @@ } }, "node_modules/@xmtp/proto": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.24.0.tgz", - "integrity": "sha512-RPzv+E7TOttY3Xs6+LE2ctQxzVLcdZLMzSeS+MEG2vBO8Dl/bhojGs/MehJorZzWHCLtL5VDPq0IY164RLqC7w==", + "version": "3.28.0-beta.1", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.28.0-beta.1.tgz", + "integrity": "sha512-gbDQ1FXKZe0j9RZxBK0Ohyy8C4z5I+ko58xmHk+QGO4QYb+cGsJyDSe0Re3oUa1tlnNudV0fkTR4nxcq4D+oIw==", "dependencies": { "long": "^5.2.0", "protobufjs": "^7.0.0", @@ -9600,11 +9600,6 @@ "node": ">=0.1.90" } }, - "node_modules/npm/node_modules/@gar/promisify": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, "node_modules/npm/node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -9833,18 +9828,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "2.0.0", "dev": true, @@ -10761,11 +10744,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/infer-owner": { - "version": "1.0.4", - "dev": true, - "license": "ISC" - }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", "dev": true, diff --git a/package.json b/package.json index 973508016..2b4b1879d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ }, "dependencies": { "@noble/secp256k1": "^1.5.2", - "@xmtp/proto": "^3.24.0", + "@xmtp/proto": "^3.28.0-beta.1", "async-mutex": "^0.4.0", "elliptic": "^6.5.4", "ethers": "^5.5.3", diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index b41fb2ac6..69a6f5caa 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -35,7 +35,6 @@ import { hmacSha256Sign } from '../crypto/ecies' import crypto from '../crypto/crypto' import { bytesToHex } from '../crypto/utils' import Long from 'long' -import { SetRefreshJobResponse } from '@xmtp/proto/ts/dist/types/keystore_api/v1/keystore.pb' const { ErrorCode } = keystore @@ -467,7 +466,7 @@ export default class InMemoryKeystore implements Keystore { async setRefreshJob({ jobType, lastRunNs, - }: keystore.SetRefeshJobRequest): Promise { + }: keystore.SetRefeshJobRequest): Promise { const key = await this.buildJobStorageKey(jobType) await this.jobStatePersistence.setItem( key, diff --git a/src/keystore/conversationStores.ts b/src/keystore/conversationStores.ts index 396ac6543..ed307e665 100644 --- a/src/keystore/conversationStores.ts +++ b/src/keystore/conversationStores.ts @@ -3,6 +3,7 @@ import { keystore, invitation } from '@xmtp/proto' import { Persistence } from './persistence/interface' import { Mutex } from 'async-mutex' import { isCompleteTopicData, topicDataToMap, typeSafeTopicMap } from './utils' +import { numberToUint8Array, uint8ArrayToNumber } from '../utils' export type AddRequest = { topic: string @@ -22,6 +23,7 @@ export class V2Store { private readonly persistenceKey: string private readonly mutex: Mutex private readonly topicMap: Map + private revision: number constructor( persistence: Persistence, @@ -30,23 +32,25 @@ export class V2Store { ) { this.persistenceKey = persistenceKey this.persistence = persistence + this.revision = 0 this.mutex = new Mutex() this.topicMap = initialData } + get revisionKey(): string { + return this.persistenceKey + '/revision' + } + static async create(persistence: Persistence): Promise { const persistenceKey = INVITE_STORAGE_KEY - const rawData = await persistence.getItem(persistenceKey) - if (rawData) { - try { - const inviteMap = typeSafeTopicMap(keystore.TopicMap.decode(rawData)) - // Create an InviteStore with data preloaded - return new V2Store(persistence, persistenceKey, inviteMap) - } catch (e) { - console.warn(`Error loading invites from store: ${e}`) - } + + const v2Store = new V2Store(persistence, persistenceKey) + try { + await v2Store.refresh() + } catch (e) { + console.error('Error refreshing store', e) } - return new V2Store(persistence, persistenceKey) + return v2Store } protected validate(topicData: AddRequest): boolean { @@ -57,8 +61,47 @@ export class V2Store { ) } + async refresh() { + const currentRevision = await this.getRevision() + if (currentRevision > this.revision) { + for (const [topic, data] of await this.loadFromPersistence()) { + this.topicMap.set(topic, data) + } + } + this.revision = currentRevision + } + + async getRevision(): Promise { + const data = await this.persistence.getItem(this.revisionKey) + if (!data) { + return 0 + } + return uint8ArrayToNumber(data) + } + + async setRevision(number: number) { + await this.persistence.setItem(this.revisionKey, numberToUint8Array(number)) + } + + async loadFromPersistence(): Promise< + Map + > { + const rawData = await this.persistence.getItem(this.persistenceKey) + if (!rawData) { + return new Map() + } + return topicDataToMap(keystore.TopicMap.decode(rawData)) + } + + async store() { + await this.persistence.setItem(this.persistenceKey, this.toBytes()) + this.revision++ + await this.setRevision(this.revision) + } + async add(topicData: AddRequest[]): Promise { await this.mutex.runExclusive(async () => { + await this.refresh() let isDirty = false for (const row of topicData) { if (!this.validate(row)) { @@ -75,7 +118,7 @@ export class V2Store { } // Only write to persistence once, and only if we have added new invites if (isDirty) { - await this.persistence.setItem(this.persistenceKey, this.toBytes()) + await this.store() } }) } @@ -98,17 +141,14 @@ export class V2Store { export class V1Store extends V2Store { static async create(persistence: Persistence): Promise { const persistenceKey = V1_STORAGE_KEY - const rawData = await persistence.getItem(persistenceKey) - if (rawData) { - try { - const inviteMap = topicDataToMap(keystore.TopicMap.decode(rawData)) - // Create an InviteStore with data preloaded - return new V1Store(persistence, persistenceKey, inviteMap) - } catch (e) { - console.warn(`Error loading invites from store: ${e}`) - } + const v1Store = new V1Store(persistence, persistenceKey) + try { + await v1Store.refresh() + } catch (e) { + console.error('Error refreshing store', e) } - return new V1Store(persistence, persistenceKey) + + return v1Store } protected override validate(topicData: AddRequest) { diff --git a/src/utils/bytes.ts b/src/utils/bytes.ts index 755158104..3c1425ab3 100644 --- a/src/utils/bytes.ts +++ b/src/utils/bytes.ts @@ -8,3 +8,23 @@ export function concat(a: Uint8Array, b: Uint8Array): Uint8Array { ab.set(b, a.length) return ab } + +export function numberToUint8Array(num: number) { + // Create a buffer for a 32-bit integer + const buffer = new ArrayBuffer(4) + const view = new DataView(buffer) + + // Set the number in the buffer + view.setInt32(0, num, true) // true for little-endian + + // Create Uint8Array from buffer + return new Uint8Array(buffer) +} + +export function uint8ArrayToNumber(arr: Uint8Array) { + const buffer = arr.buffer + const view = new DataView(buffer) + + // Read the number from the buffer + return view.getInt32(0, true) // true for little-endian +} diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 24cb5edf8..59f3ffdc8 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -2,7 +2,7 @@ import { ConversationV1, ConversationV2, } from './../../src/conversations/Conversation' -import { newLocalHostClient, newWallet, waitForUserContact } from './../helpers' +import { newLocalHostClient, waitForUserContact } from './../helpers' import { Client } from '../../src' import { buildDirectMessageTopic, diff --git a/test/keystore/conversationStores.test.ts b/test/keystore/conversationStores.test.ts index 10261334c..adf141d34 100644 --- a/test/keystore/conversationStores.test.ts +++ b/test/keystore/conversationStores.test.ts @@ -69,6 +69,19 @@ describe('V2Store', () => { const result2 = store2.lookup(topicData.topic) expect(result2).toEqual(result) }) + + it('handles concurrent access', async () => { + const persistence = InMemoryPersistence.create() + const store1 = await V2Store.create(persistence) + const store2 = await V2Store.create(persistence) + // Add an item to store 1 + await store1.add([buildAddRequest()]) + expect(store1.topics).toHaveLength(1) + expect(store2.topics).toHaveLength(0) + await store2.add([buildAddRequest()]) + expect(store2.topics).toHaveLength(2) + expect(await store2.getRevision()).toBe(2) + }) }) describe('v1Store', () => { @@ -103,4 +116,17 @@ describe('v1Store', () => { const valuesFromSecondStore = store2.topics expect(valuesFromFirstStore).toEqual(valuesFromSecondStore) }) + + it('handles concurrent access', async () => { + const persistence = InMemoryPersistence.create() + const store1 = await V2Store.create(persistence) + const store2 = await V2Store.create(persistence) + // Add an item to store 1 + await store1.add([buildAddRequest()]) + expect(store1.topics).toHaveLength(1) + expect(store2.topics).toHaveLength(0) + await store2.add([buildAddRequest()]) + expect(store2.topics).toHaveLength(2) + expect(await store2.getRevision()).toBe(2) + }) }) From 28c50cfb11f7b7af669b2ebd7283ceb189ace4c7 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 25 Aug 2023 13:06:22 -0700 Subject: [PATCH 090/137] chore: remove return type which was throwing off linter --- src/Compression.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compression.ts b/src/Compression.ts index 452f2e456..1c4c66da6 100644 --- a/src/Compression.ts +++ b/src/Compression.ts @@ -34,7 +34,7 @@ export async function compress(encoded: proto.EncodedContent): Promise { encoded.content = sink.bytes } -function compressionIdFromCode(code: proto.Compression): string { +function compressionIdFromCode(code: proto.Compression) { if (code === proto.Compression.COMPRESSION_GZIP) { return 'gzip' } From 03c1f1df732484438b1955a0950499c213d2fc68 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 25 Aug 2023 13:39:45 -0700 Subject: [PATCH 091/137] chore: only log the topic --- src/keystore/conversationStores.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keystore/conversationStores.ts b/src/keystore/conversationStores.ts index ed307e665..7e4dbc10b 100644 --- a/src/keystore/conversationStores.ts +++ b/src/keystore/conversationStores.ts @@ -105,7 +105,7 @@ export class V2Store { let isDirty = false for (const row of topicData) { if (!this.validate(row)) { - console.warn('Invalid topic data', row) + console.warn('Invalid topic data', row.topic) continue } const { topic, ...data } = row From 1a165663b5e2729e8eb170d48fa1c53863489380 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Fri, 25 Aug 2023 14:06:10 -0700 Subject: [PATCH 092/137] test: add more tests --- src/keystore/conversationStores.ts | 14 ++----- src/keystore/utils.ts | 12 ------ test/conversations/Conversations.test.ts | 51 +++++++++++++++++------- test/keystore/conversationStores.test.ts | 21 ++++++++++ 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/keystore/conversationStores.ts b/src/keystore/conversationStores.ts index 7e4dbc10b..2f64a881b 100644 --- a/src/keystore/conversationStores.ts +++ b/src/keystore/conversationStores.ts @@ -2,7 +2,7 @@ import Long from 'long' import { keystore, invitation } from '@xmtp/proto' import { Persistence } from './persistence/interface' import { Mutex } from 'async-mutex' -import { isCompleteTopicData, topicDataToMap, typeSafeTopicMap } from './utils' +import { isCompleteTopicData, topicDataToMap } from './utils' import { numberToUint8Array, uint8ArrayToNumber } from '../utils' export type AddRequest = { @@ -45,11 +45,7 @@ export class V2Store { const persistenceKey = INVITE_STORAGE_KEY const v2Store = new V2Store(persistence, persistenceKey) - try { - await v2Store.refresh() - } catch (e) { - console.error('Error refreshing store', e) - } + await v2Store.refresh() return v2Store } @@ -142,11 +138,7 @@ export class V1Store extends V2Store { static async create(persistence: Persistence): Promise { const persistenceKey = V1_STORAGE_KEY const v1Store = new V1Store(persistence, persistenceKey) - try { - await v1Store.refresh() - } catch (e) { - console.error('Error refreshing store', e) - } + await v1Store.refresh() return v1Store } diff --git a/src/keystore/utils.ts b/src/keystore/utils.ts index 83a33dd18..476c12528 100644 --- a/src/keystore/utils.ts +++ b/src/keystore/utils.ts @@ -121,18 +121,6 @@ export const isCompleteTopicData = ( obj: keystore.TopicMap_TopicData ): obj is TopicData => !!obj.invitation -export const typeSafeTopicMap = ( - topicMap: keystore.TopicMap -): Map => { - const out = new Map() - for (const [topic, topicData] of Object.entries(topicMap.topics)) { - if (isCompleteTopicData(topicData)) { - out.set(topic, topicData) - } - } - return out -} - export const topicDataToMap = (topicMap: keystore.TopicMap) => { const out = new Map() for (const [k, v] of Object.entries(topicMap.topics)) { diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 59f3ffdc8..f0f3e3c21 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -2,7 +2,7 @@ import { ConversationV1, ConversationV2, } from './../../src/conversations/Conversation' -import { newLocalHostClient, waitForUserContact } from './../helpers' +import { newLocalHostClient } from './../helpers' import { Client } from '../../src' import { buildDirectMessageTopic, @@ -19,9 +19,6 @@ describe('conversations', () => { alice = await newLocalHostClient({ publishLegacyContact: true }) bob = await newLocalHostClient({ publishLegacyContact: true }) charlie = await newLocalHostClient({ publishLegacyContact: true }) - await waitForUserContact(alice, alice) - await waitForUserContact(bob, bob) - await waitForUserContact(charlie, charlie) }) afterEach(async () => { @@ -37,7 +34,6 @@ describe('conversations', () => { const aliceToBob = await alice.conversations.newConversation(bob.address) await aliceToBob.send('gm') - await sleep(100) const aliceConversationsAfterMessage = await alice.conversations.list() expect(aliceConversationsAfterMessage).toHaveLength(1) @@ -97,7 +93,6 @@ describe('conversations', () => { conversationId: 'foo', metadata: {}, }) - await sleep(100) const aliceConversations2 = await alice.conversations.list() expect(aliceConversations2).toHaveLength(1) @@ -105,7 +100,6 @@ describe('conversations', () => { conversationId: 'bar', metadata: {}, }) - await sleep(100) const fromKeystore = await alice.keystore.getV2Conversations() expect(fromKeystore[1].context?.conversationId).toBe('bar') @@ -169,10 +163,9 @@ describe('conversations', () => { conversationId: 'xmtp.org/foo', metadata: {}, }) - await sleep(100) const stream = await alice.conversations.streamAllMessages() - await sleep(100) + await sleep(50) await aliceBobV1.send('V1') const message1 = await stream.next() @@ -215,7 +208,6 @@ describe('conversations', () => { aliceConversation.send('gm'), bobConversation.send('gm'), ]) - await sleep(100) const [aliceConversationsList, bobConversationList] = await Promise.all([ alice.conversations.list(), @@ -225,6 +217,40 @@ describe('conversations', () => { expect(bobConversationList).toHaveLength(1) }) + it('handles a mix of streaming and listing conversations', async () => { + await bob.conversations.newConversation(alice.address, { + conversationId: 'xmtp.org/1', + metadata: {}, + }) + const aliceStream = await alice.conversations.stream() + await sleep(50) + await bob.conversations.newConversation(alice.address, { + conversationId: 'xmtp.org/2', + metadata: {}, + }) + // Ensure the result has been received + await aliceStream.next() + // Expect that even though a new conversation was found while streaming the first conversation is still returned + expect(await alice.conversations.list()).toHaveLength(2) + await aliceStream.return() + + // Do it again to make sure the cache is updated with an existing timestamp + await bob.conversations.newConversation(alice.address, { + conversationId: 'xmtp.org/3', + metadata: {}, + }) + const aliceStream2 = await alice.conversations.stream() + await sleep(50) + await bob.conversations.newConversation(alice.address, { + conversationId: 'xmtp.org/4', + metadata: {}, + }) + await aliceStream2.next() + + expect(await alice.conversations.list()).toHaveLength(4) + await aliceStream2.return() + }) + describe('newConversation', () => { it('uses an existing v1 conversation when one exists', async () => { const aliceConvo = await alice.conversations.newConversation(bob.address) @@ -240,13 +266,11 @@ describe('conversations', () => { expect(aliceConvo instanceof ConversationV1).toBeTruthy() await bob.publishUserContact(false) alice.forgetContact(bob.address) - await sleep(100) const aliceConvo2 = await alice.conversations.newConversation(bob.address) expect(aliceConvo2 instanceof ConversationV1).toBeTruthy() await aliceConvo2.send('hi') - await sleep(100) const bobConvo = await bob.conversations.newConversation(alice.address) expect(bobConvo instanceof ConversationV1).toBeTruthy() const messages = await bobConvo.messages() @@ -258,7 +282,6 @@ describe('conversations', () => { it('creates a new V2 conversation when no existing convo and V2 bundle', async () => { await bob.publishUserContact(false) alice.forgetContact(bob.address) - await sleep(100) const aliceConvo = await alice.conversations.newConversation(bob.address) expect(aliceConvo instanceof ConversationV2).toBeTruthy() @@ -321,13 +344,11 @@ describe('conversations', () => { bob.address, { conversationId: conversationId1, metadata: {} } ) - await sleep(100) const aliceConvo2 = await alice.conversations.newConversation( bob.address, { conversationId: conversationId2, metadata: {} } ) - await sleep(100) if ( !(aliceConvo1 instanceof ConversationV2) || diff --git a/test/keystore/conversationStores.test.ts b/test/keystore/conversationStores.test.ts index adf141d34..6b6d92159 100644 --- a/test/keystore/conversationStores.test.ts +++ b/test/keystore/conversationStores.test.ts @@ -82,6 +82,26 @@ describe('V2Store', () => { expect(store2.topics).toHaveLength(2) expect(await store2.getRevision()).toBe(2) }) + + it('correctly handles revisions', async () => { + const persistence = InMemoryPersistence.create() + const store = await V2Store.create(persistence) + for (let i = 0; i < 10; i++) { + await store.add([buildAddRequest()]) + expect(await store.getRevision()).toBe(i + 1) + } + const newStore = await V2Store.create(persistence) + expect(await newStore.getRevision()).toBe(10) + }) + + it('omits bad data', async () => { + const store = await V2Store.create(InMemoryPersistence.create()) + const revision = await store.getRevision() + const topicData = { ...buildAddRequest(), invitation: undefined } + await store.add([topicData]) + expect(await store.getRevision()).toBe(revision) + expect(await store.topics).toHaveLength(0) + }) }) describe('v1Store', () => { @@ -127,6 +147,7 @@ describe('v1Store', () => { expect(store2.topics).toHaveLength(0) await store2.add([buildAddRequest()]) expect(store2.topics).toHaveLength(2) + expect(await store1.getRevision()).toBe(2) expect(await store2.getRevision()).toBe(2) }) }) From 8ccf607155e090b505d4775ecbab1b4c441524e1 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Mon, 28 Aug 2023 22:08:52 -0700 Subject: [PATCH 093/137] fix: move isBrowser to a function --- src/Client.ts | 8 ++++---- src/utils/browser.ts | 2 ++ src/utils/index.ts | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 src/utils/browser.ts diff --git a/src/Client.ts b/src/Client.ts index 5b35a592e..eb842aa7b 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -5,6 +5,7 @@ import { mapPaginatedStream, EnvelopeMapper, buildUserInviteTopic, + isBrowser, } from './utils' import { utils } from 'ethers' import { Signer } from './types/Signer' @@ -210,10 +211,9 @@ export function defaultOptions(opts?: Partial): ClientOptions { maxContentSize: MaxContentSize, persistConversations: true, skipContactPublishing: false, - basePersistence: - typeof localStorage === 'undefined' - ? InMemoryPersistence.create() - : BrowserStoragePersistence.create(), + basePersistence: isBrowser() + ? BrowserStoragePersistence.create() + : InMemoryPersistence.create(), disablePersistenceEncryption: false, keystoreProviders: defaultKeystoreProviders(), apiClientFactory: createHttpApiClientFromOptions, diff --git a/src/utils/browser.ts b/src/utils/browser.ts new file mode 100644 index 000000000..8e6049af6 --- /dev/null +++ b/src/utils/browser.ts @@ -0,0 +1,2 @@ +export const isBrowser = () => + typeof window !== 'undefined' && typeof window.document !== 'undefined' diff --git a/src/utils/index.ts b/src/utils/index.ts index f130d6d70..0656bd9fd 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -2,3 +2,4 @@ export * from './topic' export * from './async' export * from './date' export * from './bytes' +export * from './browser' From 8e739eed7565a08487d67ab5e2a9b511fbafa257 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 29 Aug 2023 08:30:39 -0700 Subject: [PATCH 094/137] fix: remove unused import --- src/conversations/Conversations.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index f8ca95364..091c4d71c 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -1,6 +1,5 @@ import { OnConnectionLostCallback } from './../ApiClient' import { messageApi, keystore, conversationReference } from '@xmtp/proto' -import { Mutex } from 'async-mutex' import { SignedPublicKeyBundle } from './../crypto/PublicKeyBundle' import { ListMessagesOptions } from './../Client' import { InvitationContext } from './../Invitation' From 94da6584ea72f65e04e3d9725fe381753cfbaba2 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 29 Aug 2023 08:56:16 -0700 Subject: [PATCH 095/137] test: add test for job runner --- test/conversations/JobRunner.test.ts | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 test/conversations/JobRunner.test.ts diff --git a/test/conversations/JobRunner.test.ts b/test/conversations/JobRunner.test.ts new file mode 100644 index 000000000..023b9dfd3 --- /dev/null +++ b/test/conversations/JobRunner.test.ts @@ -0,0 +1,65 @@ +import { + InMemoryKeystore, + InMemoryPersistence, + Keystore, + PrivateKeyBundleV1, + nsToDate, +} from '../../src' +import { keystore as keystoreProto } from '@xmtp/proto' +import JobRunner from '../../src/conversations/JobRunner' +import { newWallet, sleep } from '../helpers' + +describe('JobRunner', () => { + let keystore: Keystore + + beforeEach(async () => { + const bundle = await PrivateKeyBundleV1.generate(newWallet()) + keystore = await InMemoryKeystore.create( + bundle, + InMemoryPersistence.create() + ) + }) + + it('can set the job time correctly', async () => { + const v1Runner = new JobRunner('v1', keystore) + await v1Runner.run(async (lastRun) => { + expect(lastRun).toBeUndefined() + }) + + const { lastRunNs } = await keystore.getRefreshJob({ + jobType: keystoreProto.JobType.JOB_TYPE_REFRESH_V1, + }) + + // We don't know the exact timestamp that the runner will set from outside, so just assume it was within a second of now + expect(new Date().getTime() - nsToDate(lastRunNs).getTime()).toBeLessThan( + 1000 + ) + }) + + it('sets different values for v1 and v2 runners', async () => { + const v1Runner = new JobRunner('v1', keystore) + const v2Runner = new JobRunner('v2', keystore) + + await v1Runner.run(async () => {}) + // Ensure they have different timestamps + await sleep(10) + await v2Runner.run(async () => {}) + + const { lastRunNs: v1LastRunNs } = await keystore.getRefreshJob({ + jobType: keystoreProto.JobType.JOB_TYPE_REFRESH_V1, + }) + const { lastRunNs: v2LastRunNs } = await keystore.getRefreshJob({ + jobType: keystoreProto.JobType.JOB_TYPE_REFRESH_V2, + }) + + expect(v1LastRunNs.gt(0)).toBeTruthy() + expect(v2LastRunNs.gt(0)).toBeTruthy() + expect(v1LastRunNs.eq(v2LastRunNs)).toBe(false) + }) + + it('fails with an invalid job type', async () => { + // @ts-ignore-next-line + const v3Runner = new JobRunner('v3', keystore) + expect(v3Runner.run(async () => {})).rejects.toThrow('unknown job type: v3') + }) +}) From 3cc16d868085bf0528cf469ad4e779d789c2b47f Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 29 Aug 2023 08:57:53 -0700 Subject: [PATCH 096/137] test: add some more tests --- test/conversations/JobRunner.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/conversations/JobRunner.test.ts b/test/conversations/JobRunner.test.ts index 023b9dfd3..cfdd6a904 100644 --- a/test/conversations/JobRunner.test.ts +++ b/test/conversations/JobRunner.test.ts @@ -62,4 +62,23 @@ describe('JobRunner', () => { const v3Runner = new JobRunner('v3', keystore) expect(v3Runner.run(async () => {})).rejects.toThrow('unknown job type: v3') }) + + it('returns the value from the callback', async () => { + const v1Runner = new JobRunner('v1', keystore) + + const result = await v1Runner.run(async () => { + return 'foo' + }) + expect(result).toBe('foo') + }) + + it('bubbles up errors from the callback', async () => { + const v1Runner = new JobRunner('v1', keystore) + + await expect( + v1Runner.run(async () => { + throw new Error('foo') + }) + ).rejects.toThrow('foo') + }) }) From 4efffa989e4568f72e12c971d87a6ab84b8d566c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar Date: Tue, 29 Aug 2023 09:05:33 -0700 Subject: [PATCH 097/137] chore: add missing awaits --- test/Client.test.ts | 4 ++-- test/keystore/InMemoryKeystore.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Client.test.ts b/test/Client.test.ts index 1ef7e5247..e3a9ff04e 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -340,7 +340,7 @@ describe('ClientOptions', () => { return new CustomApiClient(ApiUrls.local) }, }) - expect(c).rejects.toThrow(expectedError) + await expect(c).rejects.toThrow(expectedError) }) }) @@ -355,7 +355,7 @@ describe('ClientOptions', () => { const c = newLocalHostClient({ basePersistence: new MyNewPersistence(new LocalStoragePonyfill()), }) - expect(c).rejects.toThrow('MyNewPersistence') + await expect(c).rejects.toThrow('MyNewPersistence') }) }) }) diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index 7c778601d..99028ed4a 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -208,7 +208,7 @@ describe('InMemoryKeystore', () => { it('throws if an invalid recipient is included', async () => { const createdNs = dateToNs(new Date()) - expect(async () => { + await expect(async () => { await aliceKeystore.createInvite({ recipient: {} as any, createdNs, @@ -428,7 +428,7 @@ describe('InMemoryKeystore', () => { it('rejects signing with an invalid prekey index', async () => { const digest = randomBytes(32) - expect( + await expect( aliceKeystore.signDigest({ digest, identityKey: false, From b2829443b335a1a830886b0648f9acd41411816a Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:45:24 -0700 Subject: [PATCH 098/137] chore: make tests pass post-merge --- src/conversations/Conversations.ts | 3 - src/keystore/InMemoryKeystore.ts | 16 +- src/keystore/rpcDefinitions.ts | 21 +- test/conversations/Conversations.test.ts | 3 +- test/conversations/GroupChat.test.ts | 241 ----------------------- test/keystore/InMemoryKeystore.test.ts | 4 +- 6 files changed, 17 insertions(+), 271 deletions(-) delete mode 100644 test/conversations/GroupChat.test.ts diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index f4b62a3d6..fcecf711f 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -17,9 +17,6 @@ import { import { PublicKeyBundle } from '../crypto' import { SortDirection } from '../ApiClient' import Long from 'long' -import { toSignedPublicKeyBundle } from '../keystore/utils' -import { bytesToHex } from '../crypto/utils' -import crypto from '../crypto/crypto' import JobRunner from './JobRunner' const CLOCK_SKEW_OFFSET_MS = 10000 diff --git a/src/keystore/InMemoryKeystore.ts b/src/keystore/InMemoryKeystore.ts index 14c6ec7d3..924ab684b 100644 --- a/src/keystore/InMemoryKeystore.ts +++ b/src/keystore/InMemoryKeystore.ts @@ -1,10 +1,10 @@ -import { authn, keystore, privateKey, signature, conversationReference } from '@xmtp/proto' +import { authn, keystore, privateKey, signature } from '@xmtp/proto' import { PrivateKeyBundleV1, PrivateKeyBundleV2, } from './../crypto/PrivateKeyBundle' import { InvitationV1, SealedInvitation } from './../Invitation' -import { PrivateKey, PublicKeyBundle, SignedPublicKeyBundle } from '../crypto' +import { PrivateKey, PublicKeyBundle } from '../crypto' import { Keystore, TopicData } from './interfaces' import { decryptV1, encryptV1, encryptV2, decryptV2 } from './encryption' import { KeystoreError } from './errors' @@ -329,12 +329,20 @@ export default class InMemoryKeystore implements Keystore { context: req.context, }) + const sealed = await SealedInvitation.createV1({ + sender: this.v2Keys, + recipient, + created, + invitation, + }) + const topicData = { invitation, topic: invitation.topic, createdNs: req.createdNs, peerAddress: await recipient.walletSignatureAddress(), } + await this.v2Store.add([topicData]) return keystore.CreateInviteResponse.fromPartial({ @@ -404,9 +412,7 @@ export default class InMemoryKeystore implements Keystore { return { conversations: convos } } - async getV2Conversations(): Promise< - keystore.GetConversationsResponse - > { + async getV2Conversations(): Promise { const convos = this.v2Store.topics.map((invite) => topicDataToV2ConversationReference(invite as TopicData) ) diff --git a/src/keystore/rpcDefinitions.ts b/src/keystore/rpcDefinitions.ts index 6e37980fe..27512a790 100644 --- a/src/keystore/rpcDefinitions.ts +++ b/src/keystore/rpcDefinitions.ts @@ -1,11 +1,6 @@ import { keystore, authn, publicKey, signature } from '@xmtp/proto' import { Reader, Writer } from 'protobufjs/minimal' -const { - CreateInviteFromTopicRequest, - CreateInvitesRequest, - CreateInvitesResponse, - GetV2ConversationsResponse, -} = keystore +const { GetConversationsResponse } = keystore type Codec = { decode(input: Reader | Uint8Array, length?: number): T @@ -61,18 +56,6 @@ export const apiDefs: ApiDefs = { }, getV2Conversations: { req: null, - res: GetV2ConversationsResponse, - }, - getGroupConversations: { - req: null, - res: GetV2ConversationsResponse, - }, - createInvites: { - req: CreateInvitesRequest, - res: CreateInvitesResponse, - }, - createInviteFromTopic: { - req: CreateInviteFromTopicRequest, - res: CreateInvitesResponse, + res: keystore.GetConversationsResponse, }, } as const diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 40a54bcfe..36d3b6747 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -102,7 +102,8 @@ describe('conversations', () => { conversationId: 'bar', metadata: {}, }) - const fromKeystore = (await alice.keystore.getV2Conversations()).conversations + const fromKeystore = (await alice.keystore.getV2Conversations()) + .conversations expect(fromKeystore[1].context?.conversationId).toBe('bar') const aliceConversations3 = await alice.conversations.list() diff --git a/test/conversations/GroupChat.test.ts b/test/conversations/GroupChat.test.ts deleted file mode 100644 index 6cdc13c05..000000000 --- a/test/conversations/GroupChat.test.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { newLocalHostClient, sleep, waitForUserContact } from './../helpers' -import { Client, Conversation, DecodedMessage, GroupChat } from '../../src' - -describe('GroupChat', () => { - let alice: Client - let bob: Client - let charlie: Client - let carol: Client - - beforeEach(async () => { - alice = await newLocalHostClient({ publishLegacyContact: true }) - bob = await newLocalHostClient({ publishLegacyContact: true }) - charlie = await newLocalHostClient({ publishLegacyContact: true }) - carol = await newLocalHostClient({ publishLegacyContact: true }) - await waitForUserContact(alice, alice) - await waitForUserContact(bob, bob) - await waitForUserContact(charlie, charlie) - await waitForUserContact(carol, carol) - }) - - afterEach(async () => { - if (alice) await alice.close() - if (bob) await bob.close() - if (charlie) await charlie.close() - if (carol) await carol.close() - }) - - async function conversationFromTopic( - topic: string, - client: Client - ): Promise { - const conversations = await client.conversations.list() - return conversations.find((conversation) => { - if (conversation.topic === topic) { - return conversation - } - }) - } - - async function messages( - topic: string, - client: Client - ): Promise { - const conversation = await conversationFromTopic(topic, client) - - if (!conversation) { - throw new Error('no conversation found for topic: ' + topic) - } - - return await conversation.messages() - } - - it('can be started', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const aliceGroupChat = await GroupChat.fromConversation( - alice, - aliceConversation - ) - - expect(aliceGroupChat.members.length).toBe(3) - - const bobConversations = await bob.conversations.list() - const charlieConversations = await charlie.conversations.list() - - expect(bobConversations.length).toBe(1) - expect(charlieConversations.length).toBe(1) - }) - - it('lets people chat', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - await aliceConversation.send('hi everyone') - - const bobMessages = await messages(aliceConversation.topic, bob) - const charlieMessages = await messages(aliceConversation.topic, charlie) - - expect(bobMessages.length).toBe(1) - expect(bobMessages[0].content).toBe('hi everyone') - expect(bobMessages[0].senderAddress).toBe(alice.address) - - expect(charlieMessages.length).toBe(1) - expect(charlieMessages[0].content).toBe('hi everyone') - expect(charlieMessages[0].senderAddress).toBe(alice.address) - - const charlieConversation = await conversationFromTopic( - aliceConversation.topic, - charlie - ) - - await charlieConversation!.send('hi nice to see u all') - - const bobMessages2 = await messages(aliceConversation.topic, bob) - const aliceMessages = await messages(aliceConversation.topic, alice) - - expect(bobMessages2.length).toBe(2) - expect(bobMessages2[1].content).toBe('hi nice to see u all') - expect(bobMessages2[1].senderAddress).toBe(charlie.address) - - expect(aliceMessages.length).toBe(2) - expect(aliceMessages[1].content).toBe('hi nice to see u all') - expect(aliceMessages[1].senderAddress).toBe(charlie.address) - }) - - it('can have a title', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const aliceGroupChat = new GroupChat(alice, aliceConversation) - expect(aliceGroupChat.title).toBe('') - - await aliceGroupChat.changeTitle('the fun group') - - const bobConversation = (await conversationFromTopic( - aliceConversation.topic, - bob - ))! - - const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation) - expect(bobGroupChat.title).toBe('the fun group') - - const charlieConversation = (await conversationFromTopic( - aliceConversation.topic, - charlie - ))! - - const charlieGroupChat = await GroupChat.fromConversation( - charlie, - charlieConversation - ) - expect(charlieGroupChat.title).toBe('the fun group') - }) - - it('can add members', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const groupChat = await GroupChat.fromConversation(alice, aliceConversation) - await groupChat.addMember(carol.address) - - const bobConversation = await conversationFromTopic( - aliceConversation.topic, - bob - ) - - const bobGroupChat = await GroupChat.fromConversation(bob, bobConversation!) - await bobGroupChat.rebuild() - - expect(bobGroupChat.members.length).toBe(4) - expect(bobGroupChat.members[3]).toBe(carol.address) - - await bobConversation!.send('hey carol') - - const carolMessages = await messages(aliceConversation.topic, carol) - expect(carolMessages[carolMessages.length - 1].content).toBe('hey carol') - }) - - it('can be rebuilt', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const aliceGroupChat = new GroupChat(alice, aliceConversation) - expect(aliceGroupChat.title).toBe('') - - await aliceGroupChat.addMember(carol.address) - await aliceGroupChat.changeTitle('the fun group') - - const unbuiltGroupChat = new GroupChat(alice, aliceConversation) - expect(unbuiltGroupChat.title).toBe('') - expect(unbuiltGroupChat.members.length).toBe(0) - - await unbuiltGroupChat.rebuild() - - expect(unbuiltGroupChat.title).toBe('the fun group') - expect(unbuiltGroupChat.members.length).toBe(4) - }) - - it('can be rebuilt partially', async () => { - alice.enableGroupChat() - bob.enableGroupChat() - charlie.enableGroupChat() - - const aliceConversation = await alice.conversations.newGroupConversation([ - bob.address, - charlie.address, - ]) - - const aliceGroupChat = new GroupChat(alice, aliceConversation) - expect(aliceGroupChat.title).toBe('') - - await aliceGroupChat.addMember(carol.address) - - await sleep(1000) - const date = new Date() - await sleep(1000) - - await aliceGroupChat.changeTitle('the fun group') - - const unbuiltGroupChat = new GroupChat(alice, aliceConversation) - expect(unbuiltGroupChat.title).toBe('') - - await unbuiltGroupChat.rebuild({ since: date }) - - // We should only get the second update because the first one happened before - // our `since` - expect(unbuiltGroupChat.title).toBe('the fun group') - expect(unbuiltGroupChat.members.length).toBe(3) - }) -}) diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index 20f1e7466..bde7d586b 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -234,14 +234,14 @@ describe('InMemoryKeystore', () => { if (firstResult.error) { throw firstResult.error } - + expect( nsToDate(firstResult.result!.conversation!.createdNs).getTime() ).toEqual(created.getTime()) expect(firstResult.result!.conversation!.topic).toEqual(invite.topic) expect(firstResult.result!.conversation?.context).toBeUndefined() - const conversations = await keystore.getV2Conversations() + const conversations = (await keystore.getV2Conversations()).conversations expect(conversations).toHaveLength(1) expect(conversations[0].topic).toBe(invite.topic) }) From 2185e6c302382e5e2dd6d73123ee3cdd6e2a80cd Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:56:36 -0700 Subject: [PATCH 099/137] chore: update RPCs available --- src/conversations/Conversation.ts | 7 ------- src/keystore/rpcDefinitions.ts | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 0ea54e263..206009560 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -61,11 +61,6 @@ export interface Conversation { */ createdAt: Date - /** - * Is this conversation a group chat - */ - isGroup: boolean - /** * Optional field containing the `conversationId` and `metadata` for V2 conversations. * Will always be undefined on V1 conversations @@ -156,7 +151,6 @@ export class ConversationV1 implements Conversation { peerAddress: string createdAt: Date context = undefined - isGroup = false private client: Client constructor(client: Client, address: string, createdAt: Date) { @@ -443,7 +437,6 @@ export class ConversationV2 implements Conversation { peerAddress: string createdAt: Date context?: InvitationContext - isGroup = false constructor( client: Client, diff --git a/src/keystore/rpcDefinitions.ts b/src/keystore/rpcDefinitions.ts index 27512a790..b362d3e7f 100644 --- a/src/keystore/rpcDefinitions.ts +++ b/src/keystore/rpcDefinitions.ts @@ -1,6 +1,5 @@ import { keystore, authn, publicKey, signature } from '@xmtp/proto' import { Reader, Writer } from 'protobufjs/minimal' -const { GetConversationsResponse } = keystore type Codec = { decode(input: Reader | Uint8Array, length?: number): T @@ -54,8 +53,24 @@ export const apiDefs: ApiDefs = { req: null, res: publicKey.PublicKeyBundle, }, + saveV1Conversations: { + req: keystore.SaveV1ConversationsRequest, + res: keystore.SaveV1ConversationsResponse, + }, + getV1Conversations: { + req: null, + res: keystore.GetConversationsResponse, + }, getV2Conversations: { req: null, res: keystore.GetConversationsResponse, }, + getRefreshJob: { + req: keystore.GetRefreshJobRequest, + res: keystore.GetRefreshJobResponse, + }, + setRefreshJob: { + req: keystore.SetRefeshJobRequest, + res: keystore.SetRefreshJobResponse, + }, } as const From 0129b7586c9b9bf096d3d7a411b91c96f63f4d45 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:57:00 -0700 Subject: [PATCH 100/137] build: remove deployment from snap directory --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e126816b6..06f1c980d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,6 @@ on: branches: - main - beta - - snap permissions: contents: read From 112930f2e365ee602400fce90fe116293daffe3b Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:27:11 -0700 Subject: [PATCH 101/137] feat: improved feature detection for Snaps --- src/keystore/providers/SnapProvider.ts | 16 ++++++---- src/keystore/snapHelpers.ts | 44 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 90f5a3699..46f312e8b 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -6,8 +6,8 @@ import { connectSnap, getSnap, getWalletStatus, + hasMetamaskWithSnaps, initSnap, - isFlask, } from '../snapHelpers' import { keystore } from '@xmtp/proto' import { Signer } from '../../types/Signer' @@ -29,22 +29,24 @@ export default class SnapKeystoreProvider implements KeystoreProvider { apiClient: ApiClient, wallet?: Signer ): Promise { - console.log('Starting Snap Keystore provider') - if (!isFlask()) { - throw new KeystoreProviderUnavailableError('Flask not detected') - } if (!wallet) { throw new KeystoreProviderUnavailableError('No wallet provided') } + + if (!hasMetamaskWithSnaps()) { + throw new KeystoreProviderUnavailableError( + 'MetaMask with Snaps not detected' + ) + } + const walletAddress = await wallet.getAddress() const env = opts.env const hasSnap = await getSnap() + if (!hasSnap) { - console.log('Connecting snap') await connectSnap() } - console.log('Checking if snap is loaded') if (!(await checkSnapLoaded(walletAddress, env))) { const bundle = await getBundle(opts, apiClient, wallet) await initSnap(bundle, env) diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index d5955895d..dd1ad7573 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -97,6 +97,50 @@ export async function isFlask() { } } +// If a browser has multiple providers, but one of them supports MetaMask flask +// this function will ensure that Flask is being used and return true. +// Designed to be resistant to provider clobbering by Phantom and CBW +// Inspired by https://github.com/Montoya/snap-connect-test/blob/main/index.html +export async function hasMetamaskWithSnaps() { + if ('detected' in window.ethereum) { + for (const provider of window.ethereum.detected) { + try { + // Detect snaps support + await provider.request({ + method: 'wallet_getSnaps', + }) + // enforces MetaMask as provider + window.ethereum.setProvider(provider) + + return true + } catch { + // no-op + } + } + } + + if ('providers' in window.ethereum) { + for (const provider of window.ethereum.providers) { + try { + // Detect snaps support + await provider.request({ + method: 'wallet_getSnaps', + }) + + window.ethereum = provider + + return true + } catch { + // no-op + } + } + + return false + } + + return window.ethereum +} + export async function getSnaps(): Promise { return (await getEthereum()?.request({ method: 'wallet_getSnaps', From 4ef2c6a0ac106ab115de8ef49a84241a5d301c1d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:11:37 -0700 Subject: [PATCH 102/137] build: better typing for window.ethereum --- package-lock.json | 184 ++++++++++++++++++++++++++++++++++++ package.json | 1 + src/keystore/snapHelpers.ts | 12 ++- src/types/metamask.ts | 13 ++- 4 files changed, 204 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a580b80d..548dbaf74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "devDependencies": { "@commitlint/cli": "^16.1.0", "@commitlint/config-conventional": "^16.0.0", + "@metamask/providers": "^11.1.1", "@types/benchmark": "^2.1.2", "@types/bl": "^5.0.2", "@types/callback-to-async-iterator": "^1.1.4", @@ -2300,6 +2301,75 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "node_modules/@metamask/object-multiplex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz", + "integrity": "sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "readable-stream": "^2.3.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@metamask/object-multiplex/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@metamask/providers": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.1.tgz", + "integrity": "sha512-zvsa7wRO6E1vQOb6CvRlpcWwS1LQEIV7cPEcXGZEsy3wFwRjvLDTT4vDy2FzSSHyspJZsOls+WGkFXPl+0bL/g==", + "dev": true, + "dependencies": { + "@metamask/object-multiplex": "^1.1.0", + "@metamask/safe-event-emitter": "^3.0.0", + "detect-browser": "^5.2.0", + "eth-rpc-errors": "^4.0.2", + "extension-port-stream": "^2.0.1", + "fast-deep-equal": "^3.1.3", + "is-stream": "^2.0.0", + "json-rpc-engine": "^6.1.0", + "json-rpc-middleware-stream": "^4.2.1", + "pump": "^3.0.0", + "webextension-polyfill": "^0.10.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@metamask/safe-event-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz", + "integrity": "sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@noble/secp256k1": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.2.tgz", @@ -5126,6 +5196,12 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "dev": true + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -5281,6 +5357,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/env-ci": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-9.1.0.tgz", @@ -6299,6 +6384,15 @@ "node": ">=0.10.0" } }, + "node_modules/eth-rpc-errors": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", + "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "dev": true, + "dependencies": { + "fast-safe-stringify": "^2.0.6" + } + }, "node_modules/ethers": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.3.tgz", @@ -6400,6 +6494,18 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/extension-port-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-2.1.1.tgz", + "integrity": "sha512-qknp5o5rj2J9CRKfVB8KJr+uXQlrojNZzdESUPhKYLXf97TPcGf6qWWKmpsNNtUyOdzFhab1ON0jzouNxHHvow==", + "dev": true, + "dependencies": { + "webextension-polyfill": ">=0.10.0 <1.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6440,6 +6546,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -8572,6 +8684,62 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-rpc-engine": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", + "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", + "dev": true, + "dependencies": { + "@metamask/safe-event-emitter": "^2.0.0", + "eth-rpc-errors": "^4.0.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", + "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", + "dev": true + }, + "node_modules/json-rpc-middleware-stream": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/json-rpc-middleware-stream/-/json-rpc-middleware-stream-4.2.2.tgz", + "integrity": "sha512-tmTQCI/R8wKMTWB50xlzkyh90JR5VuKiDVlWlmG7DjeKfdDtbLL/4vYCRlG5HnSSKkhrkVPI0TrHQz1Dethl7A==", + "dev": true, + "dependencies": { + "@metamask/safe-event-emitter": "^3.0.0", + "readable-stream": "^2.3.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/json-rpc-middleware-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/json-rpc-middleware-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -13171,6 +13339,16 @@ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -15370,6 +15548,12 @@ "makeerror": "1.0.12" } }, + "node_modules/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", + "dev": true + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 2b4b1879d..ea08c8cd9 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "devDependencies": { "@commitlint/cli": "^16.1.0", "@commitlint/config-conventional": "^16.0.0", + "@metamask/providers": "^11.1.1", "@types/benchmark": "^2.1.2", "@types/bl": "^5.0.2", "@types/callback-to-async-iterator": "^1.1.4", diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index dd1ad7573..d6ac093e4 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -102,7 +102,10 @@ export async function isFlask() { // Designed to be resistant to provider clobbering by Phantom and CBW // Inspired by https://github.com/Montoya/snap-connect-test/blob/main/index.html export async function hasMetamaskWithSnaps() { - if ('detected' in window.ethereum) { + if ( + typeof window.ethereum?.detected !== 'undefined' && + Array.isArray(window.ethereum.detected) + ) { for (const provider of window.ethereum.detected) { try { // Detect snaps support @@ -110,7 +113,7 @@ export async function hasMetamaskWithSnaps() { method: 'wallet_getSnaps', }) // enforces MetaMask as provider - window.ethereum.setProvider(provider) + window.ethereum?.setProvider?.(provider) return true } catch { @@ -119,7 +122,10 @@ export async function hasMetamaskWithSnaps() { } } - if ('providers' in window.ethereum) { + if ( + typeof window.ethereum?.providers !== 'undefined' && + Array.isArray(window.ethereum.providers) + ) { for (const provider of window.ethereum.providers) { try { // Detect snaps support diff --git a/src/types/metamask.ts b/src/types/metamask.ts index e93cc49d3..ee1a7a72f 100644 --- a/src/types/metamask.ts +++ b/src/types/metamask.ts @@ -1,16 +1,23 @@ /* eslint-disable*/ import { MetaMaskInpageProvider } from '@metamask/providers' +import type { providers } from 'ethers' + +type EthereumType = MetaMaskInpageProvider & { + setProvider?: (provider: MetaMaskInpageProvider) => void + detected?: MetaMaskInpageProvider[] + providers?: MetaMaskInpageProvider[] +} + /* * Window type extension to support ethereum */ - declare global { interface Window { - ethereum: MetaMaskInpageProvider + ethereum: EthereumType } interface globalThis { - ethereum: MetaMaskInpageProvider + ethereum: EthereumType } } From 4296b1fe1719c324a67912c7e9362239026b23e0 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:32:47 -0700 Subject: [PATCH 103/137] test: add tests for users without metamask --- src/keystore/providers/SnapProvider.ts | 1 + src/keystore/snapHelpers.ts | 33 +++++++------------------- test/keystore/snapHelpers.test.ts | 22 +++++++++++++---- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 46f312e8b..5c2c10e31 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -17,6 +17,7 @@ import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' import type { XmtpEnv } from '../../Client' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus } = keystore + /** * The Snap keystore provider will: * 1. Check if the user is capable of using Snaps diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index d6ac093e4..e709f51ff 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -83,37 +83,24 @@ export type Snap = { export type GetSnapsResponse = Record -export async function isFlask() { - try { - const ethereum = getEthereum() - const clientVersion = await ethereum?.request({ - method: 'web3_clientVersion', - }) - const isFlaskDetected = (clientVersion as string[])?.includes('flask') - - return Boolean(ethereum && isFlaskDetected) - } catch (e) { - return false - } -} - // If a browser has multiple providers, but one of them supports MetaMask flask // this function will ensure that Flask is being used and return true. // Designed to be resistant to provider clobbering by Phantom and CBW // Inspired by https://github.com/Montoya/snap-connect-test/blob/main/index.html export async function hasMetamaskWithSnaps() { + const ethereum = getEthereum() if ( - typeof window.ethereum?.detected !== 'undefined' && - Array.isArray(window.ethereum.detected) + typeof ethereum?.detected !== 'undefined' && + Array.isArray(ethereum.detected) ) { - for (const provider of window.ethereum.detected) { + for (const provider of ethereum.detected) { try { // Detect snaps support await provider.request({ method: 'wallet_getSnaps', }) // enforces MetaMask as provider - window.ethereum?.setProvider?.(provider) + ethereum?.setProvider?.(provider) return true } catch { @@ -123,10 +110,10 @@ export async function hasMetamaskWithSnaps() { } if ( - typeof window.ethereum?.providers !== 'undefined' && - Array.isArray(window.ethereum.providers) + typeof ethereum?.providers !== 'undefined' && + Array.isArray(ethereum.providers) ) { - for (const provider of window.ethereum.providers) { + for (const provider of ethereum.providers) { try { // Detect snaps support await provider.request({ @@ -140,11 +127,9 @@ export async function hasMetamaskWithSnaps() { // no-op } } - - return false } - return window.ethereum + return false } export async function getSnaps(): Promise { diff --git a/test/keystore/snapHelpers.test.ts b/test/keystore/snapHelpers.test.ts index a292c22b0..3fddab803 100644 --- a/test/keystore/snapHelpers.test.ts +++ b/test/keystore/snapHelpers.test.ts @@ -1,7 +1,7 @@ import { defaultSnapOrigin, getWalletStatus, - isFlask, + hasMetamaskWithSnaps, } from '../../src/keystore/snapHelpers' import { keystore } from '@xmtp/proto' import { b64Encode } from '../../src/utils' @@ -16,9 +16,14 @@ const mockRequest = jest.fn() jest.mock('../../src/utils/ethereum', () => { return { __esModule: true, - getEthereum: jest.fn(() => ({ - request: mockRequest, - })), + getEthereum: jest.fn(() => { + const ethereum: any = { + request: mockRequest, + } + ethereum.providers = [ethereum] + ethereum.detected = [ethereum] + return ethereum + }), } }) @@ -30,10 +35,17 @@ describe('snapHelpers', () => { it('can check if the user has Flask installed', async () => { mockRequest.mockResolvedValue(['flask']) - expect(await isFlask()).toBe(true) + expect(await hasMetamaskWithSnaps()).toBe(true) expect(mockRequest).toHaveBeenCalledTimes(1) }) + it('returns false when the user does not have flask installed', async () => { + mockRequest.mockRejectedValue(new Error('foo')) + + expect(await hasMetamaskWithSnaps()).toBe(false) + expect(mockRequest).toHaveBeenCalledTimes(2) + }) + it('can check wallet status', async () => { const method = 'getKeystoreStatus' const walletAddress = '0xfoo' From 77d0c90b9931f605933e18ce6caad80e6653842c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:36:16 -0700 Subject: [PATCH 104/137] chore: remove unused types --- test/conversations/Conversations.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/conversations/Conversations.test.ts b/test/conversations/Conversations.test.ts index 36d3b6747..aff73b602 100644 --- a/test/conversations/Conversations.test.ts +++ b/test/conversations/Conversations.test.ts @@ -9,8 +9,6 @@ import { buildUserIntroTopic, sleep, } from '../../src/utils' -import { InvitationV1 } from '../../src/Invitation' -import { InvitationV1_Context } from '@xmtp/proto/ts/dist/types/message_contents/invitation.pb' describe('conversations', () => { let alice: Client From 985961097a6e3d9ad9af5a9609da6c98cb17ae33 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:36:51 -0700 Subject: [PATCH 105/137] chore: remove unused types --- test/conversations/Conversation.test.ts | 10 ++-------- test/keystore/conversationStores.test.ts | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/test/conversations/Conversation.test.ts b/test/conversations/Conversation.test.ts index d991511ff..455530ce9 100644 --- a/test/conversations/Conversation.test.ts +++ b/test/conversations/Conversation.test.ts @@ -1,19 +1,13 @@ import { DecodedMessage, MessageV1 } from './../../src/Message' import { buildDirectMessageTopic } from './../../src/utils' -import { - Client, - Compression, - ContentTypeFallback, - ContentTypeId, - ContentTypeText, -} from '../../src' +import { Client, Compression, ContentTypeId, ContentTypeText } from '../../src' import { SortDirection } from '../../src/ApiClient' import { sleep } from '../../src/utils' import { newLocalHostClient, waitForUserContact } from '../helpers' import { PrivateKey, SignedPublicKeyBundle } from '../../src/crypto' import { ConversationV2 } from '../../src/conversations/Conversation' import { ContentTypeTestKey, TestKeyCodec } from '../ContentTypeTestKey' -import { content as proto, fetcher } from '@xmtp/proto' +import { content as proto } from '@xmtp/proto' describe('conversation', () => { let alice: Client diff --git a/test/keystore/conversationStores.test.ts b/test/keystore/conversationStores.test.ts index 6b6d92159..37124f5a5 100644 --- a/test/keystore/conversationStores.test.ts +++ b/test/keystore/conversationStores.test.ts @@ -1,5 +1,5 @@ import crypto from '../../src/crypto/crypto' -import { V2Store, TopicData } from '../../src/keystore' +import { V2Store } from '../../src/keystore' import { AddRequest, V1Store } from '../../src/keystore/conversationStores' import { InMemoryPersistence } from '../../src/keystore/persistence' import { dateToNs } from '../../src/utils' From c856165c8d4495f563991566d1884fe799cd2455 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 30 Aug 2023 08:34:10 -0700 Subject: [PATCH 106/137] test: add tests for SnapProvider --- .../providers/KeyGeneratorKeystoreProvider.ts | 2 +- src/keystore/providers/SnapProvider.ts | 5 +- test/keystore/providers/SnapProvider.test.ts | 99 +++++++++++++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 test/keystore/providers/SnapProvider.test.ts diff --git a/src/keystore/providers/KeyGeneratorKeystoreProvider.ts b/src/keystore/providers/KeyGeneratorKeystoreProvider.ts index 9e71aa80d..3ae3775f3 100644 --- a/src/keystore/providers/KeyGeneratorKeystoreProvider.ts +++ b/src/keystore/providers/KeyGeneratorKeystoreProvider.ts @@ -1,4 +1,4 @@ -import ApiClient from '../../ApiClient' +import { ApiClient } from '../../ApiClient' import { PrivateKeyBundleV1 } from '../../crypto' import InMemoryKeystore from '../InMemoryKeystore' import TopicPersistence from '../persistence/TopicPersistence' diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 5c2c10e31..2da9f350d 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -11,7 +11,7 @@ import { } from '../snapHelpers' import { keystore } from '@xmtp/proto' import { Signer } from '../../types/Signer' -import ApiClient from '../../ApiClient' +import { ApiClient } from '../../ApiClient' import NetworkKeystoreProvider from './NetworkKeystoreProvider' import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' @@ -34,7 +34,7 @@ export default class SnapKeystoreProvider implements KeystoreProvider { throw new KeystoreProviderUnavailableError('No wallet provided') } - if (!hasMetamaskWithSnaps()) { + if (!(await hasMetamaskWithSnaps())) { throw new KeystoreProviderUnavailableError( 'MetaMask with Snaps not detected' ) @@ -43,7 +43,6 @@ export default class SnapKeystoreProvider implements KeystoreProvider { const walletAddress = await wallet.getAddress() const env = opts.env const hasSnap = await getSnap() - if (!hasSnap) { await connectSnap() } diff --git a/test/keystore/providers/SnapProvider.test.ts b/test/keystore/providers/SnapProvider.test.ts new file mode 100644 index 000000000..c7b9fd73e --- /dev/null +++ b/test/keystore/providers/SnapProvider.test.ts @@ -0,0 +1,99 @@ +import HttpApiClient, { ApiClient, ApiUrls } from '../../../src/ApiClient' +import { + KeystoreProviderOptions, + KeystoreProviderUnavailableError, +} from '../../../src/keystore/providers' +import { newWallet } from '../../helpers' +import SnapKeystoreProvider from '../../../src/keystore/providers/SnapProvider' +import { + connectSnap, + getSnap, + getWalletStatus, + hasMetamaskWithSnaps, + initSnap, +} from '../../../src/keystore/snapHelpers' +import { Signer } from '../../../src/types/Signer' +import { keystore as keystoreProto } from '@xmtp/proto' + +jest.mock('../../../src/keystore/snapHelpers') + +describe('SnapProvider', () => { + const provider = new SnapKeystoreProvider() + const options = { env: 'local' } as KeystoreProviderOptions + let apiClient: ApiClient + let wallet: Signer + + beforeEach(async () => { + apiClient = new HttpApiClient(ApiUrls['local']) + wallet = newWallet() + jest.resetAllMocks() + }) + + it('should throw an error if no wallet is provided', async () => { + await expect( + provider.newKeystore(options, apiClient, undefined) + ).rejects.toThrow('No wallet provided') + }) + + it('should throw a KeystoreProviderUnavailableError if MetaMask with Snaps is not detected', async () => { + ;(hasMetamaskWithSnaps as jest.Mock).mockReturnValue(Promise.resolve(false)) + + await expect( + provider.newKeystore(options, apiClient, wallet) + ).rejects.toThrow( + new KeystoreProviderUnavailableError('MetaMask with Snaps not detected') + ) + }) + + it('should attempt to connect to the snap if it is not already connected', async () => { + ;(hasMetamaskWithSnaps as jest.Mock).mockReturnValue(Promise.resolve(true)) + ;(getWalletStatus as jest.Mock).mockReturnValue( + Promise.resolve( + keystoreProto.GetKeystoreStatusResponse_KeystoreStatus + .KEYSTORE_STATUS_INITIALIZED + ) + ) + ;(getSnap as jest.Mock).mockReturnValue(Promise.resolve(undefined)) + + const keystore = await provider.newKeystore(options, apiClient, wallet) + + expect(keystore).toBeDefined() + expect(getWalletStatus as jest.Mock).toHaveBeenCalledTimes(1) + expect(getSnap as jest.Mock).toHaveBeenCalledTimes(1) + expect(connectSnap as jest.Mock).toHaveBeenCalledTimes(1) + expect(initSnap as jest.Mock).not.toHaveBeenCalled() + }) + + it('does not attempt to connect to the snap if it is already connected', async () => { + ;(hasMetamaskWithSnaps as jest.Mock).mockReturnValue(Promise.resolve(true)) + ;(getWalletStatus as jest.Mock).mockReturnValue( + Promise.resolve( + keystoreProto.GetKeystoreStatusResponse_KeystoreStatus + .KEYSTORE_STATUS_INITIALIZED + ) + ) + ;(getSnap as jest.Mock).mockReturnValue(Promise.resolve({})) + ;(connectSnap as jest.Mock).mockReturnValue(Promise.resolve()) + + await provider.newKeystore(options, apiClient, wallet) + expect(connectSnap as jest.Mock).not.toHaveBeenCalled() + }) + + it('initializes the snap if it is not already initialized', async () => { + ;(hasMetamaskWithSnaps as jest.Mock).mockReturnValue(Promise.resolve(true)) + ;(getWalletStatus as jest.Mock).mockReturnValue( + Promise.resolve( + keystoreProto.GetKeystoreStatusResponse_KeystoreStatus + .KEYSTORE_STATUS_UNINITIALIZED + ) + ) + ;(getSnap as jest.Mock).mockReturnValue(Promise.resolve({})) + ;(connectSnap as jest.Mock).mockReturnValue(Promise.resolve()) + ;(initSnap as jest.Mock).mockReturnValue(Promise.resolve()) + + const keystore = await provider.newKeystore(options, apiClient, wallet) + + expect(keystore).toBeDefined() + expect(initSnap as jest.Mock).toHaveBeenCalledTimes(1) + }) +}) From 45c18acc2eef2642bfad9dd4432d2d0698810a1a Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 30 Aug 2023 08:35:27 -0700 Subject: [PATCH 107/137] test: add one more assertion to tests --- test/keystore/providers/SnapProvider.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/keystore/providers/SnapProvider.test.ts b/test/keystore/providers/SnapProvider.test.ts index c7b9fd73e..12337d986 100644 --- a/test/keystore/providers/SnapProvider.test.ts +++ b/test/keystore/providers/SnapProvider.test.ts @@ -77,6 +77,7 @@ describe('SnapProvider', () => { await provider.newKeystore(options, apiClient, wallet) expect(connectSnap as jest.Mock).not.toHaveBeenCalled() + expect(initSnap as jest.Mock).not.toHaveBeenCalled() }) it('initializes the snap if it is not already initialized', async () => { From 5e0bc9c9da094769b2d931d4668b0ca644f1c628 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 30 Aug 2023 08:41:16 -0700 Subject: [PATCH 108/137] chore: remove newline --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06f1c980d..f0e8033cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,6 @@ on: - beta permissions: contents: read - jobs: release: name: Release From 7f318b138c36c352323dbf57523447033af7bbf2 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 30 Aug 2023 08:42:23 -0700 Subject: [PATCH 109/137] chore: add back newline --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0e8033cc..dc2303f69 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,10 @@ on: branches: - main - beta + permissions: contents: read + jobs: release: name: Release From 066650d03a6bb8b47f8b49f3a9ae7daec3183340 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:22:30 -0700 Subject: [PATCH 110/137] fix: better feature detection of metamask --- src/keystore/snapHelpers.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index e709f51ff..ef6163cad 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -89,6 +89,17 @@ export type GetSnapsResponse = Record // Inspired by https://github.com/Montoya/snap-connect-test/blob/main/index.html export async function hasMetamaskWithSnaps() { const ethereum = getEthereum() + // Naive way of detecting snaps support + if (ethereum?.isMetaMask) { + try { + await ethereum.request({ + method: 'wallet_getSnaps', + }) + return true + } catch { + // no-op + } + } if ( typeof ethereum?.detected !== 'undefined' && Array.isArray(ethereum.detected) From f9e1add47440fa5c33bd51bb586894f4cbd1488f Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 31 Aug 2023 16:52:40 -0700 Subject: [PATCH 111/137] fix: we shouldn't be upgrading NPM node 18.14 should come with npm 9 --- .github/workflows/release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc2303f69..cd51cfbf2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,9 +26,6 @@ jobs: uses: actions/setup-node@v3 with: node-version-file: '.nvmrc' - - name: Use latest NPM - # Ensure we are using the latest version of NPM to get support for provenance - run: npm i -g npm - name: Install dependencies run: npm ci - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies From 23f4c7889f213e2f734d3a8d413673003782a5c5 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 31 Aug 2023 16:59:00 -0700 Subject: [PATCH 112/137] fix: missing persistance --- test/keystore/InMemoryKeystore.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/keystore/InMemoryKeystore.test.ts b/test/keystore/InMemoryKeystore.test.ts index eba7e66c8..fdbe92d67 100644 --- a/test/keystore/InMemoryKeystore.test.ts +++ b/test/keystore/InMemoryKeystore.test.ts @@ -559,7 +559,10 @@ describe('InMemoryKeystore', () => { ) ).v1! ) - bobKeystore = await InMemoryKeystore.create(bobKeys) + bobKeystore = await InMemoryKeystore.create( + bobKeys, + InMemoryPersistence.create() + ) expect(await aliceKeystore.getAccountAddress()).toEqual( '0xF56d1F3b1290204441Cb3843C2Cac1C2f5AEd690' From de871f51e336186ab9b6d6545d0e547c91f7e1bb Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Mon, 4 Sep 2023 22:35:47 -0700 Subject: [PATCH 113/137] feat: allow caller to specify snap origin --- src/keystore/SnapKeystore.ts | 15 +++++++---- src/keystore/providers/SnapProvider.ts | 28 ++++++++++++++----- src/keystore/snapHelpers.ts | 37 +++++++++++++++----------- test/keystore/snapHelpers.test.ts | 9 ++++--- 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/keystore/SnapKeystore.ts b/src/keystore/SnapKeystore.ts index 22fca4c8c..008ac2aef 100644 --- a/src/keystore/SnapKeystore.ts +++ b/src/keystore/SnapKeystore.ts @@ -6,12 +6,17 @@ import { apiDefs } from './rpcDefinitions' async function getResponse( method: T, req: Uint8Array | null, - meta: SnapMeta + meta: SnapMeta, + snapId: string ): Promise { - return snapRPC(method, apiDefs[method], req, meta) + return snapRPC(method, apiDefs[method], req, meta, snapId) } -export function SnapKeystore(walletAddress: string, env: XmtpEnv): Keystore { +export function SnapKeystore( + walletAddress: string, + env: XmtpEnv, + snapId: string +): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any const generatedMethods: any = {} @@ -24,10 +29,10 @@ export function SnapKeystore(walletAddress: string, env: XmtpEnv): Keystore { // eslint-disable-next-line @typescript-eslint/no-explicit-any generatedMethods[method] = async (req: any) => { if (!apiDef.req) { - return getResponse(method as keyof Keystore, null, snapMeta) + return getResponse(method as keyof Keystore, null, snapMeta, snapId) } - return getResponse(method as keyof Keystore, req, snapMeta) + return getResponse(method as keyof Keystore, req, snapMeta, snapId) } } diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 2da9f350d..ea7e8608f 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -18,6 +18,8 @@ import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' import type { XmtpEnv } from '../../Client' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus } = keystore +export const SNAP_LOCAL_ORIGIN = 'local:http://localhost:8080' + /** * The Snap keystore provider will: * 1. Check if the user is capable of using Snaps @@ -25,6 +27,14 @@ const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus } = keystore * 3. If not, will get keys from the network or create new keys and store them in the Snap */ export default class SnapKeystoreProvider implements KeystoreProvider { + snapId: string + snapVersion?: string + + constructor(snapId = SNAP_LOCAL_ORIGIN, snapVersion?: string) { + this.snapId = snapId + this.snapVersion = snapVersion + } + async newKeystore( opts: KeystoreProviderOptions, apiClient: ApiClient, @@ -42,17 +52,17 @@ export default class SnapKeystoreProvider implements KeystoreProvider { const walletAddress = await wallet.getAddress() const env = opts.env - const hasSnap = await getSnap() + const hasSnap = await getSnap(this.snapId, this.snapVersion) if (!hasSnap) { - await connectSnap() + await connectSnap(this.snapId) } - if (!(await checkSnapLoaded(walletAddress, env))) { + if (!(await checkSnapLoaded(walletAddress, env, this.snapId))) { const bundle = await getBundle(opts, apiClient, wallet) - await initSnap(bundle, env) + await initSnap(bundle, env, this.snapId) } - return SnapKeystore(walletAddress, env) + return SnapKeystore(walletAddress, env, this.snapId) } } @@ -89,8 +99,12 @@ async function getBundle( } } -async function checkSnapLoaded(walletAddress: string, env: XmtpEnv) { - const status = await getWalletStatus({ walletAddress, env }) +async function checkSnapLoaded( + walletAddress: string, + env: XmtpEnv, + snapId: string +) { + const status = await getWalletStatus({ walletAddress, env }, snapId) if (status === KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) { return true } diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index ef6163cad..021592a0e 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -13,9 +13,6 @@ const { GetKeystoreStatusResponse, } = keystoreProto -// TODO: Replace with npm package once released -export const defaultSnapOrigin = `local:http://localhost:8080` - export type SnapMeta = { walletAddress: string env: XmtpEnv @@ -30,7 +27,8 @@ export async function snapRPC( method: string, codecs: RPC, req: Req, - meta: SnapMeta + meta: SnapMeta, + snapId: string ): Promise { let reqParam = null if (codecs.req) { @@ -38,7 +36,7 @@ export async function snapRPC( reqParam = b64Encode(reqBytes, 0, reqBytes.length) } - const responseString = await snapRequest(method, reqParam, meta) + const responseString = await snapRequest(method, reqParam, meta, snapId) if (Array.isArray(responseString)) { throw new Error('Unexpected array response') } @@ -49,7 +47,8 @@ export async function snapRPC( export async function snapRequest( method: string, req: string | null, - meta: SnapMeta + meta: SnapMeta, + snapId: string ): Promise { const params: SnapParams = { meta } if (typeof req === 'string') { @@ -58,7 +57,7 @@ export async function snapRequest( const response = await getEthereum().request({ method: 'wallet_invokeSnap', params: { - snapId: defaultSnapOrigin, + snapId, request: { method, params, @@ -149,13 +148,15 @@ export async function getSnaps(): Promise { })) as unknown as GetSnapsResponse } -export async function getSnap(version?: string): Promise { +export async function getSnap( + snapId: string, + version?: string +): Promise { try { const snaps = await getSnaps() return Object.values(snaps).find( - (snap) => - snap.id === defaultSnapOrigin && (!version || snap.version === version) + (snap) => snap.id === snapId && (!version || snap.version === version) ) } catch (e) { console.warn('Failed to obtain installed snap', e) @@ -164,7 +165,7 @@ export async function getSnap(version?: string): Promise { } export async function connectSnap( - snapId: string = defaultSnapOrigin, + snapId: string, params: Record<'version' | string, unknown> = {} ) { await getEthereum()?.request({ @@ -179,14 +180,15 @@ const getWalletStatusCodec = { req: GetKeystoreStatusRequest, res: GetKeystoreStatusResponse, } -export async function getWalletStatus(meta: SnapMeta) { +export async function getWalletStatus(meta: SnapMeta, snapId: string) { const response = await snapRPC( 'getKeystoreStatus', getWalletStatusCodec, { walletAddress: meta.walletAddress, }, - meta + meta, + snapId ) if ( @@ -205,7 +207,11 @@ const initKeystoreCodec = { req: InitKeystoreRequest, res: InitKeystoreResponse, } -export async function initSnap(bundle: PrivateKeyBundleV1, env: XmtpEnv) { +export async function initSnap( + bundle: PrivateKeyBundleV1, + env: XmtpEnv, + snapId: string +) { const walletAddress = bundle.identityKey.publicKey.walletSignatureAddress() const response = await snapRPC( 'initKeystore', @@ -213,7 +219,8 @@ export async function initSnap(bundle: PrivateKeyBundleV1, env: XmtpEnv) { { v1: bundle, }, - { walletAddress, env } + { walletAddress, env }, + snapId ) if (response.error) { throw new KeystoreError(response.error.code, response.error.message) diff --git a/test/keystore/snapHelpers.test.ts b/test/keystore/snapHelpers.test.ts index 3fddab803..cd162a9a5 100644 --- a/test/keystore/snapHelpers.test.ts +++ b/test/keystore/snapHelpers.test.ts @@ -1,10 +1,10 @@ import { - defaultSnapOrigin, getWalletStatus, hasMetamaskWithSnaps, } from '../../src/keystore/snapHelpers' import { keystore } from '@xmtp/proto' import { b64Encode } from '../../src/utils' +import { SNAP_LOCAL_ORIGIN } from '../../src/keystore/providers/SnapProvider' const { GetKeystoreStatusRequest, GetKeystoreStatusResponse, @@ -58,7 +58,10 @@ describe('snapHelpers', () => { res: b64Encode(resBytes, 0, resBytes.length), }) - const status = await getWalletStatus({ walletAddress, env }) + const status = await getWalletStatus( + { walletAddress, env }, + SNAP_LOCAL_ORIGIN + ) expect(status).toBe(KeystoreStatus.KEYSTORE_STATUS_INITIALIZED) const expectedRequest = GetKeystoreStatusRequest.encode({ walletAddress, @@ -67,7 +70,7 @@ describe('snapHelpers', () => { expect(mockRequest).toHaveBeenCalledWith({ method: 'wallet_invokeSnap', params: { - snapId: defaultSnapOrigin, + snapId: SNAP_LOCAL_ORIGIN, request: { method, params: { From fc5b30ec8c1cd29dd9e07e31d716bebcdbd469f6 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:33:48 -0700 Subject: [PATCH 114/137] chore: include snap version in connection params --- src/keystore/providers/SnapProvider.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index ea7e8608f..3e87ddd26 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -54,7 +54,10 @@ export default class SnapKeystoreProvider implements KeystoreProvider { const env = opts.env const hasSnap = await getSnap(this.snapId, this.snapVersion) if (!hasSnap) { - await connectSnap(this.snapId) + await connectSnap( + this.snapId, + this.snapVersion ? { version: this.snapVersion } : {} + ) } if (!(await checkSnapLoaded(walletAddress, env, this.snapId))) { From f875fc647c53b8c43d230d303b951eccbd93e2e3 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:46:58 -0700 Subject: [PATCH 115/137] feat: semver support --- src/keystore/providers/SnapProvider.ts | 3 +- src/keystore/snapHelpers.ts | 5 ++- src/utils/index.ts | 1 + src/utils/semver.ts | 62 ++++++++++++++++++++++++++ test/utils/semver.test.ts | 39 ++++++++++++++++ 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 src/utils/semver.ts create mode 100644 test/utils/semver.test.ts diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 3e87ddd26..4047d8218 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -16,6 +16,7 @@ import NetworkKeystoreProvider from './NetworkKeystoreProvider' import { PrivateKeyBundleV1 } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' import type { XmtpEnv } from '../../Client' +import { semverGreaterThan } from '../../utils/semver' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus } = keystore export const SNAP_LOCAL_ORIGIN = 'local:http://localhost:8080' @@ -53,7 +54,7 @@ export default class SnapKeystoreProvider implements KeystoreProvider { const walletAddress = await wallet.getAddress() const env = opts.env const hasSnap = await getSnap(this.snapId, this.snapVersion) - if (!hasSnap) { + if (!hasSnap || semverGreaterThan(this.snapVersion, hasSnap.version)) { await connectSnap( this.snapId, this.snapVersion ? { version: this.snapVersion } : {} diff --git a/src/keystore/snapHelpers.ts b/src/keystore/snapHelpers.ts index 021592a0e..56098bfa4 100644 --- a/src/keystore/snapHelpers.ts +++ b/src/keystore/snapHelpers.ts @@ -5,6 +5,7 @@ import { KeystoreError } from './errors' import { PrivateKeyBundleV1 } from '../crypto' import { getEthereum } from '../utils/ethereum' import type { XmtpEnv } from '../Client' +import { isSameMajorVersion } from '../utils/semver' const { GetKeystoreStatusResponse_KeystoreStatus: KeystoreStatus, InitKeystoreRequest, @@ -156,7 +157,9 @@ export async function getSnap( const snaps = await getSnaps() return Object.values(snaps).find( - (snap) => snap.id === snapId && (!version || snap.version === version) + (snap) => + snap.id === snapId && + (!version || isSameMajorVersion(snap.version, version)) ) } catch (e) { console.warn('Failed to obtain installed snap', e) diff --git a/src/utils/index.ts b/src/utils/index.ts index 0656bd9fd..e666bb039 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,4 @@ export * from './async' export * from './date' export * from './bytes' export * from './browser' +export * from './semver' diff --git a/src/utils/semver.ts b/src/utils/semver.ts new file mode 100644 index 000000000..2f24d2e9a --- /dev/null +++ b/src/utils/semver.ts @@ -0,0 +1,62 @@ +export function semverParse(version: string) { + const [major, minor, ...patch] = version.split('.') + + return { + major: Number(major), + minor: Number(minor), + // Keep patch as a string so that it can support prerelease versions + patch: patch.join('.'), + } +} + +export function isSameMajorVersion(a?: string, b?: string): boolean { + // If no version is provided, assume it is the same + if (!a || !b) { + return true + } + return semverParse(a).major === semverParse(b).major +} + +// Checks if A semver is greater than B semver +export function semverGreaterThan(a?: string, b?: string): boolean { + if (!a || !b) { + return false + } + const aSemver = semverParse(a) + const bSemver = semverParse(b) + if (aSemver.major !== bSemver.major) { + return aSemver.major > bSemver.major + } + if (aSemver.minor !== bSemver.minor) { + return aSemver.minor > bSemver.minor + } + + if (!aSemver.patch || !bSemver.patch) { + return false + } + + return patchGreaterThan(aSemver.patch, bSemver.patch) +} + +// Home-brewed attempt at comparing patch versions so we don't have to import semver package. +// Example full version might be "2.0.1-alpha.1", and this will be operating on the "1-alpha.1" portion +function patchGreaterThan(a: string, b: string): boolean { + const [aVersion, aExtra] = a.split('-') + const [bVersion, bExtra] = b.split('-') + + if (Number(aVersion) !== Number(bVersion)) { + return Number(aVersion) > Number(bVersion) + } + + if (!aExtra || !bExtra) { + return false + } + + const [aTag, aTagVersion] = aExtra.split('.') + const [bTag, bTagVersion] = bExtra.split('.') + if (aTag !== bTag) { + return true + } + + return Number(aTagVersion) > Number(bTagVersion) +} diff --git a/test/utils/semver.test.ts b/test/utils/semver.test.ts new file mode 100644 index 000000000..9ae823ed7 --- /dev/null +++ b/test/utils/semver.test.ts @@ -0,0 +1,39 @@ +import { isSameMajorVersion, semverGreaterThan } from '../../src/utils/semver' + +describe('semver', () => { + describe('isSameMajorVersion', () => { + it('can parse major versions correctly', () => { + expect(isSameMajorVersion('1.0.0', '1.1.0')).toBe(true) + expect(isSameMajorVersion('1.0.0', '2.0.0')).toBe(false) + expect(isSameMajorVersion('1.1.0-beta.1', '1.1.0')).toBe(true) + expect(isSameMajorVersion('2.0.0', '1.5.0')).toBe(false) + }) + + it('handles undefined versions', () => { + expect(isSameMajorVersion(undefined, '1.0.0')).toBe(true) + expect(isSameMajorVersion('1.0.0', undefined)).toBe(true) + expect(isSameMajorVersion(undefined, undefined)).toBe(true) + }) + }) + + describe('semverGreaterThan', () => { + it('can compare major and minor versions', () => { + expect(semverGreaterThan('1.0.0', '1.1.0')).toBe(false) + expect(semverGreaterThan('1.0.0', '2.0.0')).toBe(false) + expect(semverGreaterThan('1.10.0', '1.2.0')).toBe(true) + expect(semverGreaterThan('2.0.0', '1.0.0')).toBe(true) + expect(semverGreaterThan('10.0.0', '2.0.0')).toBe(true) + }) + + it('can compare patch versions', () => { + expect(semverGreaterThan('1.0.0', '1.0.1')).toBe(false) + expect(semverGreaterThan('1.0.5', '1.0.1')).toBe(true) + expect(semverGreaterThan('1.0.0', '1.0.0-beta.1')).toBe(false) + expect(semverGreaterThan('1.0.0-beta.1', '1.0.0')).toBe(false) + expect(semverGreaterThan('1.1.1-beta.2', '1.1.1-beta.1')).toBe(true) + expect(semverGreaterThan('1.1.1-beta.1', '1.1.1-beta.1')).toBe(false) + // Handles versions > 10 + expect(semverGreaterThan('1.1.1-beta.10', '1.1.1-beta.2')).toBe(true) + }) + }) +}) From 6e1f7a4e96d6947a5df5184f63d0ec8826d66e26 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Fri, 8 Sep 2023 13:23:35 -0700 Subject: [PATCH 116/137] fix: add canGetKeys method --- package-lock.json | 11209 ++++++++++++++--------- package.json | 7 +- src/Client.ts | 33 + src/keystore/providers/SnapProvider.ts | 26 +- src/snapInfo.json | 4 + test/Client.test.ts | 31 + 6 files changed, 6812 insertions(+), 4498 deletions(-) create mode 100644 src/snapInfo.json diff --git a/package-lock.json b/package-lock.json index 548dbaf74..7e9ee7ac0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,12 +41,12 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-promise": "^6.0.1", "husky": "^7.0.4", - "jest": "^28.1.3", + "jest": "^29.6.0", "jest-environment-jsdom": "^28.1.3", "prettier": "^2.4.0", "rimraf": "^5.0.0", "semantic-release": "^21.0.3", - "ts-jest": "^28.0.0", + "ts-jest": "^29.1.1", "ts-node": "^10.9.1", "tsup": "^6.7.0", "typedoc": "^0.22.11", @@ -295,9 +295,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -525,6 +525,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -627,6 +642,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -1925,190 +1954,140 @@ } }, "node_modules/@jest/console": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", - "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz", + "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", + "jest-message-util": "^29.6.3", + "jest-util": "^29.6.3", "slash": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/core": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", - "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "node_modules/@jest/console/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/reporters": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.1.3", - "jest-config": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-resolve-dependencies": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "jest-watcher": "^28.1.3", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/core/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "node_modules/@jest/console/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true }, - "node_modules/@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", - "dev": true, - "dependencies": { - "expect": "^28.1.3", - "jest-snapshot": "^28.1.3" + "node": ">=10" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, "dependencies": { - "jest-get-type": "^28.0.2" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.6.3", "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", - "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "node_modules/@jest/console/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/types": "^28.1.3" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", - "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "node_modules/@jest/core": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz", + "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==", "dev": true, "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", + "@jest/console": "^29.6.4", + "@jest/reporters": "^29.6.4", + "@jest/test-result": "^29.6.4", + "@jest/transform": "^29.6.4", + "@jest/types": "^29.6.3", "@types/node": "*", + "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", + "ci-info": "^3.2.0", "exit": "^0.1.2", - "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-changed-files": "^29.6.3", + "jest-config": "^29.6.4", + "jest-haste-map": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.6.4", + "jest-resolve-dependencies": "^29.6.4", + "jest-runner": "^29.6.4", + "jest-runtime": "^29.6.4", + "jest-snapshot": "^29.6.4", + "jest-util": "^29.6.3", + "jest-validate": "^29.6.3", + "jest-watcher": "^29.6.4", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.1" + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -2119,118 +2098,169 @@ } } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "node_modules/@jest/core/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/@jest/core/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "node_modules/@jest/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/core/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.24.1" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@jest/source-map": { - "version": "28.1.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", - "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.13", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", - "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "node_modules/@jest/core/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-sequencer": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", - "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "@jest/test-result": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "slash": "^3.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform": { + "node_modules/@jest/environment": { "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", - "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", + "@jest/fake-timers": "^28.1.3", "@jest/types": "^28.1.3", - "@jridgewell/trace-mapping": "^0.3.13", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "@types/node": "*", + "jest-mock": "^28.1.3" }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jest/types": { + "node_modules/@jest/environment/node_modules/@jest/types": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", @@ -2247,1807 +2277,3626 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "node_modules/@jest/expect": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz", + "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "expect": "^29.6.4", + "jest-snapshot": "^29.6.4" }, "engines": { - "node": ">=6.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", "dev": true, - "engines": { - "node": ">=6.0.0" + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz", + "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==", "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, "engines": { - "node": ">=6.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "node_modules/@jest/expect/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "node_modules/@jest/expect/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, - "node_modules/@metamask/object-multiplex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz", - "integrity": "sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==", + "node_modules/@jest/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "end-of-stream": "^1.4.4", - "once": "^1.4.0", - "readable-stream": "^2.3.3" - }, "engines": { - "node": ">=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/@jest/expect/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@metamask/object-multiplex/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz", + "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "@jest/expect-utils": "^29.6.4", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-util": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@metamask/providers": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.1.tgz", - "integrity": "sha512-zvsa7wRO6E1vQOb6CvRlpcWwS1LQEIV7cPEcXGZEsy3wFwRjvLDTT4vDy2FzSSHyspJZsOls+WGkFXPl+0bL/g==", + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", + "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", "dev": true, "dependencies": { - "@metamask/object-multiplex": "^1.1.0", - "@metamask/safe-event-emitter": "^3.0.0", - "detect-browser": "^5.2.0", - "eth-rpc-errors": "^4.0.2", - "extension-port-stream": "^2.0.1", - "fast-deep-equal": "^3.1.3", - "is-stream": "^2.0.0", - "json-rpc-engine": "^6.1.0", - "json-rpc-middleware-stream": "^4.2.1", - "pump": "^3.0.0", - "webextension-polyfill": "^0.10.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">=16.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@metamask/safe-event-emitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz", - "integrity": "sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ==", + "node_modules/@jest/expect/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "engines": { - "node": ">=12.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@noble/secp256k1": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.5.2.tgz", - "integrity": "sha512-5mzA40W2q55VCRuC9XzmkiEnODdY0c5a7qsK2QcOfI5/MuVQyBaWGQyE6YOEF7kDwp+tDVWGsCDVJUME+wsWWw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", + "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "chalk": "^4.0.0", + "jest-diff": "^29.6.4", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@jest/expect/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">= 8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/auth-token": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", - "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", + "node_modules/@jest/expect/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">= 14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", - "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", + "node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", "dev": true, "dependencies": { - "@octokit/auth-token": "^3.0.0", - "@octokit/graphql": "^5.0.0", - "@octokit/request": "^6.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": ">= 14" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@octokit/endpoint": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", - "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", + "node_modules/@jest/fake-timers/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "universal-user-agent": "^6.0.0" + "@jest/schemas": "^28.1.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" }, "engines": { - "node": ">= 14" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@octokit/graphql": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", - "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", + "node_modules/@jest/globals": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz", + "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==", "dev": true, "dependencies": { - "@octokit/request": "^6.0.0", - "@octokit/types": "^9.0.0", - "universal-user-agent": "^6.0.0" + "@jest/environment": "^29.6.4", + "@jest/expect": "^29.6.4", + "@jest/types": "^29.6.3", + "jest-mock": "^29.6.3" }, "engines": { - "node": ">= 14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/openapi-types": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", - "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", - "dev": true - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-7.0.0.tgz", - "integrity": "sha512-NNm6DlYBEyKs9OZvy2Ax9YKn7e0/G7js+/I80icBTHUf6kB/nfaZkdXOF1Z32OaB+LDH6GIYpdYC3Bm3vwX5Ow==", + "node_modules/@jest/globals/node_modules/@jest/environment": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", + "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", "dev": true, "dependencies": { - "@octokit/tsconfig": "^1.0.2", - "@octokit/types": "^9.2.3" + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3" }, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/plugin-retry": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-5.0.2.tgz", - "integrity": "sha512-/Z7rWLCfjwmaVdyFuMkZoAnhfrvYgtvDrbO2d6lv7XrvJa8gFGB5tLUMngfuyMBfDCc5B9+EVu7IkQx5ebVlMg==", + "node_modules/@jest/globals/node_modules/@jest/fake-timers": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", + "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", - "bottleneck": "^2.15.3" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/plugin-throttling": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-6.0.1.tgz", - "integrity": "sha512-C5h2lT+LEF4SqmbB1RbMn1PhBlHKkZoqMGS39woJr0XJ+getmOcUvrytTtS4NOn1zh/iT1ByRWYwwmFYznv83w==", + "node_modules/@jest/globals/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", - "bottleneck": "^2.15.3" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^4.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@octokit/request": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", - "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", + "node_modules/@jest/globals/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@jest/globals/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { - "@octokit/endpoint": "^7.0.0", - "@octokit/request-error": "^3.0.0", - "@octokit/types": "^9.0.0", - "is-plain-object": "^5.0.0", - "node-fetch": "^2.6.7", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 14" + "type-detect": "4.0.8" } }, - "node_modules/@octokit/request-error": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", - "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "node_modules/@jest/globals/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "dependencies": { - "@octokit/types": "^9.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 14" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@octokit/tsconfig": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", - "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", - "dev": true - }, - "node_modules/@octokit/types": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.3.tgz", - "integrity": "sha512-MMeLdHyFIALioycq+LFcA71v0S2xpQUX2cw6pPbHQjaibcHYwLnmK/kMZaWuGfGfjBJZ3wRUq+dOaWsvrPJVvA==", + "node_modules/@jest/globals/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@octokit/openapi-types": "^17.2.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@opentelemetry/api": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.1.0.tgz", - "integrity": "sha512-hf+3bwuBwtXsugA2ULBc95qxrOqP2pOekLz34BJhcAKawt94vfeNyUKpYc0lZQ/3sCP6LqRa7UAdHA7i5UODzQ==", + "node_modules/@jest/globals/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": ">=8.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@opentelemetry/core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.3.1.tgz", - "integrity": "sha512-k7lOC86N7WIyUZsUuSKZfFIrUtINtlauMGQsC1r7jNmcr0vVJGqK1ROBvt7WWMxLbpMnt1q2pXJO8tKu0b9auA==", + "node_modules/@jest/globals/node_modules/jest-mock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", + "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", "dev": true, "dependencies": { - "@opentelemetry/semantic-conventions": "1.3.1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.6.3" }, "engines": { - "node": ">=8.12.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.2.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.1.tgz", - "integrity": "sha512-wU5J8rUoo32oSef/rFpOT1HIjLjAv3qIDHkw1QIhODV3OpAVHi5oVzlouozg9obUmZKtbZ0qUe/m7FP0y0yBzA==", + "node_modules/@jest/globals/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, "engines": { - "node": ">=8.12.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@jest/globals/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, - "optional": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">=14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@pnpm/config.env-replace": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", - "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "node_modules/@jest/reporters": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz", + "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==", "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.6.4", + "@jest/test-result": "^29.6.4", + "@jest/transform": "^29.6.4", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, "engines": { - "node": ">=12.22.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", - "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "node_modules/@jest/reporters/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "graceful-fs": "4.2.10" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=12.22.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/@pnpm/npm-conf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.0.tgz", - "integrity": "sha512-roLI1ul/GwzwcfcVpZYPdrgW2W/drLriObl1h+yLF5syc8/5ULWw2ALbCHUWF+4YltIqA3xFSbG4IwyJz37e9g==", + "node_modules/@jest/reporters/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", "dev": true, "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">=12" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + "node_modules/@jest/reporters/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + "node_modules/@jest/reporters/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, - "node_modules/@semantic-release/commit-analyzer": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-10.0.1.tgz", - "integrity": "sha512-9ejHzTAijYs9z246sY/dKBatmOPcd0GQ7lH4MgLCkv1q4GCiDZRkjHJkaQZXZVaK7mJybS+sH3Ng6G8i3pYMGQ==", + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", + "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", "dev": true, "dependencies": { - "conventional-changelog-angular": "^6.0.0", - "conventional-commits-filter": "^3.0.0", - "conventional-commits-parser": "^4.0.0", - "debug": "^4.0.0", - "import-from": "^4.0.0", - "lodash-es": "^4.17.21", - "micromatch": "^4.0.2" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" + "node": ">=10" } }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", - "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "node_modules/@jest/reporters/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, "dependencies": { - "compare-func": "^2.0.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.3.5", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "conventional-commits-parser": "cli.js" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", - "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "node_modules/@jest/reporters/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "engines": { - "node": ">=14.17" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/github": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.0.3.tgz", - "integrity": "sha512-X6gq4USKVlCxPwIIyXb99jU7gwVWlnsKOevs+OyABRdoqc+OIRITbFmrrYU3eE1vGMGk+Qu/GAoLUQQQwC3YOA==", + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@octokit/core": "^4.2.1", - "@octokit/plugin-paginate-rest": "^7.0.0", - "@octokit/plugin-retry": "^5.0.0", - "@octokit/plugin-throttling": "^6.0.0", - "@semantic-release/error": "^4.0.0", - "aggregate-error": "^4.0.1", - "debug": "^4.3.4", - "dir-glob": "^3.0.1", - "globby": "^13.1.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "issue-parser": "^6.0.0", - "lodash-es": "^4.17.21", - "mime": "^3.0.0", - "p-filter": "^3.0.0", - "url-join": "^5.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", - "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "node_modules/@jest/reporters/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">=18" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/github/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "node_modules/@jest/reporters/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "debug": "^4.3.4" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 14" + "node": ">=10" } }, - "node_modules/@semantic-release/github/node_modules/globby": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", "dev": true, "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" + "@sinclair/typebox": "^0.24.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/@semantic-release/github/node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" }, "engines": { - "node": ">= 14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/github/node_modules/https-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", - "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "node_modules/@jest/test-result": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz", + "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "@jest/console": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": ">= 14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/github/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/@jest/test-sequencer": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz", + "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "@jest/test-result": "^29.6.4", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "slash": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/npm": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-10.0.3.tgz", - "integrity": "sha512-Chbv3kX4o+y+r1X6hsqBVB8NFbSVfiNlYOqMG6o9Wc8r5Y4cjxfbaMCuJ++XAtw3YXYX/NVD05cPzBi4Orjusg==", + "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^4.0.1", - "execa": "^7.0.0", - "fs-extra": "^11.0.0", - "lodash-es": "^4.17.21", - "nerf-dart": "^1.0.0", - "normalize-url": "^8.0.0", - "npm": "^9.5.0", - "rc": "^1.2.8", - "read-pkg": "^8.0.0", - "registry-auth-token": "^5.0.0", - "semver": "^7.1.2", - "tempy": "^3.0.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=18" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "peerDependencies": { - "semantic-release": ">=20.1.0" + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/@semantic-release/npm/node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "node_modules/@jest/test-sequencer/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "node_modules/@jest/test-sequencer/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=14.14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "dependencies": { - "lru-cache": "^7.5.1" + "@jest/schemas": "^29.6.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" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "node_modules/@jest/types/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, "engines": { - "node": ">=14.18.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/@jest/types/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true }, - "node_modules/@semantic-release/npm/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/lines-and-columns": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", - "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=6.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { - "node": ">=12" + "node": ">=6.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true }, - "node_modules/@semantic-release/npm/node_modules/normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@semantic-release/npm/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@metamask/object-multiplex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz", + "integrity": "sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ==", "dev": true, "dependencies": { - "path-key": "^4.0.0" + "end-of-stream": "^1.4.4", + "once": "^1.4.0", + "readable-stream": "^2.3.3" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "node_modules/@metamask/object-multiplex/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/@semantic-release/npm/node_modules/parse-json": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.0.0.tgz", - "integrity": "sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==", + "node_modules/@metamask/object-multiplex/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.21.4", - "error-ex": "^1.3.2", - "json-parse-even-better-errors": "^3.0.0", - "lines-and-columns": "^2.0.3", - "type-fest": "^3.8.0" + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@metamask/providers": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-11.1.1.tgz", + "integrity": "sha512-zvsa7wRO6E1vQOb6CvRlpcWwS1LQEIV7cPEcXGZEsy3wFwRjvLDTT4vDy2FzSSHyspJZsOls+WGkFXPl+0bL/g==", + "dev": true, + "dependencies": { + "@metamask/object-multiplex": "^1.1.0", + "@metamask/safe-event-emitter": "^3.0.0", + "detect-browser": "^5.2.0", + "eth-rpc-errors": "^4.0.2", + "extension-port-stream": "^2.0.1", + "fast-deep-equal": "^3.1.3", + "is-stream": "^2.0.0", + "json-rpc-engine": "^6.1.0", + "json-rpc-middleware-stream": "^4.2.1", + "pump": "^3.0.0", + "webextension-polyfill": "^0.10.0" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=16.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/@metamask/safe-event-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.0.0.tgz", + "integrity": "sha512-j6Z47VOmVyGMlnKXZmL0fyvWfEYtKWCA9yGZkU3FCsGZUT5lHGmvaV9JA5F2Y+010y7+ROtR3WMXIkvl/nVzqQ==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12.0.0" } }, - "node_modules/@semantic-release/npm/node_modules/read-pkg": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.0.0.tgz", - "integrity": "sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==", + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^5.0.0", - "parse-json": "^7.0.0", - "type-fest": "^3.8.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 8" } }, - "node_modules/@semantic-release/npm/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 8" } }, - "node_modules/@semantic-release/npm/node_modules/type-fest": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.11.1.tgz", - "integrity": "sha512-aCuRNRERRVh33lgQaJRlUxZqzfhzwTrsE98Mc3o3VXqmiaQdHacgUtJ0esp+7MvZ92qhtzKPeusaX6vIEcoreA==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "engines": { - "node": ">=14.16" + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 8" } }, - "node_modules/@semantic-release/release-notes-generator": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-11.0.3.tgz", - "integrity": "sha512-NU77dWKQf+QcZrv/Hcp3DPeSxglPu8hYKCipGxAPpeaneLkg6S0zfTVug4tg4mfDhZHC6RtoI7ljQDK8VoJ2Dw==", + "node_modules/@octokit/auth-token": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", "dev": true, - "dependencies": { - "conventional-changelog-angular": "^6.0.0", - "conventional-changelog-writer": "^6.0.0", - "conventional-commits-filter": "^3.0.0", - "conventional-commits-parser": "^4.0.0", - "debug": "^4.0.0", - "get-stream": "^7.0.0", - "import-from": "^4.0.0", - "into-stream": "^7.0.0", - "lodash-es": "^4.17.21", - "read-pkg-up": "^9.0.0" - }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "semantic-release": ">=20.1.0" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", - "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "node_modules/@octokit/core": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz", + "integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==", "dev": true, "dependencies": { - "compare-func": "^2.0.0" + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">=14" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", - "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "node_modules/@octokit/endpoint": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.5.tgz", + "integrity": "sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==", "dev": true, "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.3.5", - "meow": "^8.1.2", - "split2": "^3.2.2" - }, - "bin": { - "conventional-commits-parser": "cli.js" + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": ">=14" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "node_modules/@octokit/graphql": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", "dev": true, "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "node_modules/@octokit/openapi-types": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-17.2.0.tgz", + "integrity": "sha512-MazrFNx4plbLsGl+LFesMo96eIXkFgEtaKbnNpdh4aQ0VM10aoylFsTYP1AEjkeoRNZiiPe3T6Gl2Hr8dJWdlQ==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.0.tgz", - "integrity": "sha512-ql6FW5b8tgMYvI4UaoxG3EQN3VyZ6VeQpxNBGg5BZ4xD4u+HJeprzhMMA4OCBEGQgSR+m87pstWMpiVW64W8Fw==", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-7.0.0.tgz", + "integrity": "sha512-NNm6DlYBEyKs9OZvy2Ax9YKn7e0/G7js+/I80icBTHUf6kB/nfaZkdXOF1Z32OaB+LDH6GIYpdYC3Bm3vwX5Ow==", "dev": true, + "dependencies": { + "@octokit/tsconfig": "^1.0.2", + "@octokit/types": "^9.2.3" + }, "engines": { - "node": ">=16" + "node": ">= 18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@octokit/core": ">=4" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "node_modules/@octokit/plugin-retry": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-5.0.2.tgz", + "integrity": "sha512-/Z7rWLCfjwmaVdyFuMkZoAnhfrvYgtvDrbO2d6lv7XrvJa8gFGB5tLUMngfuyMBfDCc5B9+EVu7IkQx5ebVlMg==", "dev": true, "dependencies": { - "p-locate": "^6.0.0" + "@octokit/types": "^9.0.0", + "bottleneck": "^2.15.3" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@octokit/core": ">=3" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/@octokit/plugin-throttling": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-6.0.1.tgz", + "integrity": "sha512-C5h2lT+LEF4SqmbB1RbMn1PhBlHKkZoqMGS39woJr0XJ+getmOcUvrytTtS4NOn1zh/iT1ByRWYwwmFYznv83w==", "dev": true, "dependencies": { - "yocto-queue": "^1.0.0" + "@octokit/types": "^9.0.0", + "bottleneck": "^2.15.3" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@octokit/core": "^4.0.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "node_modules/@octokit/request": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.5.tgz", + "integrity": "sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==", "dev": true, "dependencies": { - "p-limit": "^4.0.0" + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "node_modules/@octokit/request-error": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", "dev": true, + "dependencies": { + "@octokit/types": "^9.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 14" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", - "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", + "node_modules/@octokit/tsconfig": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", + "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", + "dev": true + }, + "node_modules/@octokit/types": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.2.3.tgz", + "integrity": "sha512-MMeLdHyFIALioycq+LFcA71v0S2xpQUX2cw6pPbHQjaibcHYwLnmK/kMZaWuGfGfjBJZ3wRUq+dOaWsvrPJVvA==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^2.0.0" - }, + "@octokit/openapi-types": "^17.2.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.1.0.tgz", + "integrity": "sha512-hf+3bwuBwtXsugA2ULBc95qxrOqP2pOekLz34BJhcAKawt94vfeNyUKpYc0lZQ/3sCP6LqRa7UAdHA7i5UODzQ==", + "dev": true, "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.0.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg-up": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", - "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", + "node_modules/@opentelemetry/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.3.1.tgz", + "integrity": "sha512-k7lOC86N7WIyUZsUuSKZfFIrUtINtlauMGQsC1r7jNmcr0vVJGqK1ROBvt7WWMxLbpMnt1q2pXJO8tKu0b9auA==", "dev": true, "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^7.1.0", - "type-fest": "^2.5.0" + "@opentelemetry/semantic-conventions": "1.3.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8.12.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.2.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.1.tgz", + "integrity": "sha512-wU5J8rUoo32oSef/rFpOT1HIjLjAv3qIDHkw1QIhODV3OpAVHi5oVzlouozg9obUmZKtbZ0qUe/m7FP0y0yBzA==", "dev": true, "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8.12.0" } }, - "node_modules/@semantic-release/release-notes-generator/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "optional": true, "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14" } }, - "node_modules/@sinclair/typebox": { - "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", "dev": true, - "dependencies": { - "type-detect": "4.0.8" + "engines": { + "node": ">=12.22.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.0.tgz", + "integrity": "sha512-roLI1ul/GwzwcfcVpZYPdrgW2W/drLriObl1h+yLF5syc8/5ULWw2ALbCHUWF+4YltIqA3xFSbG4IwyJz37e9g==", "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, "engines": { - "node": ">= 10" + "node": ">=12" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-10.0.1.tgz", + "integrity": "sha512-9ejHzTAijYs9z246sY/dKBatmOPcd0GQ7lH4MgLCkv1q4GCiDZRkjHJkaQZXZVaK7mJybS+sH3Ng6G8i3pYMGQ==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^6.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "debug": "^4.0.0", + "import-from": "^4.0.0", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-changelog-angular": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", + "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/commit-analyzer/node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/github": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.0.3.tgz", + "integrity": "sha512-X6gq4USKVlCxPwIIyXb99jU7gwVWlnsKOevs+OyABRdoqc+OIRITbFmrrYU3eE1vGMGk+Qu/GAoLUQQQwC3YOA==", + "dev": true, + "dependencies": { + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^7.0.0", + "@octokit/plugin-retry": "^5.0.0", + "@octokit/plugin-throttling": "^6.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^4.0.1", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^13.1.4", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^6.0.0", + "lodash-es": "^4.17.21", + "mime": "^3.0.0", + "p-filter": "^3.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@semantic-release/github/node_modules/globby": { + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", + "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@semantic-release/github/node_modules/https-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.0.tgz", + "integrity": "sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@semantic-release/github/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-10.0.3.tgz", + "integrity": "sha512-Chbv3kX4o+y+r1X6hsqBVB8NFbSVfiNlYOqMG6o9Wc8r5Y4cjxfbaMCuJ++XAtw3YXYX/NVD05cPzBi4Orjusg==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^4.0.1", + "execa": "^7.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^9.5.0", + "rc": "^1.2.8", + "read-pkg": "^8.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/npm/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@semantic-release/npm/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@semantic-release/npm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/parse-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.0.0.tgz", + "integrity": "sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/read-pkg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.0.0.tgz", + "integrity": "sha512-Ajb9oSjxXBw0YyOiwtQ2dKbAA/vMnUPnY63XcCk+mXo0BwIdQEMgZLZiMWGttQHcUhUgbK0mH85ethMPKXxziw==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^5.0.0", + "parse-json": "^7.0.0", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/type-fest": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.11.1.tgz", + "integrity": "sha512-aCuRNRERRVh33lgQaJRlUxZqzfhzwTrsE98Mc3o3VXqmiaQdHacgUtJ0esp+7MvZ92qhtzKPeusaX6vIEcoreA==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-11.0.3.tgz", + "integrity": "sha512-NU77dWKQf+QcZrv/Hcp3DPeSxglPu8hYKCipGxAPpeaneLkg6S0zfTVug4tg4mfDhZHC6RtoI7ljQDK8VoJ2Dw==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^6.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from": "^4.0.0", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-pkg-up": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-changelog-angular": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", + "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.3.5", + "meow": "^8.1.2", + "split2": "^3.2.2" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.0.tgz", + "integrity": "sha512-ql6FW5b8tgMYvI4UaoxG3EQN3VyZ6VeQpxNBGg5BZ4xD4u+HJeprzhMMA4OCBEGQgSR+m87pstWMpiVW64W8Fw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", + "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/read-pkg-up": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", + "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^7.1.0", + "type-fest": "^2.5.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/benchmark": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-2.1.2.tgz", + "integrity": "sha512-EDKtLYNMKrig22jEvhXq8TBFyFgVNSPmDF2b9UzJ7+eylPqdZVo17PCUMkn1jP6/1A/0u78VqYC6VrX6b8pDWA==", + "dev": true + }, + "node_modules/@types/bl": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bl/-/bl-5.0.2.tgz", + "integrity": "sha512-V4g3uJIfBHeDd/35QTPOujJ4+viJJVtNwC2LmBUZeXGSGL60R5iTsBEZ9Nh+wP3asMOA/LEFHxmKT6JzK+Vd0A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/readable-stream": "*" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/callback-to-async-iterator": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/callback-to-async-iterator/-/callback-to-async-iterator-1.1.4.tgz", + "integrity": "sha512-NVyiWSufzQNxYUsDQGcAEL8z83Z2NPvWoDHv3KqapWovxIxxmNq5/UTg2QWNtPSojoTevbilAO5rEFExStWVfQ==", + "dev": true + }, + "node_modules/@types/elliptic": { + "version": "6.4.14", + "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.14.tgz", + "integrity": "sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "28.1.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", + "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", + "dev": true, + "dependencies": { + "expect": "^28.0.0", + "pretty-format": "^28.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "16.2.15", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.15.tgz", + "integrity": "sha512-nwF87yjBKuX/roqGYerZZM0Nv1pZDMAT5YhOHYeM/72Fic+VEqJh4nyoqoapzJnW3pUlfxPY5FhgsJtM+dRnQQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/parse5": "^6.0.3", + "@types/tough-cookie": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/parse5": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", + "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", + "dev": true + }, + "node_modules/@types/readable-stream": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.13.tgz", + "integrity": "sha512-4JSCx8EUzaW9Idevt+9lsRAt1lcSccoQfE+AouM1gk8sFxnnytKNIO3wTl9Dy+4m6jRJ1yXhboLHHT/LXBQiEw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "safe-buffer": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", + "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz", + "integrity": "sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.38.0", + "@typescript-eslint/type-utils": "5.38.0", + "@typescript-eslint/utils": "5.38.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz", + "integrity": "sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.38.0", + "@typescript-eslint/types": "5.38.0", + "@typescript-eslint/typescript-estree": "5.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz", + "integrity": "sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.38.0", + "@typescript-eslint/visitor-keys": "5.38.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz", + "integrity": "sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.38.0", + "@typescript-eslint/utils": "5.38.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.38.0.tgz", + "integrity": "sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz", + "integrity": "sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.38.0", + "@typescript-eslint/visitor-keys": "5.38.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz", + "integrity": "sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.38.0", + "@typescript-eslint/types": "5.38.0", + "@typescript-eslint/typescript-estree": "5.38.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz", + "integrity": "sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.38.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@xmtp/proto": { + "version": "3.28.0-beta.1", + "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.28.0-beta.1.tgz", + "integrity": "sha512-gbDQ1FXKZe0j9RZxBK0Ohyy8C4z5I+ko58xmHk+QGO4QYb+cGsJyDSe0Re3oUa1tlnNudV0fkTR4nxcq4D+oIw==", + "dependencies": { + "long": "^5.2.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.8.0", + "undici": "^5.8.1" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", + "dev": true + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-mutex": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.0.tgz", + "integrity": "sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/async-mutex/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true + }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "node_modules/benny": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/benny/-/benny-3.7.1.tgz", + "integrity": "sha512-USzYxODdVfOS7JuQq/L0naxB788dWCiUgUTxvN+WLPt/JfcDURNNj8kN/N+uK6PDvuR67/9/55cVKGPleFQINA==", + "dev": true, + "dependencies": { + "@arrows/composition": "^1.0.0", + "@arrows/dispatch": "^1.0.2", + "@arrows/multimethod": "^1.1.6", + "benchmark": "^2.1.4", + "common-tags": "^1.8.0", + "fs-extra": "^10.0.0", + "json2csv": "^5.0.6", + "kleur": "^4.1.4", + "log-update": "^4.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/benny/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "peer": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "node_modules/caniuse-lite": { + "version": "1.0.30001477", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001477.tgz", + "integrity": "sha512-lZim4iUHhGcy5p+Ri/G7m84hJwncj+Kz7S5aD4hoQfslKZJgt0tHc/hafVbqHC5bbhHb+mrW2JOUHkI5KH7toQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + }, + "bin": { + "cdl": "bin/cdl.js" } }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@babel/types": "^7.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@types/benchmark": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@types/benchmark/-/benchmark-2.1.2.tgz", - "integrity": "sha512-EDKtLYNMKrig22jEvhXq8TBFyFgVNSPmDF2b9UzJ7+eylPqdZVo17PCUMkn1jP6/1A/0u78VqYC6VrX6b8pDWA==", - "dev": true + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } }, - "node_modules/@types/bl": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/bl/-/bl-5.0.2.tgz", - "integrity": "sha512-V4g3uJIfBHeDd/35QTPOujJ4+viJJVtNwC2LmBUZeXGSGL60R5iTsBEZ9Nh+wP3asMOA/LEFHxmKT6JzK+Vd0A==", + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "@types/node": "*", - "@types/readable-stream": "*" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/@types/bn.js": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", - "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true, - "dependencies": { - "@types/node": "*" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" } }, - "node_modules/@types/callback-to-async-iterator": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/callback-to-async-iterator/-/callback-to-async-iterator-1.1.4.tgz", - "integrity": "sha512-NVyiWSufzQNxYUsDQGcAEL8z83Z2NPvWoDHv3KqapWovxIxxmNq5/UTg2QWNtPSojoTevbilAO5rEFExStWVfQ==", + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, - "node_modules/@types/elliptic": { - "version": "6.4.14", - "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.14.tgz", - "integrity": "sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==", + "node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", "dev": true, "dependencies": { - "@types/bn.js": "*" + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "node_modules/clean-stack/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, - "dependencies": { - "@types/node": "*" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "*" + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "node_modules/cli-table3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "dev": true, "dependencies": { - "@types/istanbul-lib-report": "*" + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "1.4.0" } }, - "node_modules/@types/jest": { - "version": "28.1.8", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-28.1.8.tgz", - "integrity": "sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "expect": "^28.0.0", - "pretty-format": "^28.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/@types/jsdom": { - "version": "16.2.15", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.15.tgz", - "integrity": "sha512-nwF87yjBKuX/roqGYerZZM0Nv1pZDMAT5YhOHYeM/72Fic+VEqJh4nyoqoapzJnW3pUlfxPY5FhgsJtM+dRnQQ==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "dependencies": { - "@types/node": "*", - "@types/parse5": "^6.0.3", - "@types/tough-cookie": "*" + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "node_modules/@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==", + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } }, - "node_modules/@types/readable-stream": { - "version": "2.3.13", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.13.tgz", - "integrity": "sha512-4JSCx8EUzaW9Idevt+9lsRAt1lcSccoQfE+AouM1gk8sFxnnytKNIO3wTl9Dy+4m6jRJ1yXhboLHHT/LXBQiEw==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "dependencies": { - "@types/node": "*", - "safe-buffer": "*" + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "node_modules/comment-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", + "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } }, - "node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz", - "integrity": "sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==", + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/type-utils": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", + "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz", - "integrity": "sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==", + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", + "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "debug": "^4.3.4" + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=10" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz", - "integrity": "sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==", + "node_modules/conventional-changelog-writer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.0.tgz", + "integrity": "sha512-8PyWTnn7zBIt9l4hj4UusFs1TyG+9Ulu1zlOAc72L7Sdv9Hsc8E86ot7htY3HXCVhXHB/NO0pVGvZpwsyJvFfw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0" + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^8.1.2", + "semver": "^6.3.0", + "split": "^1.0.1" }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "bin": { + "conventional-changelog-writer": "cli.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=14" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz", - "integrity": "sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==", + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-commits-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.38.0", - "@typescript-eslint/utils": "5.38.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=14" + } + }, + "node_modules/conventional-commits-parser": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", + "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "dev": true, + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" }, - "peerDependencies": { - "eslint": "*" + "bin": { + "conventional-commits-parser": "cli.js" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=10" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.38.0.tgz", - "integrity": "sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==", + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz", - "integrity": "sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==", + "node_modules/cosmiconfig-typescript-loader": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", + "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/visitor-keys": "5.38.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "cosmiconfig": "^7", + "ts-node": "^10.8.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=12", + "npm": ">=6" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=7", + "typescript": ">=3" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz", - "integrity": "sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==", + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.38.0", - "@typescript-eslint/types": "5.38.0", - "@typescript-eslint/typescript-estree": "5.38.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">= 8" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.38.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz", - "integrity": "sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==", + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.38.0", - "eslint-visitor-keys": "^3.3.0" + "type-fest": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@xmtp/proto": { - "version": "3.28.0-beta.1", - "resolved": "https://registry.npmjs.org/@xmtp/proto/-/proto-3.28.0-beta.1.tgz", - "integrity": "sha512-gbDQ1FXKZe0j9RZxBK0Ohyy8C4z5I+ko58xmHk+QGO4QYb+cGsJyDSe0Re3oUa1tlnNudV0fkTR4nxcq4D+oIw==", - "dependencies": { - "long": "^5.2.0", - "protobufjs": "^7.0.0", - "rxjs": "^7.8.0", - "undici": "^5.8.1" - } + "node_modules/crypto-randomuuid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz", + "integrity": "sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==", + "dev": true }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "cssom": "~0.3.6" }, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" + "node": ">=8" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=12" } }, - "node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true, - "dependencies": { - "debug": "4" - }, "engines": { - "node": ">= 6.0.0" + "node": "*" } }, - "node_modules/aggregate-error": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", - "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "node_modules/dd-trace": { + "version": "2.45.1", + "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-2.45.1.tgz", + "integrity": "sha512-FZu1kvYRFwqR1LHR3iBlSU60R33rdWD+Wtd9yQG5VIlkbrNFTIB0IXSC4fjUusPmvkUUxo4nP0roQBwyxHdnZA==", "dev": true, + "hasInstallScript": true, "dependencies": { - "clean-stack": "^4.0.0", - "indent-string": "^5.0.0" + "@datadog/native-appsec": "^3.2.0", + "@datadog/native-iast-rewriter": "2.0.1", + "@datadog/native-iast-taint-tracking": "1.5.0", + "@datadog/native-metrics": "^1.6.0", + "@datadog/pprof": "3.1.0", + "@datadog/sketches-js": "^2.1.0", + "@opentelemetry/api": "^1.0.0", + "@opentelemetry/core": "<1.4.0", + "@types/node": "<18.13", + "crypto-randomuuid": "^1.0.0", + "diagnostics_channel": "^1.1.0", + "ignore": "^5.2.4", + "import-in-the-middle": "^1.4.2", + "int64-buffer": "^0.1.9", + "ipaddr.js": "^2.1.0", + "istanbul-lib-coverage": "3.2.0", + "koalas": "^1.0.2", + "limiter": "^1.1.4", + "lodash.kebabcase": "^4.1.1", + "lodash.pick": "^4.4.0", + "lodash.sortby": "^4.7.0", + "lodash.uniq": "^4.5.0", + "lru-cache": "^7.14.0", + "methods": "^1.1.2", + "module-details-from-path": "^1.0.3", + "msgpack-lite": "^0.1.26", + "node-abort-controller": "^3.1.1", + "opentracing": ">=0.12.1", + "path-to-regexp": "^0.1.2", + "protobufjs": "^7.2.4", + "retry": "^0.13.1", + "semver": "^7.5.4" }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/aggregate-error/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "node_modules/dd-trace/node_modules/@types/node": { + "version": "18.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz", + "integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==", + "dev": true + }, + "node_modules/dd-trace/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/dd-trace/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "lru-cache": "^6.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/dd-trace/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "type-fest": "^0.21.3" + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, + "dependencies": { + "ms": "2.1.2" + }, "engines": { - "node": ">=10" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" }, - "engines": { - "node": ">= 8" + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" + "engines": { + "node": ">=4.0.0" } }, - "node_modules/argv-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", - "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -4056,1124 +5905,1063 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "dev": true + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/async-mutex": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.0.tgz", - "integrity": "sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/async-mutex/node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", - "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "node_modules/diagnostics_channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/diagnostics_channel/-/diagnostics_channel-1.1.0.tgz", + "integrity": "sha512-OE1ngLDjSBPG6Tx0YATELzYzy3RKHC+7veQ8gLa8yS7AAgw65mFbVdcsu3501abqOZCEZqZyAIemB0zXlqDSuw==", "dev": true, - "dependencies": { - "@jest/transform": "^28.1.3", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.1.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "node": ">=4" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, "engines": { - "node": ">=8" + "node": ">=0.3.1" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", - "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "path-type": "^4.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/babel-preset-jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", - "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^28.1.3", - "babel-preset-current-node-syntax": "^1.0.0" + "esutils": "^2.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" - }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true - }, - "node_modules/benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.4", - "platform": "^1.3.3" + "node": ">=6.0.0" } }, - "node_modules/benny": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/benny/-/benny-3.7.1.tgz", - "integrity": "sha512-USzYxODdVfOS7JuQq/L0naxB788dWCiUgUTxvN+WLPt/JfcDURNNj8kN/N+uK6PDvuR67/9/55cVKGPleFQINA==", + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, "dependencies": { - "@arrows/composition": "^1.0.0", - "@arrows/dispatch": "^1.0.2", - "@arrows/multimethod": "^1.1.6", - "benchmark": "^2.1.4", - "common-tags": "^1.8.0", - "fs-extra": "^10.0.0", - "json2csv": "^5.0.6", - "kleur": "^4.1.4", - "log-update": "^4.0.0" + "webidl-conversions": "^7.0.0" }, "engines": { "node": ">=12" } }, - "node_modules/benny/node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "readable-stream": "^2.0.2" } }, - "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/bottleneck": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", - "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" + "safe-buffer": "~5.1.0" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "node_modules/electron-to-chromium": { + "version": "1.4.356", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", + "integrity": "sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==", "dev": true }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, "engines": { - "node": ">= 6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "dependencies": { - "node-int64": "^0.4.0" + "once": "^1.4.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "node_modules/env-ci": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-9.1.0.tgz", + "integrity": "sha512-ZCEas2sDVFR3gpumwwzSU4OJZwWJ46yqJH3TqH3vSxEBzeAlC0uCJLGAnZC0vX1TIXzHzjcwpKmUn2xw5mC/qA==", "dev": true, - "peer": true, "dependencies": { - "semver": "^7.0.0" + "execa": "^7.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^16.14 || >=18" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/env-ci/node_modules/execa": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, "dependencies": { - "streamsearch": "^1.1.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=10.16.0" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/env-ci/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=14.18.0" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/env-ci/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/env-ci/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/env-ci/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001477", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001477.tgz", - "integrity": "sha512-lZim4iUHhGcy5p+Ri/G7m84hJwncj+Kz7S5aD4hoQfslKZJgt0tHc/hafVbqHC5bbhHb+mrW2JOUHkI5KH7toQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "dependencies": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" + "engines": { + "node": ">=12" }, - "bin": { - "cdl": "bin/cdl.js" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "is-arrayish": "^0.2.1" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "node_modules/es-abstract": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", + "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.2", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" + "dependencies": { + "has": "^1.0.3" } }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/clean-stack": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", - "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "dependencies": { - "escape-string-regexp": "5.0.0" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/clean-stack/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "node_modules/esbuild": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.16.tgz", + "integrity": "sha512-aeSuUKr9aFVY9Dc8ETVELGgkj4urg5isYx8pLf4wlGgB0vTFjxJQdHnNH6Shmx4vYYrOTLCHtRI5i1XZ9l2Zcg==", "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=12" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@esbuild/android-arm": "0.17.16", + "@esbuild/android-arm64": "0.17.16", + "@esbuild/android-x64": "0.17.16", + "@esbuild/darwin-arm64": "0.17.16", + "@esbuild/darwin-x64": "0.17.16", + "@esbuild/freebsd-arm64": "0.17.16", + "@esbuild/freebsd-x64": "0.17.16", + "@esbuild/linux-arm": "0.17.16", + "@esbuild/linux-arm64": "0.17.16", + "@esbuild/linux-ia32": "0.17.16", + "@esbuild/linux-loong64": "0.17.16", + "@esbuild/linux-mips64el": "0.17.16", + "@esbuild/linux-ppc64": "0.17.16", + "@esbuild/linux-riscv64": "0.17.16", + "@esbuild/linux-s390x": "0.17.16", + "@esbuild/linux-x64": "0.17.16", + "@esbuild/netbsd-x64": "0.17.16", + "@esbuild/openbsd-x64": "0.17.16", + "@esbuild/sunos-x64": "0.17.16", + "@esbuild/win32-arm64": "0.17.16", + "@esbuild/win32-ia32": "0.17.16", + "@esbuild/win32-x64": "0.17.16" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/esbuild-plugin-external-global": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-external-global/-/esbuild-plugin-external-global-1.0.1.tgz", + "integrity": "sha512-NDzYHRoShpvLqNcrgV8ZQh61sMIFAry5KLTQV83BPG5iTXCCu7h72SCfJ97bW0GqtuqDD/1aqLbKinI/rNgUsg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, "engines": { - "node": "10.* || >= 12.*" + "node": ">=10" }, - "optionalDependencies": { - "colors": "1.4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=4.0" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/eslint": { + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", + "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@eslint/eslintrc": "^1.3.2", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@humanwhocodes/module-importer": "^1.0.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=7.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "node_modules/eslint-config-standard": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", + "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0" } }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "debug": "^3.2.7", + "resolve": "^1.20.0" } }, - "node_modules/comment-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.0.tgz", - "integrity": "sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "engines": { - "node": ">= 12.0.0" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, "engines": { - "node": ">=4.0.0" + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" + "ms": "^2.1.1" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", "dev": true, "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/conventional-changelog-angular": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz", - "integrity": "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==", + "node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "dependencies": { - "compare-func": "^2.0.0", - "q": "^1.5.1" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz", - "integrity": "sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==", + "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/conventional-changelog-writer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.0.tgz", - "integrity": "sha512-8PyWTnn7zBIt9l4hj4UusFs1TyG+9Ulu1zlOAc72L7Sdv9Hsc8E86ot7htY3HXCVhXHB/NO0pVGvZpwsyJvFfw==", + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "dependencies": { - "conventional-commits-filter": "^3.0.0", - "dateformat": "^3.0.3", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "meow": "^8.1.2", - "semver": "^6.3.0", - "split": "^1.0.1" - }, - "bin": { - "conventional-changelog-writer": "cli.js" + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { - "node": ">=14" - } - }, - "node_modules/conventional-changelog-writer/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, - "node_modules/conventional-commits-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", - "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.1" - }, - "engines": { - "node": ">=14" + "ms": "2.0.0" } }, - "node_modules/conventional-commits-parser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.js" + "esutils": "^2.0.2" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/eslint-plugin-jsdoc": { + "version": "37.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.9.1.tgz", + "integrity": "sha512-ynIsYL+rOtIKWOttAYWCgOJawPwYKexcX3cuoYHwifvz4+uY+MZ2un5nMHBULigdSITnQ5/ZSHpO/O1nwv/uJA==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "@es-joy/jsdoccomment": "~0.19.0", + "comment-parser": "1.3.0", + "debug": "^4.3.3", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.4.0", + "regextras": "^0.8.0", + "semver": "^7.3.5", + "spdx-expression-parse": "^3.0.1" }, "engines": { - "node": ">=10" + "node": "^12 || ^14 || ^16 || ^17" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-2.0.2.tgz", - "integrity": "sha512-KmE+bMjWMXJbkWCeY4FJX/npHuZPNr9XF9q9CIQ/bpFwi1qHfCmSiKarrCcRa0LO4fWjk93pVoeRtJAkTGcYNw==", + "node_modules/eslint-plugin-n": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.3.0.tgz", + "integrity": "sha512-IyzPnEWHypCWasDpxeJnim60jhlumbmq0pubL6IOcnk8u2y53s5QfT8JnXy7skjHJ44yWHRb11PLtDHuu1kg/Q==", "dev": true, + "peer": true, "dependencies": { - "cosmiconfig": "^7", - "ts-node": "^10.8.1" + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.10.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.7" }, "engines": { - "node": ">=12", - "npm": ">=6" + "node": ">=12.22.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=7", - "typescript": ">=3" + "eslint": ">=7.0.0" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", "dev": true, + "peer": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" } }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "peer": true, "dependencies": { - "type-fest": "^1.0.1" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "node_modules/eslint-plugin-n/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, + "peer": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/crypto-randomuuid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-randomuuid/-/crypto-randomuuid-1.0.0.tgz", - "integrity": "sha512-/RC5F4l1SCqD/jazwUF6+t34Cd8zTSAGZ7rvvZu1whZUhD2a5MOGKjSGowoGcpj/cbVZk1ZODIooJEQQq3nNAA==", - "dev": true - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", "dev": true, "dependencies": { - "cssom": "~0.3.6" + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "engines": { - "node": ">=8" + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "node_modules/eslint-plugin-node/node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" + "prettier-linter-helpers": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "node_modules/eslint-plugin-promise": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", + "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", "dev": true, "engines": { - "node": "*" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/dd-trace": { - "version": "2.45.1", - "resolved": "https://registry.npmjs.org/dd-trace/-/dd-trace-2.45.1.tgz", - "integrity": "sha512-FZu1kvYRFwqR1LHR3iBlSU60R33rdWD+Wtd9yQG5VIlkbrNFTIB0IXSC4fjUusPmvkUUxo4nP0roQBwyxHdnZA==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "hasInstallScript": true, "dependencies": { - "@datadog/native-appsec": "^3.2.0", - "@datadog/native-iast-rewriter": "2.0.1", - "@datadog/native-iast-taint-tracking": "1.5.0", - "@datadog/native-metrics": "^1.6.0", - "@datadog/pprof": "3.1.0", - "@datadog/sketches-js": "^2.1.0", - "@opentelemetry/api": "^1.0.0", - "@opentelemetry/core": "<1.4.0", - "@types/node": "<18.13", - "crypto-randomuuid": "^1.0.0", - "diagnostics_channel": "^1.1.0", - "ignore": "^5.2.4", - "import-in-the-middle": "^1.4.2", - "int64-buffer": "^0.1.9", - "ipaddr.js": "^2.1.0", - "istanbul-lib-coverage": "3.2.0", - "koalas": "^1.0.2", - "limiter": "^1.1.4", - "lodash.kebabcase": "^4.1.1", - "lodash.pick": "^4.4.0", - "lodash.sortby": "^4.7.0", - "lodash.uniq": "^4.5.0", - "lru-cache": "^7.14.0", - "methods": "^1.1.2", - "module-details-from-path": "^1.0.3", - "msgpack-lite": "^0.1.26", - "node-abort-controller": "^3.1.1", - "opentracing": ">=0.12.1", - "path-to-regexp": "^0.1.2", - "protobufjs": "^7.2.4", - "retry": "^0.13.1", - "semver": "^7.5.4" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=12" + "node": ">=8.0.0" } }, - "node_modules/dd-trace/node_modules/@types/node": { - "version": "18.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.19.tgz", - "integrity": "sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==", - "dev": true - }, - "node_modules/dd-trace/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, "engines": { - "node": ">=12" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/dd-trace/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, "engines": { "node": ">=10" } }, - "node_modules/dd-trace/node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4.0" } }, - "node_modules/decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "engines": { - "node": ">=4.0.0" + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delay": { + "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", - "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { "node": ">=10" }, @@ -5181,252 +6969,311 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "node_modules/espree": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, "engines": { - "node": ">=0.4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true - }, - "node_modules/detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", - "dev": true - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/diagnostics_channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/diagnostics_channel/-/diagnostics_channel-1.1.0.tgz", - "integrity": "sha512-OE1ngLDjSBPG6Tx0YATELzYzy3RKHC+7veQ8gLa8yS7AAgw65mFbVdcsu3501abqOZCEZqZyAIemB0zXlqDSuw==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, "engines": { "node": ">=4" } }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "dependencies": { - "path-type": "^4.0.0" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=8" + "node": ">=0.10" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, "engines": { - "node": ">=6.0.0" + "node": ">=4.0" } }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "webidl-conversions": "^7.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=12" + "node": ">=4.0" } }, - "node_modules/dot-prop": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, "engines": { - "node": ">=8" + "node": ">=4.0" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" + "engines": { + "node": ">=4.0" } }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/eth-rpc-errors": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", + "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "fast-safe-stringify": "^2.0.6" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.356", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz", - "integrity": "sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "node_modules/ethers": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.3.tgz", + "integrity": "sha512-fTT4WT8/hTe/BLwRUtl7I5zlpF3XC3P/Xwqxc5AIP2HGlH15qpmjs0Ou78az93b1rLITzXLFxoNX63B8ZbUd7g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "@ethersproject/abi": "5.5.0", + "@ethersproject/abstract-provider": "5.5.1", + "@ethersproject/abstract-signer": "5.5.0", + "@ethersproject/address": "5.5.0", + "@ethersproject/base64": "5.5.0", + "@ethersproject/basex": "5.5.0", + "@ethersproject/bignumber": "5.5.0", + "@ethersproject/bytes": "5.5.0", + "@ethersproject/constants": "5.5.0", + "@ethersproject/contracts": "5.5.0", + "@ethersproject/hash": "5.5.0", + "@ethersproject/hdnode": "5.5.0", + "@ethersproject/json-wallets": "5.5.0", + "@ethersproject/keccak256": "5.5.0", + "@ethersproject/logger": "5.5.0", + "@ethersproject/networks": "5.5.2", + "@ethersproject/pbkdf2": "5.5.0", + "@ethersproject/properties": "5.5.0", + "@ethersproject/providers": "5.5.2", + "@ethersproject/random": "5.5.1", + "@ethersproject/rlp": "5.5.0", + "@ethersproject/sha2": "5.5.0", + "@ethersproject/signing-key": "5.5.0", + "@ethersproject/solidity": "5.5.0", + "@ethersproject/strings": "5.5.0", + "@ethersproject/transactions": "5.5.0", + "@ethersproject/units": "5.5.0", + "@ethersproject/wallet": "5.5.0", + "@ethersproject/web": "5.5.1", + "@ethersproject/wordlists": "5.5.0" } }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "node_modules/event-lite": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz", + "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", "dev": true, "dependencies": { - "once": "^1.4.0" + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/env-ci": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-9.1.0.tgz", - "integrity": "sha512-ZCEas2sDVFR3gpumwwzSU4OJZwWJ46yqJH3TqH3vSxEBzeAlC0uCJLGAnZC0vX1TIXzHzjcwpKmUn2xw5mC/qA==", + "node_modules/extension-port-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-2.1.1.tgz", + "integrity": "sha512-qknp5o5rj2J9CRKfVB8KJr+uXQlrojNZzdESUPhKYLXf97TPcGf6qWWKmpsNNtUyOdzFhab1ON0jzouNxHHvow==", "dev": true, "dependencies": { - "execa": "^7.0.0", - "java-properties": "^1.0.2" + "webextension-polyfill": ">=0.10.0 <1.0" }, "engines": { - "node": "^16.14 || >=18" + "node": ">=12.0.0" } }, - "node_modules/env-ci/node_modules/execa": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", - "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=8.6.0" } }, - "node_modules/env-ci/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "engines": { - "node": ">=14.18.0" + "dependencies": { + "bser": "2.1.1" } }, - "node_modules/env-ci/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/env-ci/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "engines": { "node": ">=12" @@ -5435,53 +7282,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/env-ci/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "dependencies": { - "path-key": "^4.0.0" + "flat-cache": "^3.0.4" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/env-ci/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { - "mimic-fn": "^4.0.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/env-ci/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "engines": { - "node": ">=12" + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "node_modules/env-ci/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", "dev": true, + "dependencies": { + "semver-regex": "^4.0.5" + }, "engines": { "node": ">=12" }, @@ -5489,2444 +7334,2646 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "glob": "^7.1.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.16.tgz", - "integrity": "sha512-aeSuUKr9aFVY9Dc8ETVELGgkj4urg5isYx8pLf4wlGgB0vTFjxJQdHnNH6Shmx4vYYrOTLCHtRI5i1XZ9l2Zcg==", - "dev": true, - "hasInstallScript": true, "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" + "rimraf": "bin.js" }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.16", - "@esbuild/android-arm64": "0.17.16", - "@esbuild/android-x64": "0.17.16", - "@esbuild/darwin-arm64": "0.17.16", - "@esbuild/darwin-x64": "0.17.16", - "@esbuild/freebsd-arm64": "0.17.16", - "@esbuild/freebsd-x64": "0.17.16", - "@esbuild/linux-arm": "0.17.16", - "@esbuild/linux-arm64": "0.17.16", - "@esbuild/linux-ia32": "0.17.16", - "@esbuild/linux-loong64": "0.17.16", - "@esbuild/linux-mips64el": "0.17.16", - "@esbuild/linux-ppc64": "0.17.16", - "@esbuild/linux-riscv64": "0.17.16", - "@esbuild/linux-s390x": "0.17.16", - "@esbuild/linux-x64": "0.17.16", - "@esbuild/netbsd-x64": "0.17.16", - "@esbuild/openbsd-x64": "0.17.16", - "@esbuild/sunos-x64": "0.17.16", - "@esbuild/win32-arm64": "0.17.16", - "@esbuild/win32-ia32": "0.17.16", - "@esbuild/win32-x64": "0.17.16" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/esbuild-plugin-external-global": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esbuild-plugin-external-global/-/esbuild-plugin-external-global-1.0.1.tgz", - "integrity": "sha512-NDzYHRoShpvLqNcrgV8ZQh61sMIFAry5KLTQV83BPG5iTXCCu7h72SCfJ97bW0GqtuqDD/1aqLbKinI/rNgUsg==", + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, - "node_modules/escalade": { + "node_modules/foreground-child": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, "engines": { - "node": ">=6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", + "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" + "node": ">= 6" } }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, - "engines": { - "node": ">=4.0" + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "node_modules/fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=12" } }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.8.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/eslint": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", - "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-config-standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", - "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/git-log-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", + "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", "dev": true, - "engines": { - "node": ">=4" + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" } }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "node_modules/git-log-parser/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/git-log-parser/node_modules/split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", "dev": true, "dependencies": { - "ms": "2.0.0" + "through2": "~2.0.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/git-log-parser/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "node_modules/git-log-parser/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "37.9.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-37.9.1.tgz", - "integrity": "sha512-ynIsYL+rOtIKWOttAYWCgOJawPwYKexcX3cuoYHwifvz4+uY+MZ2un5nMHBULigdSITnQ5/ZSHpO/O1nwv/uJA==", + "node_modules/git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.19.0", - "comment-parser": "1.3.0", - "debug": "^4.3.3", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "regextras": "^0.8.0", - "semver": "^7.3.5", - "spdx-expression-parse": "^3.0.1" + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" }, - "engines": { - "node": "^12 || ^14 || ^16 || ^17" + "bin": { + "git-raw-commits": "cli.js" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "engines": { + "node": ">=10" } }, - "node_modules/eslint-plugin-n": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.3.0.tgz", - "integrity": "sha512-IyzPnEWHypCWasDpxeJnim60jhlumbmq0pubL6IOcnk8u2y53s5QfT8JnXy7skjHJ44yWHRb11PLtDHuu1kg/Q==", + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, - "peer": true, "dependencies": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.10.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.7" + "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" }, "engines": { - "node": ">=12.22.0" + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "peer": true, "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" + "node": ">= 6" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", "dev": true, - "peer": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "ini": "^1.3.4" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">=4" } }, - "node_modules/eslint-plugin-n/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, - "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-node": { + "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, - "peerDependencies": { - "eslint": ">=5.16.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-node/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">=6" + "node": ">=0.4.7" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true, "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=6" } }, - "node_modules/eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "function-bind": "^1.1.1" }, "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } + "node": ">= 0.4.0" } }, - "node_modules/eslint-plugin-promise": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", - "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, "engines": { - "node": ">=8.0.0" + "node": ">=8" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "get-intrinsic": "^1.1.1" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "has-symbols": "^1.0.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/hook-std": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", "dev": true, "dependencies": { - "is-glob": "^4.0.3" + "lru-cache": "^6.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=10" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "dependencies": { - "argparse": "^2.0.1" + "whatwg-encoding": "^2.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=12" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "dependencies": { - "p-limit": "^3.0.2" + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true, + "bin": { + "husky": "lib/bin.js" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/typicode" } }, - "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=0.10.0" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 4" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, "engines": { - "node": ">=0.10" + "node": ">=4" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/import-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", + "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=12.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/import-in-the-middle": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", + "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", "dev": true, "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, "engines": { - "node": ">=4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=0.8.19" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/eth-rpc-errors": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", - "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "dependencies": { - "fast-safe-stringify": "^2.0.6" + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/ethers": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.3.tgz", - "integrity": "sha512-fTT4WT8/hTe/BLwRUtl7I5zlpF3XC3P/Xwqxc5AIP2HGlH15qpmjs0Ou78az93b1rLITzXLFxoNX63B8ZbUd7g==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "5.5.0", - "@ethersproject/abstract-provider": "5.5.1", - "@ethersproject/abstract-signer": "5.5.0", - "@ethersproject/address": "5.5.0", - "@ethersproject/base64": "5.5.0", - "@ethersproject/basex": "5.5.0", - "@ethersproject/bignumber": "5.5.0", - "@ethersproject/bytes": "5.5.0", - "@ethersproject/constants": "5.5.0", - "@ethersproject/contracts": "5.5.0", - "@ethersproject/hash": "5.5.0", - "@ethersproject/hdnode": "5.5.0", - "@ethersproject/json-wallets": "5.5.0", - "@ethersproject/keccak256": "5.5.0", - "@ethersproject/logger": "5.5.0", - "@ethersproject/networks": "5.5.2", - "@ethersproject/pbkdf2": "5.5.0", - "@ethersproject/properties": "5.5.0", - "@ethersproject/providers": "5.5.2", - "@ethersproject/random": "5.5.1", - "@ethersproject/rlp": "5.5.0", - "@ethersproject/sha2": "5.5.0", - "@ethersproject/signing-key": "5.5.0", - "@ethersproject/solidity": "5.5.0", - "@ethersproject/strings": "5.5.0", - "@ethersproject/transactions": "5.5.0", - "@ethersproject/units": "5.5.0", - "@ethersproject/wallet": "5.5.0", - "@ethersproject/web": "5.5.1", - "@ethersproject/wordlists": "5.5.0" - } + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/event-lite": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.3.tgz", - "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==", + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/int64-buffer": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", + "integrity": "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/into-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "dev": true, + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", "dev": true, "engines": { - "node": ">= 0.8.0" + "node": ">= 10" } }, - "node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" + "has-bigints": "^1.0.1" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extension-port-stream": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-2.1.1.tgz", - "integrity": "sha512-qknp5o5rj2J9CRKfVB8KJr+uXQlrojNZzdESUPhKYLXf97TPcGf6qWWKmpsNNtUyOdzFhab1ON0jzouNxHHvow==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { - "webextension-polyfill": ">=0.10.0 <1.0" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=8" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/is-callable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", + "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dev": true, "dependencies": { - "bser": "2.1.1" + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=8" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=0.12.0" } }, - "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { - "semver-regex": "^4.0.5" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=0.10.0" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "dependencies": { - "glob": "^7.1.3" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" + "call-bind": "^1.0.2" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { - "node": ">=14" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "has-tostringtag": "^1.0.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "call-bind": "^1.0.2" }, - "engines": { - "node": ">=12" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fs.realpath": { + "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "node_modules/issue-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", + "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.13" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10" } }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=8.0.0" + "node": ">=10" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "node_modules/jackspeak": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", + "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "cliui": "^7.0.4" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/git-log-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz", - "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=", + "node_modules/java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", "dev": true, - "dependencies": { - "argv-formatter": "~1.0.0", - "spawn-error-forwarder": "~1.0.0", - "split2": "~1.0.0", - "stream-combiner2": "~1.1.1", - "through2": "~2.0.0", - "traverse": "~0.6.6" + "engines": { + "node": ">= 0.6.0" } }, - "node_modules/git-log-parser/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/jest": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz", + "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==", "dev": true, "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "@jest/core": "^29.6.4", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.6.4" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/git-log-parser/node_modules/split2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", - "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=", + "node_modules/jest-changed-files": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz", + "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==", "dev": true, "dependencies": { - "through2": "~2.0.0" + "execa": "^5.0.0", + "jest-util": "^29.6.3", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/git-log-parser/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/jest-changed-files/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/git-log-parser/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "node_modules/jest-circus": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz", + "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==", "dev": true, "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "git-raw-commits": "cli.js" + "@jest/environment": "^29.6.4", + "@jest/expect": "^29.6.4", + "@jest/test-result": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.6.3", + "jest-matcher-utils": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-runtime": "^29.6.4", + "jest-snapshot": "^29.6.4", + "jest-util": "^29.6.3", + "p-limit": "^3.1.0", + "pretty-format": "^29.6.3", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "node_modules/jest-circus/node_modules/@jest/environment": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", + "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", "dev": true, "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" + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/jest-circus/node_modules/@jest/fake-timers": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", + "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, "engines": { - "node": ">= 6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "node_modules/jest-circus/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "ini": "^1.3.4" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "node_modules/jest-circus/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type-detect": "4.0.8" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", + "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", "dev": true, "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", + "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1" + "chalk": "^4.0.0", + "jest-diff": "^29.6.4", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/jest-circus/node_modules/jest-mock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", + "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.6.3" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "node_modules/jest-cli": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz", + "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==", + "dev": true, "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "@jest/core": "^29.6.4", + "@jest/test-result": "^29.6.4", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.6.4", + "jest-util": "^29.6.3", + "jest-validate": "^29.6.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", + "dev": true, "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/hook-std": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", - "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", + "node_modules/jest-config": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz", + "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==", "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.6.4", + "@jest/types": "^29.6.3", + "babel-jest": "^29.6.4", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.6.4", + "jest-environment-node": "^29.6.4", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.6.4", + "jest-runner": "^29.6.4", + "jest-util": "^29.6.3", + "jest-validate": "^29.6.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "node_modules/jest-config/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "node_modules/jest-config/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", "dev": true, "dependencies": { - "whatwg-encoding": "^2.0.0" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">=12" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/jest-config/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "node_modules/jest-config/node_modules/babel-jest": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz", + "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==", "dev": true, "dependencies": { - "agent-base": "6", - "debug": "4" + "@jest/transform": "^29.6.4", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" }, "engines": { - "node": ">= 6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/jest-config/node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, "engines": { - "node": ">=10.17.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "node_modules/jest-config/node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "bin": { - "husky": "lib/bin.js" + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": ">=12" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "funding": { - "url": "https://github.com/sponsors/typicode" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/jest-config/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "node_modules/jest-config/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-config/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "engines": { - "node": ">= 4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/import-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", - "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", + "node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, - "engines": { - "node": ">=12.2" + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/import-in-the-middle": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.4.2.tgz", - "integrity": "sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==", + "node_modules/jest-docblock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz", + "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==", "dev": true, "dependencies": { - "acorn": "^8.8.2", - "acorn-import-assertions": "^1.9.0", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "node_modules/jest-each": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz", + "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==", "dev": true, "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/jest-each/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "engines": { - "node": ">=0.8.19" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/int64-buffer": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", - "integrity": "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/into-stream": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", - "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "node_modules/jest-environment-jsdom": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-28.1.3.tgz", + "integrity": "sha512-HnlGUmZRdxfCByd3GM2F100DgQOajUBzEitjGqIREcb45kGjZvRrKUdlaF6escXBdcXNl0OBh+1ZrfeZT3GnAg==", "dev": true, "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/jsdom": "^16.2.4", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3", + "jsdom": "^19.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "node_modules/jest-environment-jsdom/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.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" + }, "engines": { - "node": ">= 10" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/jest-environment-node": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz", + "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "@jest/environment": "^29.6.4", + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/jest-environment-node/node_modules/@jest/environment": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", + "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", + "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-callable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", - "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", + "node_modules/jest-environment-node/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, - "engines": { - "node": ">= 0.4" + "dependencies": { + "@sinclair/typebox": "^0.27.8" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "node_modules/jest-environment-node/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-environment-node/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "type-detect": "4.0.8" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/jest-environment-node/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", + "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.6.3" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/jest-environment-node/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "is-extglob": "^2.1.1" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jest-leak-detector": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", + "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==", "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" + }, "engines": { - "node": ">=0.12.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/jest-leak-detector/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/jest-leak-detector/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "@jest/schemas": "^28.1.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" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "@jest/types": "^28.1.3", + "@types/node": "*" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { - "text-extensions": "^1.0.0" + "@jest/schemas": "^28.1.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" }, "engines": { - "node": ">=0.10.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "engines": { - "node": ">=12" + "node": ">=6" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/jest-resolve": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz", + "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.6.3", + "jest-validate": "^29.6.3", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "node_modules/jest-resolve-dependencies": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz", + "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.6.4" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/jest-resolve-dependencies/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/issue-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz", - "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==", + "node_modules/jest-resolve/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, "dependencies": { - "lodash.capitalize": "^4.2.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.uniqby": "^4.7.0" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": ">=10.13" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "node_modules/jest-resolve/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/jest-runner": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz", + "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "@jest/console": "^29.6.4", + "@jest/environment": "^29.6.4", + "@jest/test-result": "^29.6.4", + "@jest/transform": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.6.3", + "jest-environment-node": "^29.6.4", + "jest-haste-map": "^29.6.4", + "jest-leak-detector": "^29.6.3", + "jest-message-util": "^29.6.3", + "jest-resolve": "^29.6.4", + "jest-runtime": "^29.6.4", + "jest-util": "^29.6.3", + "jest-watcher": "^29.6.4", + "jest-worker": "^29.6.4", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "node_modules/jest-runner/node_modules/@jest/environment": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", + "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", "dev": true, "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/jest-runner/node_modules/@jest/fake-timers": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", + "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", "dev": true, "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "node_modules/jest-runner/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jackspeak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", - "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", + "node_modules/jest-runner/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", "dev": true, "dependencies": { - "cliui": "^7.0.4" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">=14" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-runner/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/jest-runner/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "fsevents": "^2.3.2" } }, - "node_modules/java-properties": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", - "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": ">= 0.6.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", - "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "node_modules/jest-runner/node_modules/jest-mock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", + "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", "dev": true, "dependencies": { - "@jest/core": "^28.1.3", - "@jest/types": "^28.1.3", - "import-local": "^3.0.2", - "jest-cli": "^28.1.3" - }, - "bin": { - "jest": "bin/jest.js" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.6.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", - "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "node_modules/jest-runner/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-changed-files/node_modules/p-limit": { + "node_modules/jest-runner/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", @@ -7941,552 +9988,675 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", - "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "node_modules/jest-runner/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/expect": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz", + "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.4", + "@jest/fake-timers": "^29.6.4", + "@jest/globals": "^29.6.4", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.6.4", + "@jest/transform": "^29.6.4", + "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "p-limit": "^3.1.0", - "pretty-format": "^28.1.3", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.6.4", + "jest-snapshot": "^29.6.4", + "jest-util": "^29.6.3", "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "strip-bom": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/jest-runtime/node_modules/@jest/environment": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", + "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "@jest/fake-timers": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.6.3" }, "engines": { - "node": ">=10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/fake-timers": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", + "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.3", + "jest-mock": "^29.6.3", + "jest-util": "^29.6.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-cli": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", - "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "node_modules/jest-runtime/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "@jest/core": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "exit": "^0.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "prompts": "^2.0.1", - "yargs": "^17.3.1" + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, - "bin": { - "jest": "bin/jest.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/jest-runtime/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-config": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", - "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.3", - "@jest/types": "^28.1.3", - "babel-jest": "^28.1.3", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.3", - "jest-environment-node": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-runner": "^28.1.3", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^28.1.3", + "pretty-format": "^29.6.3", "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", + "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.6.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-docblock": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", - "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "node_modules/jest-runtime/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "detect-newline": "^3.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", - "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "node_modules/jest-runtime/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.3", - "pretty-format": "^28.1.3" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-28.1.3.tgz", - "integrity": "sha512-HnlGUmZRdxfCByd3GM2F100DgQOajUBzEitjGqIREcb45kGjZvRrKUdlaF6escXBdcXNl0OBh+1ZrfeZT3GnAg==", + "node_modules/jest-snapshot": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz", + "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/jsdom": "^16.2.4", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3", - "jsdom": "^19.0.0" + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.6.4", + "@jest/transform": "^29.6.4", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.6.4", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.6.4", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-util": "^29.6.3", + "natural-compare": "^1.4.0", + "pretty-format": "^29.6.3", + "semver": "^7.5.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", - "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz", + "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-get-type": "^29.6.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "node_modules/jest-snapshot/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-haste-map": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", - "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "node_modules/jest-snapshot/node_modules/@jest/transform": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", + "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.3", - "jest-worker": "^28.1.3", + "jest-haste-map": "^29.6.4", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", "micromatch": "^4.0.4", - "walker": "^1.0.8" + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "node_modules/jest-snapshot/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/expect": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz", + "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==", "dev": true, "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@jest/expect-utils": "^29.6.4", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.6.4", + "jest-message-util": "^29.6.3", + "jest-util": "^29.6.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", + "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-leak-detector": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", - "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-haste-map": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", + "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", "dev": true, "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.6.3", + "jest-worker": "^29.6.4", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", + "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" + "jest-diff": "^29.6.4", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.6.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", + "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", + "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", + "pretty-format": "^29.6.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "node_modules/jest-snapshot/node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", - "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.3", - "jest-validate": "^28.1.3", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", - "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.3" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10" } }, - "node_modules/jest-runner": { + "node_modules/jest-util": { "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", - "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", "dev": true, "dependencies": { - "@jest/console": "^28.1.3", - "@jest/environment": "^28.1.3", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.10.2", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.1.1", - "jest-environment-node": "^28.1.3", - "jest-haste-map": "^28.1.3", - "jest-leak-detector": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-resolve": "^28.1.3", - "jest-runtime": "^28.1.3", - "jest-util": "^28.1.3", - "jest-watcher": "^28.1.3", - "jest-worker": "^28.1.3", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" + "picomatch": "^2.2.3" }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-runner/node_modules/jest-worker": { + "node_modules/jest-util/node_modules/@jest/types": { "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-runner/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/jest-validate": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz", + "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.6.3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "node_modules/jest-validate/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/jest-validate/node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runtime": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", - "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", + "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", "dev": true, "dependencies": { - "@jest/environment": "^28.1.3", - "@jest/fake-timers": "^28.1.3", - "@jest/globals": "^28.1.3", - "@jest/source-map": "^28.1.2", - "@jest/test-result": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.3", - "jest-snapshot": "^28.1.3", - "jest-util": "^28.1.3", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", - "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "node_modules/jest-watcher": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz", + "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==", "dev": true, "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.3", - "@jest/transform": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", + "@jest/test-result": "^29.6.4", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "expect": "^28.1.3", - "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.3", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3", - "natural-compare": "^1.4.0", - "pretty-format": "^28.1.3", - "semver": "^7.3.5" + "emittery": "^0.13.1", + "jest-util": "^29.6.3", + "string-length": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -8494,55 +10664,54 @@ "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", - "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "node_modules/jest-worker": { + "version": "29.6.4", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz", + "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "leven": "^3.1.0", - "pretty-format": "^28.1.3" + "@types/node": "*", + "jest-util": "^29.6.3", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-watcher": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", - "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "@jest/test-result": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.3", - "string-length": "^4.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/joycon": { @@ -9115,27 +11284,33 @@ "dev": true }, "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/make-error": { @@ -9412,6 +11587,15 @@ "node": ">=0.10.0" } }, + "node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -9493,9 +11677,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "dependencies": { "whatwg-url": "^5.0.0" @@ -13008,13 +15192,13 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -13032,15 +15216,6 @@ "node": "14 || >=16.14" } }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -13358,6 +15533,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz", + "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -13558,6 +15749,14 @@ "esprima": "~4.0.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -13674,9 +15873,9 @@ } }, "node_modules/resolve.exports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", - "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, "engines": { "node": ">=10" @@ -14438,6 +16637,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", @@ -14848,22 +17057,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -15023,32 +17216,32 @@ "dev": true }, "node_modules/ts-jest": { - "version": "28.0.8", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", - "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", - "json5": "^2.2.1", + "jest-util": "^29.0.0", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", - "semver": "7.x", + "semver": "^7.5.3", "yargs-parser": "^21.0.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^28.0.0", - "babel-jest": "^28.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" }, "peerDependenciesMeta": { "@babel/core": { @@ -15065,6 +17258,38 @@ } } }, + "node_modules/ts-jest/node_modules/jest-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", + "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ts-jest/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/package.json b/package.json index ea08c8cd9..393bfd5f9 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,11 @@ "clean:proto": "rimraf -g src/proto/*.ts", "package": "npm pack", "prepublishOnly": "npm run build", + "updateSnapVersion": "npm view @xmtp/snap --json | jq '{\"version\": .version, \"package\": .name}' > ./src/snapInfo.json", "test:setup": "./dev/up", "test:teardown": "./dev/down", "test": "npm run test:node", - "test:node": "jest --no-cache --env='node' --testTimeout=30000", + "test:node": "jest --no-cache --config ./jest.config.cjs --testTimeout=30000", "test:jsdom": "jest --no-cache --env='./jest.jsdom.env.cjs' --testTimeout=30000", "test:cov": "jest --coverage --no-cache --runInBand", "lint": "prettier --check . && eslint .", @@ -114,12 +115,12 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-promise": "^6.0.1", "husky": "^7.0.4", - "jest": "^28.1.3", + "jest": "^29.6.0", "jest-environment-jsdom": "^28.1.3", "prettier": "^2.4.0", "rimraf": "^5.0.0", "semantic-release": "^21.0.3", - "ts-jest": "^28.0.0", + "ts-jest": "^29.1.1", "ts-node": "^10.9.1", "tsup": "^6.7.0", "typedoc": "^0.22.11", diff --git a/src/Client.ts b/src/Client.ts index 8448a75be..900bbb455 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -31,6 +31,7 @@ import { KeystoreProvider, KeystoreProviderUnavailableError, NetworkKeystoreProvider, + SnapProvider, StaticKeystoreProvider, } from './keystore/providers' import { @@ -38,6 +39,8 @@ import { InMemoryPersistence, Persistence, } from './keystore/persistence' +import { hasMetamaskWithSnaps } from './keystore/snapHelpers' +import { version as snapVersion, package as snapPackage } from './snapInfo.json' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types @@ -159,6 +162,10 @@ export type KeyStoreOptions = { * Only disable if you are using a secure datastore that already has encryption */ disablePersistenceEncryption: boolean + /** + * A single option to allow Metamask Snaps to be used as a keystore provider + */ + useSnaps: boolean } export type LegacyOptions = { @@ -210,6 +217,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { maxContentSize: MaxContentSize, persistConversations: true, skipContactPublishing: false, + useSnaps: false, basePersistence: isBrowser() ? BrowserStoragePersistence.create() : InMemoryPersistence.create(), @@ -222,6 +230,13 @@ export function defaultOptions(opts?: Partial): ClientOptions { opts.codecs = _defaultOptions.codecs.concat(opts.codecs) } + if (opts?.useSnaps) { + opts.keystoreProviders = [ + new SnapProvider(`npm:${snapPackage}`, snapVersion), + ..._defaultOptions.keystoreProviders, + ] + } + return { ..._defaultOptions, ...opts } as ClientOptions } @@ -331,6 +346,24 @@ export default class Client { return new PrivateKeyBundleV1(keys).encode() } + /** + * Tells the caller whether `getKeys` will work for them or throw + * Right now, this is only true if the user has Metamask with Snaps + * and has enabled the `useSnaps` option + */ + static async canGetKeys( + wallet: Signer | null, + opts?: Partial + ) { + if (!defaultOptions(opts).useSnaps) { + return true + } + + const isSnapCompatible = await hasMetamaskWithSnaps() + + return !isSnapCompatible + } + private static async setupBackupClient( walletAddress: string, env: keyof typeof ApiUrls diff --git a/src/keystore/providers/SnapProvider.ts b/src/keystore/providers/SnapProvider.ts index 4047d8218..a22787a14 100644 --- a/src/keystore/providers/SnapProvider.ts +++ b/src/keystore/providers/SnapProvider.ts @@ -13,7 +13,7 @@ import { keystore } from '@xmtp/proto' import { Signer } from '../../types/Signer' import { ApiClient } from '../../ApiClient' import NetworkKeystoreProvider from './NetworkKeystoreProvider' -import { PrivateKeyBundleV1 } from '../../crypto' +import { PrivateKeyBundleV1, decodePrivateKeyBundle } from '../../crypto' import KeyGeneratorKeystoreProvider from './KeyGeneratorKeystoreProvider' import type { XmtpEnv } from '../../Client' import { semverGreaterThan } from '../../utils/semver' @@ -62,7 +62,7 @@ export default class SnapKeystoreProvider implements KeystoreProvider { } if (!(await checkSnapLoaded(walletAddress, env, this.snapId))) { - const bundle = await getBundle(opts, apiClient, wallet) + const bundle = await bundleFromOptions(opts, apiClient, wallet) await initSnap(bundle, env, this.snapId) } @@ -80,7 +80,27 @@ async function createBundle( return new PrivateKeyBundleV1(await tmpKeystore.getPrivateKeyBundle()) } -async function getBundle( +async function bundleFromOptions( + opts: KeystoreProviderOptions, + apiClient: ApiClient, + wallet?: Signer +) { + if (opts.privateKeyOverride) { + const bundle = decodePrivateKeyBundle(opts.privateKeyOverride) + if (!(bundle instanceof PrivateKeyBundleV1)) { + throw new Error('Unsupported private key bundle version') + } + return bundle + } + + if (!wallet) { + throw new Error('No privateKeyOverride or wallet') + } + + return getOrCreateBundle(opts, apiClient, wallet) +} + +async function getOrCreateBundle( opts: KeystoreProviderOptions, apiClient: ApiClient, wallet: Signer diff --git a/src/snapInfo.json b/src/snapInfo.json new file mode 100644 index 000000000..c579f12d9 --- /dev/null +++ b/src/snapInfo.json @@ -0,0 +1,4 @@ +{ + "version": "1.2.2", + "package": "@xmtp/snap" +} diff --git a/test/Client.test.ts b/test/Client.test.ts index e3a9ff04e..725d0ddd6 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -28,6 +28,22 @@ type TestCase = { newClient: (opts?: Partial) => Promise } +const mockEthRequest = jest.fn() +jest.mock('../src/utils/ethereum', () => { + return { + __esModule: true, + getEthereum: jest.fn(() => { + const ethereum: any = { + request: mockEthRequest, + } + ethereum.providers = [ethereum] + ethereum.detected = [ethereum] + ethereum.isMetaMask = true + return ethereum + }), + } +}) + describe('Client', () => { const tests: TestCase[] = [ { @@ -358,4 +374,19 @@ describe('ClientOptions', () => { await expect(c).rejects.toThrow('MyNewPersistence') }) }) + + describe('canGetKeys', () => { + it('returns true if the useSnaps flag is false', async () => { + const canGetKeys = await Client.canGetKeys(newWallet(), {}) + expect(canGetKeys).toBe(true) + }) + + it('returns false if the user has a Snaps capable browser and snaps are enabled', async () => { + mockEthRequest.mockResolvedValue([]) + const canGetKeys = await Client.canGetKeys(newWallet(), { + useSnaps: true, + }) + expect(canGetKeys).toBe(false) + }) + }) }) From ac1372be98ccf9cf3eb225b75937df820b0a7755 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Fri, 8 Sep 2023 13:28:37 -0700 Subject: [PATCH 117/137] fix: rename method --- package.json | 2 +- src/Client.ts | 13 ++----------- test/Client.test.ts | 11 +++++------ 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 393bfd5f9..4c61b022c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "test:setup": "./dev/up", "test:teardown": "./dev/down", "test": "npm run test:node", - "test:node": "jest --no-cache --config ./jest.config.cjs --testTimeout=30000", + "test:node": "jest --no-cache --env='node' --testTimeout=30000", "test:jsdom": "jest --no-cache --env='./jest.jsdom.env.cjs' --testTimeout=30000", "test:cov": "jest --coverage --no-cache --runInBand", "lint": "prettier --check . && eslint .", diff --git a/src/Client.ts b/src/Client.ts index 900bbb455..7e4e1912e 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -351,17 +351,8 @@ export default class Client { * Right now, this is only true if the user has Metamask with Snaps * and has enabled the `useSnaps` option */ - static async canGetKeys( - wallet: Signer | null, - opts?: Partial - ) { - if (!defaultOptions(opts).useSnaps) { - return true - } - - const isSnapCompatible = await hasMetamaskWithSnaps() - - return !isSnapCompatible + static isSnapsReady() { + return hasMetamaskWithSnaps() } private static async setupBackupClient( diff --git a/test/Client.test.ts b/test/Client.test.ts index 725d0ddd6..c3773d227 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -377,16 +377,15 @@ describe('ClientOptions', () => { describe('canGetKeys', () => { it('returns true if the useSnaps flag is false', async () => { - const canGetKeys = await Client.canGetKeys(newWallet(), {}) - expect(canGetKeys).toBe(true) + mockEthRequest.mockRejectedValue(new Error('foo')) + const isSnapsReady = await Client.isSnapsReady() + expect(isSnapsReady).toBe(false) }) it('returns false if the user has a Snaps capable browser and snaps are enabled', async () => { mockEthRequest.mockResolvedValue([]) - const canGetKeys = await Client.canGetKeys(newWallet(), { - useSnaps: true, - }) - expect(canGetKeys).toBe(false) + const isSnapsReady = await Client.isSnapsReady() + expect(isSnapsReady).toBe(true) }) }) }) From a5959747adc5290ca438eb7a535321ab9388710e Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Mon, 11 Sep 2023 09:20:33 -0700 Subject: [PATCH 118/137] docs: add more keystore details --- README.md | 12 ++++++ src/keystore/README.md | 86 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/keystore/README.md diff --git a/README.md b/README.md index 58c975a81..9d399c4ee 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,10 @@ The client's network connection and key storage method can be configured with th | maxContentSize | `100M` | Maximum message content size in bytes. | | preCreateIdentityCallback | `undefined` | `preCreateIdentityCallback` is a function that will be called immediately before a [Create Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-create-an-xmtp-identity) is requested from the user. | | preEnableIdentityCallback | `undefined` | `preEnableIdentityCallback` is a function that will be called immediately before an [Enable Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-enable-an-xmtp-identity) is requested from the user. | +| useSnaps | `false` | Enabling the `useSnaps` flag will allow the client to attempt to connect to the "Sign in with XMTP" MetaMask Snap as part of client creation. It is safe to enable this flag even if you do not know whether the user has an appropriate MetaMask version enabled. If no compatible version of MetaMask is found, client creation will proceed as if this flag was set to `false`. Read more about Snaps [here](#interacting-with-snaps) | +| basePersistence | `InMemoryPersistence` (Node.js) or `LocalStoragePersistence` (browser) | A persistence provider used by the Keystore to persist its cache of conversations and metadata. Ignored in cases where the `useSnaps` is enabled and the user has a Snaps compatible browser | +| basePersistence | `InMemoryPersistence` (Node.js) or `LocalStoragePersistence` (browser) | A persistence provider used by the Keystore to persist its cache of conversations and metadata. Ignored in cases where the `useSnaps` is enabled and the user has a Snaps compatible browser | +| apiClientFactory | `HttpApiClient` | Override the function used to create an API client for the XMTP network. If you are running `xmtp-js` on a server, you will want to import [`@xmtp/grpc-api-client`](https://github.com/xmtp/bot-kit-pro) and set this option to `GrpcApiClient.fromOptions` for better performance and reliability | ### Conversations @@ -390,6 +394,14 @@ const clientWithNoCache = await Client.create(wallet, { }) ``` +### Interacting with Snaps + +If the user has a compatible version of MetaMask installed in their browser, and the `useSnaps` `ClientCreateOption` is set to `true`, the SDK will attempt to install and connect to the ["Sign In With XMTP" Snap](https://github.com/xmtp/snap) as part of client creation. If successful, all crytographic operations will happen inside the secure context of the Snap instead of the main browser thread. This offers greater security and a smoother sign-in experience. + +In cases where the Snap is being used, `Client.getKeys()` will fail, as the client application has no access to the private key material when used with Snaps. + +In future versions of `xmtp-js`, this flag will be set with a default of `true`. + ## Breaking revisions Because `xmtp-js` is in active development, you should expect breaking revisions that might require you to adopt the latest SDK release to enable your app to continue working as expected. diff --git a/src/keystore/README.md b/src/keystore/README.md new file mode 100644 index 000000000..230539fbb --- /dev/null +++ b/src/keystore/README.md @@ -0,0 +1,86 @@ +# Keystore + +The Keystore module is responsible for all operations that involve the user's identity keys, pre keys, or conversation keys. + +Keystores are responsible for encrypting, and storing, sensitive key material in their underlying persistence layer. There is a standard API [defined here](./interfaces.ts), with Protocol Buffer message types for serialization. + +## Types of Keystore + +### `InMemoryKeystore` + +This is the default Keystore that ships with `xmtp-js`. It lives inside the SDK and is accessed as a module. It can be configured to persist data with any valid [Persistence Provider](./persistence/interface.ts). The default persistence provider is `LocalStoragePersistence` in the browser and `InMemoryPersistence` in Node.js. + +Here is a diagram of the interactions between the SDK, Keystore, and the XMTP node in this configuration: + +```mermaid +sequenceDiagram + box transparent SDK + Participant C as Client + Participant K as InMemoryKeystore + end + box transparent XMTP Network + Participant N as Node + end + C-->>N: Query for messages on invite topic + N-->>C: QueryResponse + C-->>K: saveInvitesRequest to Keystore + K-->>C: saveInvitesResponse from Keystore +``` + +### SnapKeystore + +The `SnapKeystore` has a slightly different architecture than the `InMemoryKeystore`. When processing a request the `SnapKeystore` client module found in this repository will serialize the request and send it to a MetaMask Snap, which lives inside the MetaMask browser extension. When a response is received it will deserialize it and pass it back to the SDK. + +```mermaid +sequenceDiagram + box transparent SDK + Participant C as Client + Participant K as SnapKeystore Client + end + box transparent MetaMask Snaps + Participant S as SnapKeystore + end + box transparent XMTP Network + Participant N as Node + end + C-->>N: Query for messages on invite topic + N-->>C: QueryResponse + C-->>K: saveInvitesRequest to Keystore + K-->>S: saveInvitesRequest to Snap + S-->>K: saveInvitesResponse to Keystore + K-->>C: saveInvitesResponse from Keystore +``` + +You can learn more about MetaMask Snaps [here](https://docs.metamask.io/snaps/), and see the implementation of the XMTP Snap [here](https://github.com/xmtp/snap). + +#### Installing and upgrading Snaps + +If the `useSnaps` option is enabled, and the user has a compatible version of MetaMask installed in their browser, `xmtp-js` will attempt to install the "Sign in with XMTP" Snap as part of the client creation process. The SDK is responsible for installing or upgrading the correct version of the Snap using the following rules. + +- If no instance of `@xmtp/snap` is already installed, install the version specified in [`snapInfo.json`](../snapInfo.json). This requires the user to accept a confirmation dialog in MetaMask. +- If the currently installed version of `@xmtp/snap` has a higher major version than the version specified in [`snapInfo.json`](../snapInfo.json), (ie. `snapInfo.json` specifies version `1.5` and MetaMask reports that version `2.1` is installed), installation will fail and another Keystore provider will be used. +- If the currently installed version of `@xmtp/snap` is on the same major version, but a lower minor version (for example, `snapInfo.json` specifies `1.6` and MetaMask reports version `1.4` is installed), the SDK will attempt to upgrade the user to the version specified in `snapInfo.json`. This requires the user to accept a confirmation dialog in MetaMask. +- If the currently installed version of `@xmtp/snap` is _higher_ than the version specified in `snapInfo.json`, but is still on the same major version, do nothing and use the currently installed version. It is not possible to downgrade a Snap to a lower version. + +Once the Snap is successfully installed, the SDK will check if the Snap is already storing keys for the current environment and wallet address. A Snap may already have keys stored because the user has already used your application with Snaps enabled in the past, or the user has used any other application using `xmtp-js` with Snaps enabled. + +If the Snap already has keys for the current wallet address and environment, no further action is needed. + +If the Snap does not yet have keys for the user, keys will either be downloaded from the network for the user and decrypted with a wallet signature, or created if it is the user's first time using the XMTP network. + +## Making changes to the Keystore + +Because the Snap lives in a completely different execution environment, and the source code comes from another repository, care must be taken when making changes to the Keystore. + +First, you must decide if your change is breaking or non-breaking. A breaking change is anything that alters the response format from the Keystore API in a way that an older client cannot handle. For example, adding a new method to the Keystore or changing the response type of an existing method. Examples of non-breaking changes include performance enhancements, code cleanup, or additional documentation. + +For non-breaking changes, you can simply commit the change to this repository. + +If the intended change is breaking you will need to design it in a backwards compatible way. For example, instead of changing the response format of an existing Keystore method, create a new method instead and leave the old method in place. + +You will then want to sequence the release as following: + +1. Update the files in the `keystore` folder in a backwards-compatible way, but do not make any changes outside of the Keystore folder. Merge to `main` to create a new release of `@xmtp/xmtp-js`. If you are introducing a new method, make sure to update [`rpcDefinitions.ts`](./rpcDefinitions.ts) +2. Upgrade the `xmtp-js` dependency in `@xmtp/snap` to the newly released version. Usually this will require no other code changes, since the Snap itself is a very thin wrapper around the `InMemoryKeystore` and `rpcDefinitions`. Merge to main to create a new release of `@xmtp/snap` +3. Run `npm run updateSnapVersion` in the root of `xmtp-js` to update the version stored in `snapInfo.json` +4. Make any changes required in the SDK to use your new Keystore method. For example, you may need to update some code to call your new API. Merge to main to create a new release. From 0f1b880cad65a9869b5ac98b1543959a775e6f8e Mon Sep 17 00:00:00 2001 From: Jennifer Hasegawa <5481259+jhaaaa@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:10:19 -0700 Subject: [PATCH 119/137] docs: tw edits to readmes --- README.md | 37 ++++++++++++++++++------------------- src/keystore/README.md | 26 ++++++++++++++------------ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 9d399c4ee..d2a0873a1 100644 --- a/README.md +++ b/README.md @@ -117,22 +117,21 @@ const xmtp = await Client.create(wallet) The client's network connection and key storage method can be configured with these optional parameters of `Client.create`: -| Parameter | Default | Description | -| ------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| appVersion | `undefined` | Add a client app version identifier that's included with API requests.
For example, you can use the following format: `appVersion: APP_NAME + '/' + APP_VERSION`.
Setting this value provides telemetry that shows which apps are using the XMTP client SDK. This information can help XMTP developers provide app support, especially around communicating important SDK updates, including deprecations and required upgrades. | -| env | `dev` | Connect to the specified XMTP network environment. Valid values include `dev`, `production`, or `local`. For important details about working with these environments, see [XMTP `production` and `dev` network environments](https://github.com/xmtp/xmtp-js/blob/main/README.md#xmtp-production-and-dev-network-environments). | -| apiUrl | `undefined` | Manually specify an API URL to use. If specified, value of `env` will be ignored. | -| keystoreProviders | `[StaticKeystoreProvider, NetworkKeystoreProvider, KeyGeneratorKeystoreProvider]` | Override the default behaviour of how the client creates a Keystore with a custom provider. This can be used to get the user's private keys from a different storage mechanism. | -| persistConversations | `true` | Maintain a cache of previously seen V2 conversations in the storage provider (defaults to `LocalStorage`). | -| skipContactPublishing | `false` | Do not publish the user's contact bundle to the network on client creation. Designed to be used in cases where the client session is short-lived (for example, decrypting a push notification), and where it is known that a client instance has been instantiated with this flag set to false at some point in the past. | -| codecs | `[TextCodec]` | Add codecs to support additional content types. | -| maxContentSize | `100M` | Maximum message content size in bytes. | -| preCreateIdentityCallback | `undefined` | `preCreateIdentityCallback` is a function that will be called immediately before a [Create Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-create-an-xmtp-identity) is requested from the user. | -| preEnableIdentityCallback | `undefined` | `preEnableIdentityCallback` is a function that will be called immediately before an [Enable Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-enable-an-xmtp-identity) is requested from the user. | -| useSnaps | `false` | Enabling the `useSnaps` flag will allow the client to attempt to connect to the "Sign in with XMTP" MetaMask Snap as part of client creation. It is safe to enable this flag even if you do not know whether the user has an appropriate MetaMask version enabled. If no compatible version of MetaMask is found, client creation will proceed as if this flag was set to `false`. Read more about Snaps [here](#interacting-with-snaps) | -| basePersistence | `InMemoryPersistence` (Node.js) or `LocalStoragePersistence` (browser) | A persistence provider used by the Keystore to persist its cache of conversations and metadata. Ignored in cases where the `useSnaps` is enabled and the user has a Snaps compatible browser | -| basePersistence | `InMemoryPersistence` (Node.js) or `LocalStoragePersistence` (browser) | A persistence provider used by the Keystore to persist its cache of conversations and metadata. Ignored in cases where the `useSnaps` is enabled and the user has a Snaps compatible browser | -| apiClientFactory | `HttpApiClient` | Override the function used to create an API client for the XMTP network. If you are running `xmtp-js` on a server, you will want to import [`@xmtp/grpc-api-client`](https://github.com/xmtp/bot-kit-pro) and set this option to `GrpcApiClient.fromOptions` for better performance and reliability | +| Parameter | Default | Description | +| ------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| appVersion | `undefined` | Add a client app version identifier that's included with API requests.
For example, you can use the following format: `appVersion: APP_NAME + '/' + APP_VERSION`.
Setting this value provides telemetry that shows which apps are using the XMTP client SDK. This information can help XMTP developers provide app support, especially around communicating important SDK updates, including deprecations and required upgrades. | +| env | `dev` | Connect to the specified XMTP network environment. Valid values include `dev`, `production`, or `local`. For important details about working with these environments, see [XMTP `production` and `dev` network environments](https://github.com/xmtp/xmtp-js/blob/main/README.md#xmtp-production-and-dev-network-environments). | +| apiUrl | `undefined` | Manually specify an API URL to use. If specified, value of `env` will be ignored. | +| keystoreProviders | `[StaticKeystoreProvider, NetworkKeystoreProvider, KeyGeneratorKeystoreProvider]` | Override the default behaviour of how the client creates a Keystore with a custom provider. This can be used to get the user's private keys from a different storage mechanism. | +| persistConversations | `true` | Maintain a cache of previously seen V2 conversations in the storage provider (defaults to `LocalStorage`). | +| skipContactPublishing | `false` | Do not publish the user's contact bundle to the network on client creation. Designed to be used in cases where the client session is short-lived (for example, decrypting a push notification), and where it is known that a client instance has been instantiated with this flag set to false at some point in the past. | +| codecs | `[TextCodec]` | Add codecs to support additional content types. | +| maxContentSize | `100M` | Maximum message content size in bytes. | +| preCreateIdentityCallback | `undefined` | `preCreateIdentityCallback` is a function that will be called immediately before a [Create Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-create-an-xmtp-identity) is requested from the user. | +| preEnableIdentityCallback | `undefined` | `preEnableIdentityCallback` is a function that will be called immediately before an [Enable Identity wallet signature](https://xmtp.org/docs/concepts/account-signatures#sign-to-enable-an-xmtp-identity) is requested from the user. | +| useSnaps | `false` | Enabling the `useSnaps` flag will allow the client to attempt to connect to the "Sign in with XMTP" MetaMask Snap as part of client creation. It is safe to enable this flag even if you do not know whether the user has an appropriate MetaMask version enabled. If no compatible version of MetaMask is found, client creation will proceed as if this flag was set to `false`. To learn more, see [Interacting with Snaps](#interacting-with-snaps). | +| basePersistence | `InMemoryPersistence` (Node.js) or `LocalStoragePersistence` (browser) | A persistence provider used by the Keystore to persist its cache of conversations and metadata. Ignored in cases where the `useSnaps` is enabled and the user has a Snaps-compatible browser. | +| apiClientFactory | `HttpApiClient` | Override the function used to create an API client for the XMTP network. If you are running `xmtp-js` on a server, you will want to import [`@xmtp/grpc-api-client`](https://github.com/xmtp/bot-kit-pro) and set this option to `GrpcApiClient.fromOptions` for better performance and reliability. | ### Conversations @@ -396,11 +395,11 @@ const clientWithNoCache = await Client.create(wallet, { ### Interacting with Snaps -If the user has a compatible version of MetaMask installed in their browser, and the `useSnaps` `ClientCreateOption` is set to `true`, the SDK will attempt to install and connect to the ["Sign In With XMTP" Snap](https://github.com/xmtp/snap) as part of client creation. If successful, all crytographic operations will happen inside the secure context of the Snap instead of the main browser thread. This offers greater security and a smoother sign-in experience. +If the user has a compatible version of MetaMask installed in their browser, and the `useSnaps` `ClientCreateOption` is set to `true`, the SDK will attempt to install and connect to the ["Sign in with XMTP" Snap](https://github.com/xmtp/snap) as part of client creation. If successful, all cryptographic operations will happen inside the secure context of the Snap instead of the main browser thread. This offers greater security and a smoother sign-in experience. -In cases where the Snap is being used, `Client.getKeys()` will fail, as the client application has no access to the private key material when used with Snaps. +In cases where the Snap is being used, `Client.getKeys()` will fail because the client application has no access to the private key material when used with Snaps. -In future versions of `xmtp-js`, this flag will be set with a default of `true`. +Currently, `useSnaps` uses a default value of `false`. However, in future versions of `xmtp-js`, it will be updated to use a default value of `true`. ## Breaking revisions diff --git a/src/keystore/README.md b/src/keystore/README.md index 230539fbb..e1e481c54 100644 --- a/src/keystore/README.md +++ b/src/keystore/README.md @@ -1,10 +1,10 @@ # Keystore -The Keystore module is responsible for all operations that involve the user's identity keys, pre keys, or conversation keys. +The Keystore module is responsible for all operations that involve the user's identity keys, prekeys, or conversation keys. Keystores are responsible for encrypting, and storing, sensitive key material in their underlying persistence layer. There is a standard API [defined here](./interfaces.ts), with Protocol Buffer message types for serialization. -## Types of Keystore +## Types of keystores ### `InMemoryKeystore` @@ -29,7 +29,7 @@ sequenceDiagram ### SnapKeystore -The `SnapKeystore` has a slightly different architecture than the `InMemoryKeystore`. When processing a request the `SnapKeystore` client module found in this repository will serialize the request and send it to a MetaMask Snap, which lives inside the MetaMask browser extension. When a response is received it will deserialize it and pass it back to the SDK. +The `SnapKeystore` has a slightly different architecture than the `InMemoryKeystore`. When processing a request, the `SnapKeystore` client module found in this repository will serialize the request and send it to a MetaMask Snap, which lives inside the MetaMask browser extension. When a response is received, it will deserialize it and pass it back to the SDK. ```mermaid sequenceDiagram @@ -58,7 +58,7 @@ You can learn more about MetaMask Snaps [here](https://docs.metamask.io/snaps/), If the `useSnaps` option is enabled, and the user has a compatible version of MetaMask installed in their browser, `xmtp-js` will attempt to install the "Sign in with XMTP" Snap as part of the client creation process. The SDK is responsible for installing or upgrading the correct version of the Snap using the following rules. - If no instance of `@xmtp/snap` is already installed, install the version specified in [`snapInfo.json`](../snapInfo.json). This requires the user to accept a confirmation dialog in MetaMask. -- If the currently installed version of `@xmtp/snap` has a higher major version than the version specified in [`snapInfo.json`](../snapInfo.json), (ie. `snapInfo.json` specifies version `1.5` and MetaMask reports that version `2.1` is installed), installation will fail and another Keystore provider will be used. +- If the currently installed version of `@xmtp/snap` has a higher major version than the version specified in [`snapInfo.json`](../snapInfo.json), (for example, `snapInfo.json` specifies version `1.5` and MetaMask reports that version `2.1` is installed), installation will fail, and another Keystore provider will be used. - If the currently installed version of `@xmtp/snap` is on the same major version, but a lower minor version (for example, `snapInfo.json` specifies `1.6` and MetaMask reports version `1.4` is installed), the SDK will attempt to upgrade the user to the version specified in `snapInfo.json`. This requires the user to accept a confirmation dialog in MetaMask. - If the currently installed version of `@xmtp/snap` is _higher_ than the version specified in `snapInfo.json`, but is still on the same major version, do nothing and use the currently installed version. It is not possible to downgrade a Snap to a lower version. @@ -66,21 +66,23 @@ Once the Snap is successfully installed, the SDK will check if the Snap is alrea If the Snap already has keys for the current wallet address and environment, no further action is needed. -If the Snap does not yet have keys for the user, keys will either be downloaded from the network for the user and decrypted with a wallet signature, or created if it is the user's first time using the XMTP network. +If the Snap does not yet have keys for the user, keys will either be downloaded from the XMTP network for the user and decrypted with a wallet signature, or created if it is the user's first time using the XMTP network. ## Making changes to the Keystore Because the Snap lives in a completely different execution environment, and the source code comes from another repository, care must be taken when making changes to the Keystore. -First, you must decide if your change is breaking or non-breaking. A breaking change is anything that alters the response format from the Keystore API in a way that an older client cannot handle. For example, adding a new method to the Keystore or changing the response type of an existing method. Examples of non-breaking changes include performance enhancements, code cleanup, or additional documentation. +First, you must decide if your change is non-breaking or breaking. -For non-breaking changes, you can simply commit the change to this repository. +- Non-breaking changes include performance enhancements, code cleanup, or additional documentation. For non-breaking changes, you can simply commit the change to this repository. -If the intended change is breaking you will need to design it in a backwards compatible way. For example, instead of changing the response format of an existing Keystore method, create a new method instead and leave the old method in place. +- Breaking changes are things that alter the response format from the Keystore API in a way that an older client cannot handle. For example, adding a new method to the Keystore or changing the response type of an existing method. -You will then want to sequence the release as following: +If the intended change is breaking, you will need to design it in a backwards-compatible way. For example, instead of changing the response format of an existing Keystore method, create a new method instead and leave the old method in place. -1. Update the files in the `keystore` folder in a backwards-compatible way, but do not make any changes outside of the Keystore folder. Merge to `main` to create a new release of `@xmtp/xmtp-js`. If you are introducing a new method, make sure to update [`rpcDefinitions.ts`](./rpcDefinitions.ts) -2. Upgrade the `xmtp-js` dependency in `@xmtp/snap` to the newly released version. Usually this will require no other code changes, since the Snap itself is a very thin wrapper around the `InMemoryKeystore` and `rpcDefinitions`. Merge to main to create a new release of `@xmtp/snap` -3. Run `npm run updateSnapVersion` in the root of `xmtp-js` to update the version stored in `snapInfo.json` +You will then want to sequence the release as follows: + +1. Update the files in the `keystore` folder in a backwards-compatible way, but do not make any changes outside of the Keystore folder. Merge to `main` to create a new release of `@xmtp/xmtp-js`. If you are introducing a new method, make sure to update [`rpcDefinitions.ts`](./rpcDefinitions.ts). +2. Upgrade the `xmtp-js` dependency in `@xmtp/snap` to the newly released version. Usually this will require no other code changes, since the Snap itself is a very thin wrapper around the `InMemoryKeystore` and `rpcDefinitions`. Merge to main to create a new release of `@xmtp/snap`. +3. Run `npm run updateSnapVersion` in the root of `xmtp-js` to update the version stored in `snapInfo.json`. 4. Make any changes required in the SDK to use your new Keystore method. For example, you may need to update some code to call your new API. Merge to main to create a new release. From 91e5e7b47444a411f8dcadf6dc90201b321f8811 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:36:11 -0700 Subject: [PATCH 120/137] feat: add strong typing to client --- src/Client.ts | 85 +++++++++++++++++++----- src/Message.ts | 68 ++++++------------- src/conversations/Conversation.ts | 87 +++++++++++-------------- src/conversations/Conversations.ts | 59 +++++++++-------- src/index.ts | 8 +-- test/Client.test.ts | 2 +- test/Message.test.ts | 3 + test/conversations/Conversation.test.ts | 18 ++--- 8 files changed, 174 insertions(+), 156 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 7e4e1912e..37b777375 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -11,8 +11,8 @@ import { utils } from 'ethers' import { Signer } from './types/Signer' import { Conversations } from './conversations' import { ContentTypeText, TextCodec } from './codecs/Text' -import { ContentTypeId, ContentCodec } from './MessageContent' -import { compress } from './Compression' +import { ContentTypeId, ContentCodec, EncodedContent } from './MessageContent' +import { compress, decompress } from './Compression' import { content as proto, messageApi } from '@xmtp/proto' import { decodeContactBundle, encodeContactBundle } from './ContactBundle' import HttpApiClient, { @@ -41,6 +41,7 @@ import { } from './keystore/persistence' import { hasMetamaskWithSnaps } from './keystore/snapHelpers' import { version as snapVersion, package as snapPackage } from './snapInfo.json' +import { CompositeCodec } from './codecs/Composite' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types @@ -203,6 +204,8 @@ export type ClientOptions = Flatten< PreEventCallbackOptions > +export type ExtractDecodedType = C extends ContentCodec ? T : never + /** * Provide a default client configuration. These settings can be used on their own, or as a starting point for custom configurations * @@ -244,7 +247,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { * Client class initiates connection to the XMTP network. * Should be created with `await Client.create(options)` */ -export default class Client { +export default class Client { address: string keystore: Keystore apiClient: ApiClient @@ -256,7 +259,7 @@ export default class Client { > // addresses and key bundles that we have witnessed private _backupClient: BackupClient - private readonly _conversations: Conversations + private readonly _conversations: Conversations // eslint-disable-next-line @typescript-eslint/no-explicit-any private _codecs: Map> private _maxContentSize: number @@ -286,7 +289,7 @@ export default class Client { /** * @type {Conversations} */ - get conversations(): Conversations { + get conversations(): Conversations { return this._conversations } @@ -304,10 +307,10 @@ export default class Client { * @param wallet the wallet as a Signer instance * @param opts specify how to to connect to the network */ - static async create( + static async create[]>( wallet: Signer | null, - opts?: Partial - ): Promise { + opts?: Partial & { codecs?: U } + ): Promise>> { const options = defaultOptions(opts) const apiClient = options.apiClientFactory(options) const keystore = await bootstrapKeystore(options, apiClient, wallet) @@ -317,7 +320,7 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) - const client = new Client( + const client = new Client>( publicKeyBundle, apiClient, backupClient, @@ -337,9 +340,9 @@ export default class Client { * impersonate a user on the XMTP network and read the user's * messages. */ - static async getKeys( + static async getKeys( wallet: Signer | null, - opts?: Partial + opts?: Partial & { codecs?: U } ): Promise { const client = await Client.create(wallet, opts) const keys = await client.keystore.getPrivateKeyBundle() @@ -623,11 +626,7 @@ export default class Client { * Convert arbitrary content into a serialized `EncodedContent` instance * with the given options */ - async encodeContent( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - content: any, - options?: SendOptions - ): Promise { + async encodeContent(content: T, options?: SendOptions): Promise { const contentType = options?.contentType || ContentTypeText const codec = this.codecFor(contentType) if (!codec) { @@ -646,6 +645,39 @@ export default class Client { return proto.EncodedContent.encode(encoded).finish() } + async decodeContent(contentBytes: Uint8Array): Promise<{ + content: T + contentType: ContentTypeId + error?: Error + contentFallback?: string + }> { + const encodedContent = proto.EncodedContent.decode(contentBytes) + + if (!encodedContent.type) { + throw new Error('missing content type') + } + + let content: any // eslint-disable-line @typescript-eslint/no-explicit-any + const contentType = new ContentTypeId(encodedContent.type) + let error: Error | undefined + + await decompress(encodedContent, 1000) + + const codec = this.codecFor(contentType) + if (codec) { + content = codec.decode(encodedContent as EncodedContent, this) + } else { + error = new Error('unknown content type ' + contentType) + } + + return { + content, + contentType, + error, + contentFallback: encodedContent.fallback, + } + } + listInvitations(opts?: ListMessagesOptions): Promise { return this.listEnvelopes( buildUserInviteTopic(this.address), @@ -714,6 +746,8 @@ export default class Client { } } +export type AnyClient = Client[]> + function createHttpApiClientFromOptions(options: NetworkOptions): ApiClient { const apiUrl = options.apiUrl || ApiUrls[options.env] return new HttpApiClient(apiUrl, { appVersion: options.appVersion }) @@ -829,3 +863,22 @@ async function bootstrapKeystore( } throw new Error('No keystore providers available') } + +export type ClientReturnType = C extends Client ? T : never + +// async function stronglyTypedClient() { +// const c = await Client.create(null, { +// codecs: [new CompositeCodec(), new TextCodec()], +// }) + +// const convos = await c.conversations.list() +// convos[0].send('hello') +// convos[0].send(123) + +// for await (const msg of await convos[0].streamMessages()) { +// // Let's see what content type this is? +// // +// // +// console.log(msg.content) +// } +// } diff --git a/src/Message.ts b/src/Message.ts index 552f6dcd2..f149df522 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -15,6 +15,7 @@ import { PublicKeyBundle, PublicKey } from './crypto' import { bytesToHex } from './crypto/utils' import { sha256 } from './crypto/encryption' import { + ContentCodec, ContentTypeFallback, ContentTypeId, EncodedContent, @@ -23,6 +24,7 @@ import { dateToNs, nsToDate } from './utils' import { decompress } from './Compression' import { Keystore } from './keystore' import { buildDecryptV1Request, getResultOrThrow } from './utils/keystore' +import { AnyClient, ClientReturnType } from './Client' const headerBytesAndCiphertext = ( msg: proto.Message @@ -228,16 +230,16 @@ export class MessageV2 extends MessageBase implements proto.MessageV2 { export type Message = MessageV1 | MessageV2 -export class DecodedMessage { +export class DecodedMessage { id: string messageVersion: 'v1' | 'v2' senderAddress: string recipientAddress?: string sent: Date contentTopic: string - conversation: Conversation + conversation: Conversation contentType: ContentTypeId - content: any // eslint-disable-line @typescript-eslint/no-explicit-any + content: T // eslint-disable-line @typescript-eslint/no-explicit-any error?: Error contentBytes: Uint8Array contentFallback?: string @@ -255,7 +257,7 @@ export class DecodedMessage { sent, error, contentFallback, - }: Omit) { + }: Omit, 'toBytes'>) { this.id = id this.messageVersion = messageVersion this.senderAddress = senderAddress @@ -283,10 +285,10 @@ export class DecodedMessage { }).finish() } - static async fromBytes( + static async fromBytes( data: Uint8Array, - client: Client - ): Promise { + client: Client + ): Promise>> { const protoVal = proto.DecodedMessage.decode(data) const messageVersion = protoVal.messageVersion @@ -299,7 +301,7 @@ export class DecodedMessage { } const { content, contentType, error, contentFallback } = - await decodeContent(protoVal.contentBytes, client) + await client.decodeContent(protoVal.contentBytes) return new DecodedMessage({ ...protoVal, @@ -317,16 +319,16 @@ export class DecodedMessage { }) } - static fromV1Message( + static fromV1Message( message: MessageV1, - content: any, // eslint-disable-line @typescript-eslint/no-explicit-any + content: T, // eslint-disable-line @typescript-eslint/no-explicit-any contentType: ContentTypeId, contentBytes: Uint8Array, contentTopic: string, - conversation: Conversation, + conversation: Conversation, error?: Error, contentFallback?: string - ): DecodedMessage { + ): DecodedMessage { const { id, senderAddress, recipientAddress, sent } = message if (!senderAddress) { throw new Error('Sender address is required') @@ -347,17 +349,17 @@ export class DecodedMessage { }) } - static fromV2Message( + static fromV2Message( message: MessageV2, content: any, // eslint-disable-line @typescript-eslint/no-explicit-any contentType: ContentTypeId, contentTopic: string, contentBytes: Uint8Array, - conversation: Conversation, + conversation: Conversation, senderAddress: string, error?: Error, contentFallback?: string - ): DecodedMessage { + ): DecodedMessage { const { id, sent } = message return new DecodedMessage({ @@ -376,39 +378,11 @@ export class DecodedMessage { } } -export async function decodeContent(contentBytes: Uint8Array, client: Client) { - const encodedContent = protoContent.EncodedContent.decode(contentBytes) - - if (!encodedContent.type) { - throw new Error('missing content type') - } - - let content: any // eslint-disable-line @typescript-eslint/no-explicit-any - const contentType = new ContentTypeId(encodedContent.type) - let error: Error | undefined - - await decompress(encodedContent, 1000) - - const codec = client.codecFor(contentType) - if (codec) { - content = codec.decode(encodedContent as EncodedContent, client) - } else { - error = new Error('unknown content type ' + contentType) - } - - return { - content, - contentType, - error, - contentFallback: encodedContent.fallback, - } -} - -function conversationReferenceToConversation( +function conversationReferenceToConversation( reference: conversationReference.ConversationReference, - client: Client, - version: DecodedMessage['messageVersion'] -): Conversation { + client: Client, + version: DecodedMessage>['messageVersion'] +): Conversation { if (version === 'v1') { return new ConversationV1( client, diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 206009560..b32f9ffc9 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -14,7 +14,7 @@ import Client, { SendOptions, } from '../Client' import { InvitationContext } from '../Invitation' -import { DecodedMessage, MessageV1, MessageV2, decodeContent } from '../Message' +import { DecodedMessage, MessageV1, MessageV2 } from '../Message' import { messageApi, message, @@ -33,12 +33,10 @@ import { sha256 } from '../crypto/encryption' import { buildDecryptV1Request, getResultOrThrow } from '../utils/keystore' import { ContentTypeText } from '../codecs/Text' -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ - /** * Conversation represents either a V1 or V2 conversation with a common set of methods. */ -export interface Conversation { +export interface Conversation { conversationVersion: 'v1' | 'v2' /** * The wallet address connected to the client @@ -80,18 +78,18 @@ export interface Conversation { * }) * ``` */ - messages(opts?: ListMessagesOptions): Promise + messages(opts?: ListMessagesOptions): Promise[]> /** * @deprecated */ messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator + ): AsyncGenerator[]> /** * Takes a XMTP envelope as input and will decrypt and decode it * returning a `DecodedMessage` instance. */ - decodeMessage(env: messageApi.Envelope): Promise + decodeMessage(env: messageApi.Envelope): Promise> /** * Return a `Stream` of new messages in this conversation. * @@ -104,7 +102,7 @@ export interface Conversation { * } * ``` */ - streamMessages(): Promise> + streamMessages(): Promise>> /** * Send a message into the conversation * @@ -113,10 +111,7 @@ export interface Conversation { * await conversation.send('Hello world') // returns a `DecodedMessage` instance * ``` */ - send( - content: any, // eslint-disable-line @typescript-eslint/no-explicit-any - options?: SendOptions - ): Promise + send(content: T, options?: SendOptions): Promise> /** * Return a `PreparedMessage` that has contains the message ID @@ -140,20 +135,20 @@ export interface Conversation { * } * ``` */ - streamEphemeral(): Promise> + streamEphemeral(): Promise>> } /** * ConversationV1 allows you to view, stream, and send messages to/from a peer address */ -export class ConversationV1 implements Conversation { +export class ConversationV1 implements Conversation { conversationVersion = 'v1' as const peerAddress: string createdAt: Date context = undefined - private client: Client + private client: Client - constructor(client: Client, address: string, createdAt: Date) { + constructor(client: Client, address: string, createdAt: Date) { this.peerAddress = utils.getAddress(address) this.client = client this.createdAt = createdAt @@ -177,7 +172,7 @@ export class ConversationV1 implements Conversation { /** * Returns a list of all messages to/from the peerAddress */ - async messages(opts?: ListMessagesOptions): Promise { + async messages(opts?: ListMessagesOptions): Promise[]> { const topic = buildDirectMessageTopic(this.peerAddress, this.client.address) const messages = await this.client.listEnvelopes( topic, @@ -190,7 +185,7 @@ export class ConversationV1 implements Conversation { messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator { + ): AsyncGenerator[]> { return this.client.listEnvelopesPaginated( this.topic, // This won't be performant once we start supporting a remote keystore @@ -201,7 +196,7 @@ export class ConversationV1 implements Conversation { } // decodeMessage takes an envelope and either returns a `DecodedMessage` or throws if an error occurs - async decodeMessage(env: messageApi.Envelope): Promise { + async decodeMessage(env: messageApi.Envelope): Promise> { if (!env.contentTopic) { throw new Error('Missing content topic') } @@ -265,8 +260,8 @@ export class ConversationV1 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise> { - return Stream.create( + ): Promise>> { + return Stream.create>( this.client, [this.topic], async (env: messageApi.Envelope) => this.decodeMessage(env), @@ -300,8 +295,8 @@ export class ConversationV1 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise> { - return Stream.create( + ): Promise>> { + return Stream.create>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -313,10 +308,7 @@ export class ConversationV1 implements Conversation { /** * Send a message into the conversation. */ - async send( - content: any, // eslint-disable-line @typescript-eslint/no-explicit-any - options?: SendOptions - ): Promise { + async send(content: T, options?: SendOptions): Promise> { let topics: string[] let recipient = await this.client.getUserContact(this.peerAddress) if (!recipient) { @@ -364,14 +356,14 @@ export class ConversationV1 implements Conversation { messages: MessageV1[], topic: string, throwOnError = false - ): Promise { + ): Promise[]> { const responses = ( await this.client.keystore.decryptV1( buildDecryptV1Request(messages, this.client.publicKeyBundle) ) ).responses - const out: DecodedMessage[] = [] + const out: DecodedMessage[] = [] for (let i = 0; i < responses.length; i++) { const result = responses[i] const message = messages[i] @@ -393,9 +385,9 @@ export class ConversationV1 implements Conversation { message: MessageV1, decrypted: Uint8Array, topic: string - ): Promise { + ): Promise> { const { content, contentType, error, contentFallback } = - await decodeContent(decrypted, this.client) + await this.client.decodeContent(decrypted) return DecodedMessage.fromV1Message( message, @@ -430,16 +422,16 @@ export class ConversationV1 implements Conversation { /** * ConversationV2 */ -export class ConversationV2 implements Conversation { +export class ConversationV2 implements Conversation { conversationVersion = 'v2' as const - client: Client + client: Client topic: string peerAddress: string createdAt: Date context?: InvitationContext constructor( - client: Client, + client: Client, topic: string, peerAddress: string, createdAt: Date, @@ -459,7 +451,7 @@ export class ConversationV2 implements Conversation { /** * Returns a list of all messages to/from the peerAddress */ - async messages(opts?: ListMessagesOptions): Promise { + async messages(opts?: ListMessagesOptions): Promise[]> { const messages = await this.client.listEnvelopes( this.topic, this.processEnvelope.bind(this), @@ -471,7 +463,7 @@ export class ConversationV2 implements Conversation { messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator { + ): AsyncGenerator[]> { return this.client.listEnvelopesPaginated( this.topic, this.decodeMessage.bind(this), @@ -485,8 +477,8 @@ export class ConversationV2 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise> { - return Stream.create( + ): Promise>> { + return Stream.create>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -500,8 +492,8 @@ export class ConversationV2 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise> { - return Stream.create( + ): Promise>> { + return Stream.create>( this.client, [this.topic], this.decodeMessage.bind(this), @@ -513,10 +505,7 @@ export class ConversationV2 implements Conversation { /** * Send a message into the conversation */ - async send( - content: any, // eslint-disable-line @typescript-eslint/no-explicit-any - options?: SendOptions - ): Promise { + async send(content: T, options?: SendOptions): Promise> { const payload = await this.client.encodeContent(content, options) const msg = await this.createMessage(payload, options?.timestamp) @@ -582,12 +571,12 @@ export class ConversationV2 implements Conversation { private async decryptBatch( messages: MessageV2[], throwOnError = false - ): Promise { + ): Promise[]> { const responses = ( await this.client.keystore.decryptV2(this.buildDecryptRequest(messages)) ).responses - const out: DecodedMessage[] = [] + const out: DecodedMessage[] = [] for (let i = 0; i < responses.length; i++) { const result = responses[i] const message = messages[i] @@ -643,7 +632,7 @@ export class ConversationV2 implements Conversation { private async buildDecodedMessage( msg: MessageV2, decrypted: Uint8Array - ): Promise { + ): Promise> { // Decode the decrypted bytes into SignedContent const signed = proto.SignedContent.decode(decrypted) if ( @@ -673,7 +662,7 @@ export class ConversationV2 implements Conversation { ).walletSignatureAddress() const { content, contentType, error, contentFallback } = - await decodeContent(signed.payload, this.client) + await this.client.decodeContent(signed.payload) return DecodedMessage.fromV2Message( msg, @@ -732,7 +721,7 @@ export class ConversationV2 implements Conversation { return MessageV2.create(msg, header, env.message) } - async decodeMessage(env: messageApi.Envelope): Promise { + async decodeMessage(env: messageApi.Envelope): Promise> { if (!env.contentTopic) { throw new Error('Missing content topic') } diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index fcecf711f..7198a5853 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -28,12 +28,12 @@ const messageHasHeaders = (msg: MessageV1): boolean => { /** * Conversations allows you to view ongoing 1:1 messaging sessions with another wallet */ -export default class Conversations { - private client: Client +export default class Conversations { + private client: Client private v1JobRunner: JobRunner private v2JobRunner: JobRunner - constructor(client: Client) { + constructor(client: Client) { this.client = client this.v1JobRunner = new JobRunner('v1', client.keystore) this.v2JobRunner = new JobRunner('v2', client.keystore) @@ -42,7 +42,7 @@ export default class Conversations { /** * List all conversations with the current wallet found in the network. */ - async list(): Promise { + async list(): Promise[]> { const [v1Convos, v2Convos] = await Promise.all([ this.listV1Conversations(), this.listV2Conversations(), @@ -58,8 +58,8 @@ export default class Conversations { * List all conversations stored in the client cache, which may not include * conversations on the network. */ - async listFromCache(): Promise { - const [v1Convos, v2Convos]: Conversation[][] = await Promise.all([ + async listFromCache(): Promise[]> { + const [v1Convos, v2Convos]: Conversation[][] = await Promise.all([ this.getV1ConversationsFromKeystore(), this.getV2ConversationsFromKeystore(), ]) @@ -69,7 +69,7 @@ export default class Conversations { return conversations } - private async listV1Conversations(): Promise { + private async listV1Conversations(): Promise[]> { return this.v1JobRunner.run(async (latestSeen) => { const seenPeers = await this.getIntroductionPeers({ startTime: latestSeen @@ -98,7 +98,7 @@ export default class Conversations { /** * List all V2 conversations */ - private async listV2Conversations(): Promise { + private async listV2Conversations(): Promise[]> { return this.v2JobRunner.run(async (lastRun) => { // Get all conversations already in the KeyStore const existing = await this.getV2ConversationsFromKeystore() @@ -121,20 +121,20 @@ export default class Conversations { }) } - private async getV2ConversationsFromKeystore(): Promise { + private async getV2ConversationsFromKeystore(): Promise[]> { return (await this.client.keystore.getV2Conversations()).conversations.map( this.conversationReferenceToV2.bind(this) ) } - private async getV1ConversationsFromKeystore(): Promise { + private async getV1ConversationsFromKeystore(): Promise[]> { return (await this.client.keystore.getV1Conversations()).conversations.map( this.conversationReferenceToV1.bind(this) ) } // Called in listV2Conversations and in newConversation - async updateV2Conversations(startTime?: Date): Promise { + async updateV2Conversations(startTime?: Date): Promise[]> { const envelopes = await this.client.listInvitations({ startTime: startTime ? new Date(+startTime - CLOCK_SKEW_OFFSET_MS) @@ -148,7 +148,7 @@ export default class Conversations { private async decodeInvites( envelopes: messageApi.Envelope[], shouldThrow = false - ): Promise { + ): Promise[]> { const { responses } = await this.client.keystore.saveInvites({ requests: envelopes.map((env) => ({ payload: env.message as Uint8Array, @@ -157,7 +157,7 @@ export default class Conversations { })), }) - const out: ConversationV2[] = [] + const out: ConversationV2[] = [] for (const response of responses) { try { out.push(this.saveInviteResponseToConversation(response)) @@ -174,7 +174,7 @@ export default class Conversations { private saveInviteResponseToConversation({ result, error, - }: keystore.SaveInvitesResponse_Response): ConversationV2 { + }: keystore.SaveInvitesResponse_Response): ConversationV2 { if (error || !result || !result.conversation) { throw new Error(`Error from keystore: ${error?.code} ${error?.message}}`) } @@ -183,7 +183,7 @@ export default class Conversations { private conversationReferenceToV2( convoRef: conversationReference.ConversationReference - ): ConversationV2 { + ): ConversationV2 { return new ConversationV2( this.client, convoRef.topic, @@ -195,7 +195,7 @@ export default class Conversations { private conversationReferenceToV1( convoRef: conversationReference.ConversationReference - ): ConversationV1 { + ): ConversationV1 { return new ConversationV1( this.client, convoRef.peerAddress, @@ -210,7 +210,7 @@ export default class Conversations { */ async stream( onConnectionLost?: OnConnectionLostCallback - ): Promise> { + ): Promise>> { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) @@ -249,7 +249,7 @@ export default class Conversations { const topics = [introTopic, inviteTopic] - return Stream.create( + return Stream.create>( this.client, topics, decodeConversation.bind(this), @@ -267,13 +267,13 @@ export default class Conversations { */ async streamAllMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise> { + ): Promise>> { const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) const topics = new Set([introTopic, inviteTopic]) - const convoMap = new Map() + const convoMap = new Map>() for (const conversation of await this.list()) { topics.add(conversation.topic) @@ -282,7 +282,7 @@ export default class Conversations { const decodeMessage = async ( env: messageApi.Envelope - ): Promise => { + ): Promise | DecodedMessage | null> => { const contentTopic = env.contentTopic if (!contentTopic || !env.message) { return null @@ -331,7 +331,10 @@ export default class Conversations { throw new Error('Unknown topic') } - const addConvo = (topic: string, conversation: Conversation): boolean => { + const addConvo = ( + topic: string, + conversation: Conversation + ): boolean => { if (topics.has(topic)) { return false } @@ -340,7 +343,9 @@ export default class Conversations { return true } - const contentTopicUpdater = (msg: Conversation | DecodedMessage | null) => { + const contentTopicUpdater = ( + msg: Conversation | DecodedMessage | null + ) => { // If we have a V1 message from the introTopic, store the conversation in our mapping if (msg instanceof DecodedMessage && msg.contentTopic === introTopic) { const convo = new ConversationV1( @@ -364,7 +369,7 @@ export default class Conversations { return undefined } - const str = await Stream.create( + const str = await Stream.create | Conversation | null>( this.client, Array.from(topics.values()), decodeMessage, @@ -438,7 +443,7 @@ export default class Conversations { async newConversation( peerAddress: string, context?: InvitationContext - ): Promise { + ): Promise> { let contact = await this.client.getUserContact(peerAddress) if (!contact) { throw new Error(`Recipient ${peerAddress} is not on the XMTP network`) @@ -485,7 +490,7 @@ export default class Conversations { } // Define a function for matching V2 conversations - const matcherFn = (convo: Conversation) => + const matcherFn = (convo: Conversation) => convo.peerAddress === peerAddress && isMatchingContext(context, convo.context ?? undefined) @@ -510,7 +515,7 @@ export default class Conversations { private async createV2Convo( recipient: SignedPublicKeyBundle, context?: InvitationContext - ): Promise { + ): Promise> { const timestamp = new Date() const { payload, conversation } = await this.client.keystore.createInvite({ recipient, diff --git a/src/index.ts b/src/index.ts index f95944315..7a1110f3a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,4 @@ -export { - Message, - DecodedMessage, - decodeContent, - MessageV1, - MessageV2, -} from './Message' +export { Message, DecodedMessage, MessageV1, MessageV2 } from './Message' export { Ciphertext, PublicKey, diff --git a/test/Client.test.ts b/test/Client.test.ts index c3773d227..49ff23170 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -25,7 +25,7 @@ import LocalStoragePonyfill from '../src/keystore/persistence/LocalStoragePonyfi type TestCase = { name: string - newClient: (opts?: Partial) => Promise + newClient: (opts?: Partial) => Promise> } const mockEthRequest = jest.fn() diff --git a/test/Message.test.ts b/test/Message.test.ts index 6ab26a2c4..16b7b09f6 100644 --- a/test/Message.test.ts +++ b/test/Message.test.ts @@ -248,6 +248,9 @@ describe('Message', function () { sentMessageBytes, aliceClient ) + if (typeof aliceRestoredMessage.content === 'string') { + throw new Error('Expected content to be a PublicKeyBundle') + } expect( equalBytes( aliceRestoredMessage.content?.secp256k1Uncompressed.bytes, diff --git a/test/conversations/Conversation.test.ts b/test/conversations/Conversation.test.ts index 6ef97bea7..665e41556 100644 --- a/test/conversations/Conversation.test.ts +++ b/test/conversations/Conversation.test.ts @@ -80,7 +80,7 @@ describe('conversation', () => { expect(messageIds.size).toBe(10) // Test sorting - let lastMessage: DecodedMessage | undefined = undefined + let lastMessage: DecodedMessage | undefined = undefined for await (const page of aliceConversation.messagesPaginated({ direction: SortDirection.SORT_DIRECTION_DESCENDING, })) { @@ -408,7 +408,7 @@ describe('conversation', () => { alice.keystore = aliceKeystore await aliceConvo.send('Hello from Alice') const result = await stream.next() - const msg = result.value as DecodedMessage + const msg = result.value expect(msg.senderAddress).toBe(alice.address) expect(msg.content).toBe('Hello from Alice') await stream.return() @@ -437,11 +437,11 @@ describe('conversation', () => { }) const aliceResult1 = await aliceStream.next() - const aliceMessage1 = aliceResult1.value as DecodedMessage + const aliceMessage1 = aliceResult1.value expect(aliceMessage1.content).toEqual(key) const bobResult1 = await bobStream.next() - const bobMessage1 = bobResult1.value as DecodedMessage + const bobMessage1 = bobResult1.value expect(bobMessage1).toBeTruthy() expect(bobMessage1.error?.message).toBe( 'unknown content type xmtp.test/public-key:1.0' @@ -457,7 +457,7 @@ describe('conversation', () => { contentType: ContentTypeTestKey, }) const bobResult2 = await bobStream.next() - const bobMessage2 = bobResult2.value as DecodedMessage + const bobMessage2 = bobResult2.value expect(bobMessage2.contentType).toBeTruthy() expect(bobMessage2.contentType.sameAs(ContentTypeTestKey)).toBeTruthy() expect(key.equals(bobMessage2.content)).toBeTruthy() @@ -603,7 +603,7 @@ describe('conversation', () => { ) await sleep(100) - const firstMessageFromStream: DecodedMessage = (await stream.next()).value + const firstMessageFromStream = (await stream.next()).value expect(firstMessageFromStream.messageVersion).toBe('v2') expect(firstMessageFromStream.content).toBe('foo') expect(firstMessageFromStream.conversation.context?.conversationId).toBe( @@ -675,11 +675,11 @@ describe('conversation', () => { }) const aliceResult1 = await aliceStream.next() - const aliceMessage1 = aliceResult1.value as DecodedMessage + const aliceMessage1 = aliceResult1.value expect(aliceMessage1.content).toEqual(key) const bobResult1 = await bobStream.next() - const bobMessage1 = bobResult1.value as DecodedMessage + const bobMessage1 = bobResult1.value expect(bobMessage1).toBeTruthy() expect(bobMessage1.error?.message).toBe( 'unknown content type xmtp.test/public-key:1.0' @@ -695,7 +695,7 @@ describe('conversation', () => { contentType: ContentTypeTestKey, }) const bobResult2 = await bobStream.next() - const bobMessage2 = bobResult2.value as DecodedMessage + const bobMessage2 = bobResult2.value expect(bobMessage2.contentType).toBeTruthy() expect(bobMessage2.contentType.sameAs(ContentTypeTestKey)).toBeTruthy() expect(key.equals(bobMessage2.content)).toBeTruthy() From da8daab146acf6339f68de331b8fec363e9009da Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:36:30 -0700 Subject: [PATCH 121/137] chore: remove test function --- src/Client.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 37b777375..5309a2eef 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -865,20 +865,3 @@ async function bootstrapKeystore( } export type ClientReturnType = C extends Client ? T : never - -// async function stronglyTypedClient() { -// const c = await Client.create(null, { -// codecs: [new CompositeCodec(), new TextCodec()], -// }) - -// const convos = await c.conversations.list() -// convos[0].send('hello') -// convos[0].send(123) - -// for await (const msg of await convos[0].streamMessages()) { -// // Let's see what content type this is? -// // -// // -// console.log(msg.content) -// } -// } From 296ef66dc279ba8fedb1b0ac466f2d696a316806 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:37:43 -0700 Subject: [PATCH 122/137] chore: remove unused import --- src/Client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Client.ts b/src/Client.ts index 5309a2eef..c1f58fb0f 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -41,7 +41,6 @@ import { } from './keystore/persistence' import { hasMetamaskWithSnaps } from './keystore/snapHelpers' import { version as snapVersion, package as snapPackage } from './snapInfo.json' -import { CompositeCodec } from './codecs/Composite' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types From c3ab592fd422379253c9984bee153dfa4acc6ad4 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:59:03 -0700 Subject: [PATCH 123/137] chore: add eslint ignore --- src/Client.ts | 3 ++- src/Message.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index c1f58fb0f..bd6ea062f 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -246,6 +246,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { * Client class initiates connection to the XMTP network. * Should be created with `await Client.create(options)` */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export default class Client { address: string keystore: Keystore @@ -319,7 +320,7 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) - const client = new Client>( + const client = new Client( publicKeyBundle, apiClient, backupClient, diff --git a/src/Message.ts b/src/Message.ts index f149df522..0f6abe6f0 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -230,7 +230,7 @@ export class MessageV2 extends MessageBase implements proto.MessageV2 { export type Message = MessageV1 | MessageV2 -export class DecodedMessage { +export class DecodedMessage { id: string messageVersion: 'v1' | 'v2' senderAddress: string From 8f945d6bf7394fca6e0fa857a767328da3cc5673 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:04:58 -0700 Subject: [PATCH 124/137] chore: lint --- src/Client.ts | 4 ++-- src/Message.ts | 16 +++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index bd6ea062f..5520d293c 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -307,6 +307,8 @@ export default class Client { * @param wallet the wallet as a Signer instance * @param opts specify how to to connect to the network */ + + // eslint-disable-next-line @typescript-eslint/no-explicit-any static async create[]>( wallet: Signer | null, opts?: Partial & { codecs?: U } @@ -746,8 +748,6 @@ export default class Client { } } -export type AnyClient = Client[]> - function createHttpApiClientFromOptions(options: NetworkOptions): ApiClient { const apiUrl = options.apiUrl || ApiUrls[options.env] return new HttpApiClient(apiUrl, { appVersion: options.appVersion }) diff --git a/src/Message.ts b/src/Message.ts index 0f6abe6f0..1470132e5 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -4,27 +4,17 @@ import { ConversationV2, } from './conversations/Conversation' import type Client from './Client' -import { - message as proto, - content as protoContent, - conversationReference, -} from '@xmtp/proto' +import { message as proto, conversationReference } from '@xmtp/proto' import Long from 'long' import Ciphertext from './crypto/Ciphertext' import { PublicKeyBundle, PublicKey } from './crypto' import { bytesToHex } from './crypto/utils' import { sha256 } from './crypto/encryption' -import { - ContentCodec, - ContentTypeFallback, - ContentTypeId, - EncodedContent, -} from './MessageContent' +import { ContentTypeId } from './MessageContent' import { dateToNs, nsToDate } from './utils' -import { decompress } from './Compression' import { Keystore } from './keystore' import { buildDecryptV1Request, getResultOrThrow } from './utils/keystore' -import { AnyClient, ClientReturnType } from './Client' +import { ClientReturnType } from './Client' const headerBytesAndCiphertext = ( msg: proto.Message From 736c3a6c95a7c53f1413e9dee7fedbfb5e60789b Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:23:38 -0700 Subject: [PATCH 125/137] chore: export decodeContent again --- src/Message.ts | 4 ++++ src/index.ts | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Message.ts b/src/Message.ts index 1470132e5..8c27a7e44 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -391,3 +391,7 @@ function conversationReferenceToConversation( } throw new Error(`Unknown conversation version ${version}`) } + +export function decodeContent(contentBytes: Uint8Array, client: Client) { + return client.decodeContent(contentBytes) +} diff --git a/src/index.ts b/src/index.ts index 7a1110f3a..cbf0326d7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,10 @@ -export { Message, DecodedMessage, MessageV1, MessageV2 } from './Message' +export { + Message, + DecodedMessage, + MessageV1, + MessageV2, + decodeContent, +} from './Message' export { Ciphertext, PublicKey, From 9727f3c1b50f6dde56bea1662d67d9a7293ced12 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:35:33 -0700 Subject: [PATCH 126/137] test: add some tests for type assertions --- src/Client.ts | 5 ++--- test/Client.test.ts | 37 +++++++++++++++++++++++++++++++++++++ test/helpers.ts | 8 +++----- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 5520d293c..6b7f0f734 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -308,8 +308,7 @@ export default class Client { * @param opts specify how to to connect to the network */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static async create[]>( + static async create[] = []>( wallet: Signer | null, opts?: Partial & { codecs?: U } ): Promise>> { @@ -322,7 +321,7 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) - const client = new Client( + const client = new Client>( publicKeyBundle, apiClient, backupClient, diff --git a/test/Client.test.ts b/test/Client.test.ts index 49ff23170..db4462270 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -10,10 +10,13 @@ import { buildUserContactTopic } from '../src/utils' import Client, { ClientOptions } from '../src/Client' import { ApiUrls, + CompositeCodec, Compression, + ContentTypeText, HttpApiClient, InMemoryPersistence, PublishParams, + TextCodec, } from '../src' import NetworkKeyManager from '../src/keystore/providers/NetworkKeyManager' import TopicPersistence from '../src/keystore/persistence/TopicPersistence' @@ -342,6 +345,40 @@ describe('ClientOptions', () => { }) }) + describe('custom codecs', () => { + it('gives type errors when you use the wrong types', async () => { + const client = await Client.create(newWallet()) + const other = await newLocalHostClient() + const convo = await client.conversations.newConversation(other.address) + expect(convo).toBeTruthy() + try { + // Add ts-expect-error so that if we break the type casting someone will notice + // @ts-expect-error + await convo.send(123) + const messages = await convo.messages() + for (const message of messages) { + // Strings don't have this kind of method + // @ts-expect-error + message.toFixed() + } + } catch (e) { + return + } + fail() + }) + + it('allows you to use custom content types', async () => { + const client = await Client.create(newWallet(), { + codecs: [new CompositeCodec()], + }) + const other = await newLocalHostClient() + const convo = await client.conversations.newConversation(other.address) + expect(convo).toBeTruthy() + // This will have a type error if the codecs field isn't being respected + await convo.send({ parts: [{ type: ContentTypeText, content: 'foo' }] }) + }) + }) + describe('Pluggable API client', () => { it('allows you to specify a custom API client factory', async () => { const expectedError = new Error('CustomApiClient') diff --git a/test/helpers.ts b/test/helpers.ts index d697d1642..9e46bcaf9 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -157,9 +157,7 @@ export class CodecRegistry { // client running against local node running on the host, // see github.com/xmtp/xmtp-node-go/scripts/xmtp-js.sh -export const newLocalHostClient = ( - opts?: Partial -): Promise => +export const newLocalHostClient = (opts?: Partial) => Client.create(newWallet(), { env: 'local', ...opts, @@ -169,14 +167,14 @@ export const newLocalHostClient = ( // with a non-ethers wallet export const newLocalHostClientWithCustomWallet = ( opts?: Partial -): Promise => +) => Client.create(newCustomWallet(), { env: 'local', ...opts, }) // client running against the dev cluster in AWS -export const newDevClient = (opts?: Partial): Promise => +export const newDevClient = (opts?: Partial) => Client.create(newWallet(), { env: 'dev', ...opts, From 7b035681370242ee1474ca542db271fb170bc551 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:41:09 -0700 Subject: [PATCH 127/137] test: improve client tests --- test/Client.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Client.test.ts b/test/Client.test.ts index db4462270..401ca164b 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -348,7 +348,7 @@ describe('ClientOptions', () => { describe('custom codecs', () => { it('gives type errors when you use the wrong types', async () => { const client = await Client.create(newWallet()) - const other = await newLocalHostClient() + const other = await Client.create(newWallet()) const convo = await client.conversations.newConversation(other.address) expect(convo).toBeTruthy() try { @@ -371,7 +371,7 @@ describe('ClientOptions', () => { const client = await Client.create(newWallet(), { codecs: [new CompositeCodec()], }) - const other = await newLocalHostClient() + const other = await Client.create(newWallet()) const convo = await client.conversations.newConversation(other.address) expect(convo).toBeTruthy() // This will have a type error if the codecs field isn't being respected From c6da56dbb3f8ee92e68e17f776d411ace92e0f75 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:44:39 -0700 Subject: [PATCH 128/137] test: make DecodedMessage default to any --- src/Message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message.ts b/src/Message.ts index 8c27a7e44..37e4a37b4 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -220,7 +220,7 @@ export class MessageV2 extends MessageBase implements proto.MessageV2 { export type Message = MessageV1 | MessageV2 -export class DecodedMessage { +export class DecodedMessage { id: string messageVersion: 'v1' | 'v2' senderAddress: string From ec13522480da77deb3ed561f2d7f3b6208597532 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:45:13 -0700 Subject: [PATCH 129/137] build: disable lint warning --- src/Message.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Message.ts b/src/Message.ts index 37e4a37b4..c4f585a3c 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -220,6 +220,7 @@ export class MessageV2 extends MessageBase implements proto.MessageV2 { export type Message = MessageV1 | MessageV2 +// eslint-disable-next-line @typescript-eslint/no-explicit-any export class DecodedMessage { id: string messageVersion: 'v1' | 'v2' From 1697a9be3f3b5f96c2edfa6e0ceae5d3e6fcacce Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:22:47 -0700 Subject: [PATCH 130/137] build: make generic types safer --- src/Client.ts | 11 ++++++----- src/Message.ts | 8 ++++---- src/Stream.ts | 13 +++++++------ src/conversations/Conversation.ts | 20 ++++++++++---------- src/conversations/Conversations.ts | 9 ++++++--- src/index.ts | 4 ++++ src/types/client.ts | 8 ++++++++ test/Client.test.ts | 4 ++-- test/conversations/Conversation.test.ts | 12 ++++++++++-- 9 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 src/types/client.ts diff --git a/src/Client.ts b/src/Client.ts index 6b7f0f734..b2b5a6e7d 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -41,6 +41,7 @@ import { } from './keystore/persistence' import { hasMetamaskWithSnaps } from './keystore/snapHelpers' import { version as snapVersion, package as snapPackage } from './snapInfo.json' +import { ExtractDecodedType } from './types/client' const { Compression } = proto // eslint-disable @typescript-eslint/explicit-module-boundary-types @@ -203,8 +204,6 @@ export type ClientOptions = Flatten< PreEventCallbackOptions > -export type ExtractDecodedType = C extends ContentCodec ? T : never - /** * Provide a default client configuration. These settings can be used on their own, or as a starting point for custom configurations * @@ -308,6 +307,7 @@ export default class Client { * @param opts specify how to to connect to the network */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any static async create[] = []>( wallet: Signer | null, opts?: Partial & { codecs?: U } @@ -600,10 +600,13 @@ export default class Client { * messages of the given Content Type */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - registerCodec(codec: ContentCodec): void { + registerCodec>( + codec: Codec + ): Client> { const id = codec.contentType const key = `${id.authorityId}/${id.typeId}` this._codecs.set(key, codec) + return this } /** @@ -862,5 +865,3 @@ async function bootstrapKeystore( } throw new Error('No keystore providers available') } - -export type ClientReturnType = C extends Client ? T : never diff --git a/src/Message.ts b/src/Message.ts index c4f585a3c..188541f7d 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -14,7 +14,7 @@ import { ContentTypeId } from './MessageContent' import { dateToNs, nsToDate } from './utils' import { Keystore } from './keystore' import { buildDecryptV1Request, getResultOrThrow } from './utils/keystore' -import { ClientReturnType } from './Client' +import { GetMessageContentTypeFromClient } from './types/client' const headerBytesAndCiphertext = ( msg: proto.Message @@ -279,7 +279,7 @@ export class DecodedMessage { static async fromBytes( data: Uint8Array, client: Client - ): Promise>> { + ): Promise> { const protoVal = proto.DecodedMessage.decode(data) const messageVersion = protoVal.messageVersion @@ -342,7 +342,7 @@ export class DecodedMessage { static fromV2Message( message: MessageV2, - content: any, // eslint-disable-line @typescript-eslint/no-explicit-any + content: T, contentType: ContentTypeId, contentTopic: string, contentBytes: Uint8Array, @@ -372,7 +372,7 @@ export class DecodedMessage { function conversationReferenceToConversation( reference: conversationReference.ConversationReference, client: Client, - version: DecodedMessage>['messageVersion'] + version: DecodedMessage['messageVersion'] ): Conversation { if (version === 'v1') { return new ConversationV1( diff --git a/src/Stream.ts b/src/Stream.ts index 1beb2e194..416a8c133 100644 --- a/src/Stream.ts +++ b/src/Stream.ts @@ -16,9 +16,10 @@ export type ContentTopicUpdater = (msg: M) => string[] | undefined * Stream implements an Asynchronous Iterable over messages received from a topic. * As such can be used with constructs like for-await-of, yield*, array destructing, etc. */ -export default class Stream { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default class Stream { topics: string[] - client: Client + client: Client // queue of incoming Waku messages messages: T[] // queue of already pending Promises @@ -32,7 +33,7 @@ export default class Stream { onConnectionLost?: OnConnectionLostCallback constructor( - client: Client, + client: Client, topics: string[], decoder: MessageDecoder, contentTopicUpdater?: ContentTopicUpdater, @@ -100,13 +101,13 @@ export default class Stream { ) } - static async create( - client: Client, + static async create( + client: Client, topics: string[], decoder: MessageDecoder, contentTopicUpdater?: ContentTopicUpdater, onConnectionLost?: OnConnectionLostCallback - ): Promise> { + ): Promise> { const stream = new Stream( client, topics, diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index b32f9ffc9..9b7116e5e 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -102,7 +102,7 @@ export interface Conversation { * } * ``` */ - streamMessages(): Promise>> + streamMessages(): Promise, T>> /** * Send a message into the conversation * @@ -135,7 +135,7 @@ export interface Conversation { * } * ``` */ - streamEphemeral(): Promise>> + streamEphemeral(): Promise, T>> } /** @@ -260,8 +260,8 @@ export class ConversationV1 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { - return Stream.create>( + ): Promise, T>> { + return Stream.create, T>( this.client, [this.topic], async (env: messageApi.Envelope) => this.decodeMessage(env), @@ -295,8 +295,8 @@ export class ConversationV1 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { - return Stream.create>( + ): Promise, T>> { + return Stream.create, T>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -477,8 +477,8 @@ export class ConversationV2 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { - return Stream.create>( + ): Promise, T>> { + return Stream.create, T>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -492,8 +492,8 @@ export class ConversationV2 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { - return Stream.create>( + ): Promise, T>> { + return Stream.create, T>( this.client, [this.topic], this.decodeMessage.bind(this), diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index 7198a5853..dba2a3c1f 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -210,7 +210,7 @@ export default class Conversations { */ async stream( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { + ): Promise, T>> { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) @@ -249,7 +249,7 @@ export default class Conversations { const topics = [introTopic, inviteTopic] - return Stream.create>( + return Stream.create, T>( this.client, topics, decodeConversation.bind(this), @@ -369,7 +369,10 @@ export default class Conversations { return undefined } - const str = await Stream.create | Conversation | null>( + const str = await Stream.create< + DecodedMessage | Conversation | null, + T + >( this.client, Array.from(topics.values()), decodeMessage, diff --git a/src/index.ts b/src/index.ts index cbf0326d7..196ad7bbc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -108,3 +108,7 @@ export { } from './keystore/persistence' export { InvitationContext, SealedInvitation } from './Invitation' export { decodeContactBundle } from './ContactBundle' +export type { + GetMessageContentTypeFromClient, + ExtractDecodedType, +} from './types/client' diff --git a/src/types/client.ts b/src/types/client.ts new file mode 100644 index 000000000..8adb9c599 --- /dev/null +++ b/src/types/client.ts @@ -0,0 +1,8 @@ +import type Client from '../Client' +import type { ContentCodec } from '../MessageContent' + +export type GetMessageContentTypeFromClient = C extends Client + ? T + : never + +export type ExtractDecodedType = C extends ContentCodec ? T : never diff --git a/test/Client.test.ts b/test/Client.test.ts index 401ca164b..88b63c0f4 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -347,8 +347,8 @@ describe('ClientOptions', () => { describe('custom codecs', () => { it('gives type errors when you use the wrong types', async () => { - const client = await Client.create(newWallet()) - const other = await Client.create(newWallet()) + const client = await Client.create(newWallet(), { env: 'local' }) + const other = await Client.create(newWallet(), { env: 'local' }) const convo = await client.conversations.newConversation(other.address) expect(convo).toBeTruthy() try { diff --git a/test/conversations/Conversation.test.ts b/test/conversations/Conversation.test.ts index 665e41556..5f5c51668 100644 --- a/test/conversations/Conversation.test.ts +++ b/test/conversations/Conversation.test.ts @@ -10,8 +10,8 @@ import { ContentTypeTestKey, TestKeyCodec } from '../ContentTypeTestKey' import { content as proto } from '@xmtp/proto' describe('conversation', () => { - let alice: Client - let bob: Client + let alice: Client + let bob: Client describe('v1', () => { beforeEach(async () => { @@ -425,6 +425,7 @@ describe('conversation', () => { // alice doesn't recognize the type await expect( + // @ts-expect-error aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -432,6 +433,7 @@ describe('conversation', () => { // bob doesn't recognize the type alice.registerCodec(new TestKeyCodec()) + // @ts-expect-error await aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -453,6 +455,7 @@ describe('conversation', () => { // both recognize the type bob.registerCodec(new TestKeyCodec()) + // @ts-expect-error await aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -467,6 +470,7 @@ describe('conversation', () => { ...ContentTypeTestKey, versionMajor: 2, }) + // @ts-expect-error expect(aliceConvo.send(key, { contentType: type2 })).rejects.toThrow( 'unknown content type xmtp.test/public-key:2.0' ) @@ -663,6 +667,7 @@ describe('conversation', () => { // alice doesn't recognize the type expect( + // @ts-expect-error aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -670,6 +675,7 @@ describe('conversation', () => { // bob doesn't recognize the type alice.registerCodec(new TestKeyCodec()) + // @ts-expect-error await aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -691,6 +697,7 @@ describe('conversation', () => { // both recognize the type bob.registerCodec(new TestKeyCodec()) + // @ts-expect-error await aliceConvo.send(key, { contentType: ContentTypeTestKey, }) @@ -705,6 +712,7 @@ describe('conversation', () => { ...ContentTypeTestKey, versionMajor: 2, }) + // @ts-expect-error expect(aliceConvo.send(key, { contentType: type2 })).rejects.toThrow( 'unknown content type xmtp.test/public-key:2.0' ) From b3836f76ccf35903d8845dd6940e4743c9a1bc6d Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:29:20 -0700 Subject: [PATCH 131/137] chore: default conversation types to any --- src/conversations/Conversation.ts | 3 ++- src/conversations/Conversations.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 9b7116e5e..8cccaca9d 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -36,7 +36,8 @@ import { ContentTypeText } from '../codecs/Text' /** * Conversation represents either a V1 or V2 conversation with a common set of methods. */ -export interface Conversation { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface Conversation { conversationVersion: 'v1' | 'v2' /** * The wallet address connected to the client diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index dba2a3c1f..92e8d6fbe 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -28,7 +28,8 @@ const messageHasHeaders = (msg: MessageV1): boolean => { /** * Conversations allows you to view ongoing 1:1 messaging sessions with another wallet */ -export default class Conversations { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default class Conversations { private client: Client private v1JobRunner: JobRunner private v2JobRunner: JobRunner From 28e63bfcf7ca3f885f6aa5968a59ff28d422d0f5 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:46:46 -0700 Subject: [PATCH 132/137] build: disallow sending undefined, but do return it as possible type --- src/Client.ts | 13 ++++++------- src/conversations/Conversation.ts | 15 ++++++++++++--- test/Message.test.ts | 5 ++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index b2b5a6e7d..0bc4fe3d5 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -311,7 +311,9 @@ export default class Client { static async create[] = []>( wallet: Signer | null, opts?: Partial & { codecs?: U } - ): Promise>> { + ): Promise< + Client | undefined> + > { const options = defaultOptions(opts) const apiClient = options.apiClientFactory(options) const keystore = await bootstrapKeystore(options, apiClient, wallet) @@ -321,12 +323,9 @@ export default class Client { const address = publicKeyBundle.walletSignatureAddress() apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) - const client = new Client>( - publicKeyBundle, - apiClient, - backupClient, - keystore - ) + const client = new Client< + ExtractDecodedType<[...U, TextCodec][number]> | undefined + >(publicKeyBundle, apiClient, backupClient, keystore) await client.init(options) return client } diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 8cccaca9d..1d501cc73 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -112,7 +112,10 @@ export interface Conversation { * await conversation.send('Hello world') // returns a `DecodedMessage` instance * ``` */ - send(content: T, options?: SendOptions): Promise> + send( + content: Exclude, + options?: SendOptions + ): Promise> /** * Return a `PreparedMessage` that has contains the message ID @@ -309,7 +312,10 @@ export class ConversationV1 implements Conversation { /** * Send a message into the conversation. */ - async send(content: T, options?: SendOptions): Promise> { + async send( + content: Exclude, + options?: SendOptions + ): Promise> { let topics: string[] let recipient = await this.client.getUserContact(this.peerAddress) if (!recipient) { @@ -506,7 +512,10 @@ export class ConversationV2 implements Conversation { /** * Send a message into the conversation */ - async send(content: T, options?: SendOptions): Promise> { + async send( + content: Exclude, + options?: SendOptions + ): Promise> { const payload = await this.client.encodeContent(content, options) const msg = await this.createMessage(payload, options?.timestamp) diff --git a/test/Message.test.ts b/test/Message.test.ts index 16b7b09f6..0f95b802b 100644 --- a/test/Message.test.ts +++ b/test/Message.test.ts @@ -248,7 +248,10 @@ describe('Message', function () { sentMessageBytes, aliceClient ) - if (typeof aliceRestoredMessage.content === 'string') { + if ( + typeof aliceRestoredMessage.content === 'string' || + !aliceRestoredMessage.content + ) { throw new Error('Expected content to be a PublicKeyBundle') } expect( From 8ab816260943d4a20be3b0948cfb70bf76f7ce91 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 13 Sep 2023 08:07:18 -0700 Subject: [PATCH 133/137] fix: fix a bug that the types found --- bench/encode.ts | 2 +- test/Client.test.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bench/encode.ts b/bench/encode.ts index 42eee2ba3..7c52b9959 100644 --- a/bench/encode.ts +++ b/bench/encode.ts @@ -17,7 +17,7 @@ const encodeV1 = () => { const alice = await Client.create(newWallet(), { env: 'local' }) const bobKeys = (await newPrivateKeyBundle()).getPublicKeyBundle() - const message = randomBytes(size) + const message = randomBytes(size).toString() const timestamp = new Date() // The returned function is the actual benchmark. Everything above is setup diff --git a/test/Client.test.ts b/test/Client.test.ts index 88b63c0f4..947a8ac07 100644 --- a/test/Client.test.ts +++ b/test/Client.test.ts @@ -201,7 +201,9 @@ describe('encodeContent', () => { describe('canMessage', () => { it('can confirm a user is on the network statically', async () => { - const registeredClient = await newLocalHostClient() + const registeredClient = await newLocalHostClient({ + codecs: [new TextCodec()], + }) await waitForUserContact(registeredClient, registeredClient) const canMessageRegisteredClient = await Client.canMessage( registeredClient.address, From 1542277b81357df7893e37d8b01f38f7b8dd4e9c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:34:31 -0700 Subject: [PATCH 134/137] fix: close stream when generator returns --- src/conversations/Conversations.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index fcecf711f..65f351cd0 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -372,7 +372,7 @@ export default class Conversations { onConnectionLost ) - return (async function* generate() { + const gen = (async function* generate() { for await (const val of str) { if (val instanceof DecodedMessage) { yield val @@ -386,6 +386,16 @@ export default class Conversations { } } })() + + // Overwrite the generator's return method to close the underlying stream + // Generators by default need to wait until the next yield to return. + // In this case, that's only when the next message arrives...which could be a long time + gen.return = async () => { + await str?.return() + return { value: undefined, done: true } + } + + return gen } private async getIntroductionPeers( From 90233f680ae2398e6d984ab7a8d4e4c4892fc55c Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 13 Sep 2023 15:51:34 -0700 Subject: [PATCH 135/137] chore: rename types --- src/Client.ts | 25 +++++---- src/Message.ts | 41 +++++++------- src/conversations/Conversation.ts | 88 +++++++++++++++++------------- src/conversations/Conversations.ts | 73 ++++++++++++++----------- 4 files changed, 129 insertions(+), 98 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 0bc4fe3d5..592359a7d 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -246,7 +246,7 @@ export function defaultOptions(opts?: Partial): ClientOptions { * Should be created with `await Client.create(options)` */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export default class Client { +export default class Client { address: string keystore: Keystore apiClient: ApiClient @@ -258,7 +258,7 @@ export default class Client { > // addresses and key bundles that we have witnessed private _backupClient: BackupClient - private readonly _conversations: Conversations + private readonly _conversations: Conversations // eslint-disable-next-line @typescript-eslint/no-explicit-any private _codecs: Map> private _maxContentSize: number @@ -288,7 +288,7 @@ export default class Client { /** * @type {Conversations} */ - get conversations(): Conversations { + get conversations(): Conversations { return this._conversations } @@ -308,11 +308,13 @@ export default class Client { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - static async create[] = []>( + static async create[] = []>( wallet: Signer | null, - opts?: Partial & { codecs?: U } + opts?: Partial & { codecs?: ContentCodecs } ): Promise< - Client | undefined> + Client< + ExtractDecodedType<[...ContentCodecs, TextCodec][number]> | undefined + > > { const options = defaultOptions(opts) const apiClient = options.apiClientFactory(options) @@ -324,7 +326,7 @@ export default class Client { apiClient.setAuthenticator(new KeystoreAuthenticator(keystore)) const backupClient = await Client.setupBackupClient(address, options.env) const client = new Client< - ExtractDecodedType<[...U, TextCodec][number]> | undefined + ExtractDecodedType<[...ContentCodecs, TextCodec][number]> | undefined >(publicKeyBundle, apiClient, backupClient, keystore) await client.init(options) return client @@ -601,7 +603,7 @@ export default class Client { // eslint-disable-next-line @typescript-eslint/no-explicit-any registerCodec>( codec: Codec - ): Client> { + ): Client> { const id = codec.contentType const key = `${id.authorityId}/${id.typeId}` this._codecs.set(key, codec) @@ -629,7 +631,10 @@ export default class Client { * Convert arbitrary content into a serialized `EncodedContent` instance * with the given options */ - async encodeContent(content: T, options?: SendOptions): Promise { + async encodeContent( + content: ContentTypes, + options?: SendOptions + ): Promise { const contentType = options?.contentType || ContentTypeText const codec = this.codecFor(contentType) if (!codec) { @@ -649,7 +654,7 @@ export default class Client { } async decodeContent(contentBytes: Uint8Array): Promise<{ - content: T + content: ContentTypes contentType: ContentTypeId error?: Error contentFallback?: string diff --git a/src/Message.ts b/src/Message.ts index 188541f7d..f4a23bbf5 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -221,16 +221,16 @@ export class MessageV2 extends MessageBase implements proto.MessageV2 { export type Message = MessageV1 | MessageV2 // eslint-disable-next-line @typescript-eslint/no-explicit-any -export class DecodedMessage { +export class DecodedMessage { id: string messageVersion: 'v1' | 'v2' senderAddress: string recipientAddress?: string sent: Date contentTopic: string - conversation: Conversation + conversation: Conversation contentType: ContentTypeId - content: T // eslint-disable-line @typescript-eslint/no-explicit-any + content: ContentTypes error?: Error contentBytes: Uint8Array contentFallback?: string @@ -248,7 +248,7 @@ export class DecodedMessage { sent, error, contentFallback, - }: Omit, 'toBytes'>) { + }: Omit, 'toBytes'>) { this.id = id this.messageVersion = messageVersion this.senderAddress = senderAddress @@ -276,10 +276,10 @@ export class DecodedMessage { }).finish() } - static async fromBytes( + static async fromBytes( data: Uint8Array, - client: Client - ): Promise> { + client: Client + ): Promise> { const protoVal = proto.DecodedMessage.decode(data) const messageVersion = protoVal.messageVersion @@ -310,16 +310,16 @@ export class DecodedMessage { }) } - static fromV1Message( + static fromV1Message( message: MessageV1, - content: T, // eslint-disable-line @typescript-eslint/no-explicit-any + content: ContentTypes, contentType: ContentTypeId, contentBytes: Uint8Array, contentTopic: string, - conversation: Conversation, + conversation: Conversation, error?: Error, contentFallback?: string - ): DecodedMessage { + ): DecodedMessage { const { id, senderAddress, recipientAddress, sent } = message if (!senderAddress) { throw new Error('Sender address is required') @@ -340,17 +340,17 @@ export class DecodedMessage { }) } - static fromV2Message( + static fromV2Message( message: MessageV2, - content: T, + content: ContentTypes, contentType: ContentTypeId, contentTopic: string, contentBytes: Uint8Array, - conversation: Conversation, + conversation: Conversation, senderAddress: string, error?: Error, contentFallback?: string - ): DecodedMessage { + ): DecodedMessage { const { id, sent } = message return new DecodedMessage({ @@ -369,11 +369,11 @@ export class DecodedMessage { } } -function conversationReferenceToConversation( +function conversationReferenceToConversation( reference: conversationReference.ConversationReference, - client: Client, + client: Client, version: DecodedMessage['messageVersion'] -): Conversation { +): Conversation { if (version === 'v1') { return new ConversationV1( client, @@ -393,6 +393,9 @@ function conversationReferenceToConversation( throw new Error(`Unknown conversation version ${version}`) } -export function decodeContent(contentBytes: Uint8Array, client: Client) { +export function decodeContent( + contentBytes: Uint8Array, + client: Client +) { return client.decodeContent(contentBytes) } diff --git a/src/conversations/Conversation.ts b/src/conversations/Conversation.ts index 1d501cc73..e8380411d 100644 --- a/src/conversations/Conversation.ts +++ b/src/conversations/Conversation.ts @@ -37,7 +37,7 @@ import { ContentTypeText } from '../codecs/Text' * Conversation represents either a V1 or V2 conversation with a common set of methods. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export interface Conversation { +export interface Conversation { conversationVersion: 'v1' | 'v2' /** * The wallet address connected to the client @@ -79,18 +79,18 @@ export interface Conversation { * }) * ``` */ - messages(opts?: ListMessagesOptions): Promise[]> + messages(opts?: ListMessagesOptions): Promise[]> /** * @deprecated */ messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator[]> + ): AsyncGenerator[]> /** * Takes a XMTP envelope as input and will decrypt and decode it * returning a `DecodedMessage` instance. */ - decodeMessage(env: messageApi.Envelope): Promise> + decodeMessage(env: messageApi.Envelope): Promise> /** * Return a `Stream` of new messages in this conversation. * @@ -103,7 +103,7 @@ export interface Conversation { * } * ``` */ - streamMessages(): Promise, T>> + streamMessages(): Promise, ContentTypes>> /** * Send a message into the conversation * @@ -113,9 +113,9 @@ export interface Conversation { * ``` */ send( - content: Exclude, + content: Exclude, options?: SendOptions - ): Promise> + ): Promise> /** * Return a `PreparedMessage` that has contains the message ID @@ -139,20 +139,22 @@ export interface Conversation { * } * ``` */ - streamEphemeral(): Promise, T>> + streamEphemeral(): Promise, ContentTypes>> } /** * ConversationV1 allows you to view, stream, and send messages to/from a peer address */ -export class ConversationV1 implements Conversation { +export class ConversationV1 + implements Conversation +{ conversationVersion = 'v1' as const peerAddress: string createdAt: Date context = undefined - private client: Client + private client: Client - constructor(client: Client, address: string, createdAt: Date) { + constructor(client: Client, address: string, createdAt: Date) { this.peerAddress = utils.getAddress(address) this.client = client this.createdAt = createdAt @@ -176,7 +178,9 @@ export class ConversationV1 implements Conversation { /** * Returns a list of all messages to/from the peerAddress */ - async messages(opts?: ListMessagesOptions): Promise[]> { + async messages( + opts?: ListMessagesOptions + ): Promise[]> { const topic = buildDirectMessageTopic(this.peerAddress, this.client.address) const messages = await this.client.listEnvelopes( topic, @@ -189,7 +193,7 @@ export class ConversationV1 implements Conversation { messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator[]> { + ): AsyncGenerator[]> { return this.client.listEnvelopesPaginated( this.topic, // This won't be performant once we start supporting a remote keystore @@ -200,7 +204,9 @@ export class ConversationV1 implements Conversation { } // decodeMessage takes an envelope and either returns a `DecodedMessage` or throws if an error occurs - async decodeMessage(env: messageApi.Envelope): Promise> { + async decodeMessage( + env: messageApi.Envelope + ): Promise> { if (!env.contentTopic) { throw new Error('Missing content topic') } @@ -264,8 +270,8 @@ export class ConversationV1 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise, T>> { - return Stream.create, T>( + ): Promise, ContentTypes>> { + return Stream.create, ContentTypes>( this.client, [this.topic], async (env: messageApi.Envelope) => this.decodeMessage(env), @@ -299,8 +305,8 @@ export class ConversationV1 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise, T>> { - return Stream.create, T>( + ): Promise, ContentTypes>> { + return Stream.create, ContentTypes>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -313,9 +319,9 @@ export class ConversationV1 implements Conversation { * Send a message into the conversation. */ async send( - content: Exclude, + content: Exclude, options?: SendOptions - ): Promise> { + ): Promise> { let topics: string[] let recipient = await this.client.getUserContact(this.peerAddress) if (!recipient) { @@ -363,14 +369,14 @@ export class ConversationV1 implements Conversation { messages: MessageV1[], topic: string, throwOnError = false - ): Promise[]> { + ): Promise[]> { const responses = ( await this.client.keystore.decryptV1( buildDecryptV1Request(messages, this.client.publicKeyBundle) ) ).responses - const out: DecodedMessage[] = [] + const out: DecodedMessage[] = [] for (let i = 0; i < responses.length; i++) { const result = responses[i] const message = messages[i] @@ -392,7 +398,7 @@ export class ConversationV1 implements Conversation { message: MessageV1, decrypted: Uint8Array, topic: string - ): Promise> { + ): Promise> { const { content, contentType, error, contentFallback } = await this.client.decodeContent(decrypted) @@ -429,16 +435,18 @@ export class ConversationV1 implements Conversation { /** * ConversationV2 */ -export class ConversationV2 implements Conversation { +export class ConversationV2 + implements Conversation +{ conversationVersion = 'v2' as const - client: Client + client: Client topic: string peerAddress: string createdAt: Date context?: InvitationContext constructor( - client: Client, + client: Client, topic: string, peerAddress: string, createdAt: Date, @@ -458,7 +466,9 @@ export class ConversationV2 implements Conversation { /** * Returns a list of all messages to/from the peerAddress */ - async messages(opts?: ListMessagesOptions): Promise[]> { + async messages( + opts?: ListMessagesOptions + ): Promise[]> { const messages = await this.client.listEnvelopes( this.topic, this.processEnvelope.bind(this), @@ -470,7 +480,7 @@ export class ConversationV2 implements Conversation { messagesPaginated( opts?: ListMessagesPaginatedOptions - ): AsyncGenerator[]> { + ): AsyncGenerator[]> { return this.client.listEnvelopesPaginated( this.topic, this.decodeMessage.bind(this), @@ -484,8 +494,8 @@ export class ConversationV2 implements Conversation { streamEphemeral( onConnectionLost?: OnConnectionLostCallback - ): Promise, T>> { - return Stream.create, T>( + ): Promise, ContentTypes>> { + return Stream.create, ContentTypes>( this.client, [this.ephemeralTopic], this.decodeMessage.bind(this), @@ -499,8 +509,8 @@ export class ConversationV2 implements Conversation { */ streamMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise, T>> { - return Stream.create, T>( + ): Promise, ContentTypes>> { + return Stream.create, ContentTypes>( this.client, [this.topic], this.decodeMessage.bind(this), @@ -513,9 +523,9 @@ export class ConversationV2 implements Conversation { * Send a message into the conversation */ async send( - content: Exclude, + content: Exclude, options?: SendOptions - ): Promise> { + ): Promise> { const payload = await this.client.encodeContent(content, options) const msg = await this.createMessage(payload, options?.timestamp) @@ -581,12 +591,12 @@ export class ConversationV2 implements Conversation { private async decryptBatch( messages: MessageV2[], throwOnError = false - ): Promise[]> { + ): Promise[]> { const responses = ( await this.client.keystore.decryptV2(this.buildDecryptRequest(messages)) ).responses - const out: DecodedMessage[] = [] + const out: DecodedMessage[] = [] for (let i = 0; i < responses.length; i++) { const result = responses[i] const message = messages[i] @@ -642,7 +652,7 @@ export class ConversationV2 implements Conversation { private async buildDecodedMessage( msg: MessageV2, decrypted: Uint8Array - ): Promise> { + ): Promise> { // Decode the decrypted bytes into SignedContent const signed = proto.SignedContent.decode(decrypted) if ( @@ -731,7 +741,9 @@ export class ConversationV2 implements Conversation { return MessageV2.create(msg, header, env.message) } - async decodeMessage(env: messageApi.Envelope): Promise> { + async decodeMessage( + env: messageApi.Envelope + ): Promise> { if (!env.contentTopic) { throw new Error('Missing content topic') } diff --git a/src/conversations/Conversations.ts b/src/conversations/Conversations.ts index b70a7d6ca..1423daf35 100644 --- a/src/conversations/Conversations.ts +++ b/src/conversations/Conversations.ts @@ -29,12 +29,12 @@ const messageHasHeaders = (msg: MessageV1): boolean => { * Conversations allows you to view ongoing 1:1 messaging sessions with another wallet */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export default class Conversations { - private client: Client +export default class Conversations { + private client: Client private v1JobRunner: JobRunner private v2JobRunner: JobRunner - constructor(client: Client) { + constructor(client: Client) { this.client = client this.v1JobRunner = new JobRunner('v1', client.keystore) this.v2JobRunner = new JobRunner('v2', client.keystore) @@ -43,7 +43,7 @@ export default class Conversations { /** * List all conversations with the current wallet found in the network. */ - async list(): Promise[]> { + async list(): Promise[]> { const [v1Convos, v2Convos] = await Promise.all([ this.listV1Conversations(), this.listV2Conversations(), @@ -59,18 +59,19 @@ export default class Conversations { * List all conversations stored in the client cache, which may not include * conversations on the network. */ - async listFromCache(): Promise[]> { - const [v1Convos, v2Convos]: Conversation[][] = await Promise.all([ - this.getV1ConversationsFromKeystore(), - this.getV2ConversationsFromKeystore(), - ]) + async listFromCache(): Promise[]> { + const [v1Convos, v2Convos]: Conversation[][] = + await Promise.all([ + this.getV1ConversationsFromKeystore(), + this.getV2ConversationsFromKeystore(), + ]) const conversations = v1Convos.concat(v2Convos) conversations.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()) return conversations } - private async listV1Conversations(): Promise[]> { + private async listV1Conversations(): Promise[]> { return this.v1JobRunner.run(async (latestSeen) => { const seenPeers = await this.getIntroductionPeers({ startTime: latestSeen @@ -99,7 +100,7 @@ export default class Conversations { /** * List all V2 conversations */ - private async listV2Conversations(): Promise[]> { + private async listV2Conversations(): Promise[]> { return this.v2JobRunner.run(async (lastRun) => { // Get all conversations already in the KeyStore const existing = await this.getV2ConversationsFromKeystore() @@ -122,20 +123,26 @@ export default class Conversations { }) } - private async getV2ConversationsFromKeystore(): Promise[]> { + private async getV2ConversationsFromKeystore(): Promise< + ConversationV2[] + > { return (await this.client.keystore.getV2Conversations()).conversations.map( this.conversationReferenceToV2.bind(this) ) } - private async getV1ConversationsFromKeystore(): Promise[]> { + private async getV1ConversationsFromKeystore(): Promise< + ConversationV1[] + > { return (await this.client.keystore.getV1Conversations()).conversations.map( this.conversationReferenceToV1.bind(this) ) } // Called in listV2Conversations and in newConversation - async updateV2Conversations(startTime?: Date): Promise[]> { + async updateV2Conversations( + startTime?: Date + ): Promise[]> { const envelopes = await this.client.listInvitations({ startTime: startTime ? new Date(+startTime - CLOCK_SKEW_OFFSET_MS) @@ -149,7 +156,7 @@ export default class Conversations { private async decodeInvites( envelopes: messageApi.Envelope[], shouldThrow = false - ): Promise[]> { + ): Promise[]> { const { responses } = await this.client.keystore.saveInvites({ requests: envelopes.map((env) => ({ payload: env.message as Uint8Array, @@ -158,7 +165,7 @@ export default class Conversations { })), }) - const out: ConversationV2[] = [] + const out: ConversationV2[] = [] for (const response of responses) { try { out.push(this.saveInviteResponseToConversation(response)) @@ -175,7 +182,7 @@ export default class Conversations { private saveInviteResponseToConversation({ result, error, - }: keystore.SaveInvitesResponse_Response): ConversationV2 { + }: keystore.SaveInvitesResponse_Response): ConversationV2 { if (error || !result || !result.conversation) { throw new Error(`Error from keystore: ${error?.code} ${error?.message}}`) } @@ -184,7 +191,7 @@ export default class Conversations { private conversationReferenceToV2( convoRef: conversationReference.ConversationReference - ): ConversationV2 { + ): ConversationV2 { return new ConversationV2( this.client, convoRef.topic, @@ -196,7 +203,7 @@ export default class Conversations { private conversationReferenceToV1( convoRef: conversationReference.ConversationReference - ): ConversationV1 { + ): ConversationV1 { return new ConversationV1( this.client, convoRef.peerAddress, @@ -211,7 +218,7 @@ export default class Conversations { */ async stream( onConnectionLost?: OnConnectionLostCallback - ): Promise, T>> { + ): Promise, ContentTypes>> { const seenPeers: Set = new Set() const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) @@ -250,7 +257,7 @@ export default class Conversations { const topics = [introTopic, inviteTopic] - return Stream.create, T>( + return Stream.create, ContentTypes>( this.client, topics, decodeConversation.bind(this), @@ -268,13 +275,13 @@ export default class Conversations { */ async streamAllMessages( onConnectionLost?: OnConnectionLostCallback - ): Promise>> { + ): Promise>> { const introTopic = buildUserIntroTopic(this.client.address) const inviteTopic = buildUserInviteTopic(this.client.address) const topics = new Set([introTopic, inviteTopic]) - const convoMap = new Map>() + const convoMap = new Map>() for (const conversation of await this.list()) { topics.add(conversation.topic) @@ -283,7 +290,9 @@ export default class Conversations { const decodeMessage = async ( env: messageApi.Envelope - ): Promise | DecodedMessage | null> => { + ): Promise< + Conversation | DecodedMessage | null + > => { const contentTopic = env.contentTopic if (!contentTopic || !env.message) { return null @@ -334,7 +343,7 @@ export default class Conversations { const addConvo = ( topic: string, - conversation: Conversation + conversation: Conversation ): boolean => { if (topics.has(topic)) { return false @@ -345,7 +354,7 @@ export default class Conversations { } const contentTopicUpdater = ( - msg: Conversation | DecodedMessage | null + msg: Conversation | DecodedMessage | null ) => { // If we have a V1 message from the introTopic, store the conversation in our mapping if (msg instanceof DecodedMessage && msg.contentTopic === introTopic) { @@ -371,8 +380,8 @@ export default class Conversations { } const str = await Stream.create< - DecodedMessage | Conversation | null, - T + DecodedMessage | Conversation | null, + ContentTypes >( this.client, Array.from(topics.values()), @@ -400,6 +409,8 @@ export default class Conversations { // Generators by default need to wait until the next yield to return. // In this case, that's only when the next message arrives...which could be a long time gen.return = async () => { + // Returning the stream will cause the iteration to end inside the generator + // The generator will then return on its own await str?.return() return { value: undefined, done: true } } @@ -457,7 +468,7 @@ export default class Conversations { async newConversation( peerAddress: string, context?: InvitationContext - ): Promise> { + ): Promise> { let contact = await this.client.getUserContact(peerAddress) if (!contact) { throw new Error(`Recipient ${peerAddress} is not on the XMTP network`) @@ -504,7 +515,7 @@ export default class Conversations { } // Define a function for matching V2 conversations - const matcherFn = (convo: Conversation) => + const matcherFn = (convo: Conversation) => convo.peerAddress === peerAddress && isMatchingContext(context, convo.context ?? undefined) @@ -529,7 +540,7 @@ export default class Conversations { private async createV2Convo( recipient: SignedPublicKeyBundle, context?: InvitationContext - ): Promise> { + ): Promise> { const timestamp = new Date() const { payload, conversation } = await this.client.keystore.createInvite({ recipient, From 4d301604236ffc77e15fe0ce67ab3c58bd55c868 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:04:18 -0700 Subject: [PATCH 136/137] chore: remove unused import --- src/Message.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Message.ts b/src/Message.ts index f4a23bbf5..f98a41e88 100644 --- a/src/Message.ts +++ b/src/Message.ts @@ -14,7 +14,6 @@ import { ContentTypeId } from './MessageContent' import { dateToNs, nsToDate } from './utils' import { Keystore } from './keystore' import { buildDecryptV1Request, getResultOrThrow } from './utils/keystore' -import { GetMessageContentTypeFromClient } from './types/client' const headerBytesAndCiphertext = ( msg: proto.Message From 73818d87ac4dab9c51b494190b08bf3fbd7a44b1 Mon Sep 17 00:00:00 2001 From: Nicholas Molnar <65710+neekolas@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:30:10 -0700 Subject: [PATCH 137/137] docs: fix isSnapsReady comment --- src/Client.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Client.ts b/src/Client.ts index 592359a7d..378d52439 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -352,9 +352,7 @@ export default class Client { } /** - * Tells the caller whether `getKeys` will work for them or throw - * Right now, this is only true if the user has Metamask with Snaps - * and has enabled the `useSnaps` option + * Tells the caller whether the browser has a Snaps-compatible version of MetaMask installed */ static isSnapsReady() { return hasMetamaskWithSnaps()