From 2f2dd83d398a53917d1a04b99add610a54f52cd2 Mon Sep 17 00:00:00 2001 From: adityapk00 <31996805+adityapk00@users.noreply.github.com> Date: Wed, 6 Sep 2023 07:03:55 -0700 Subject: [PATCH] feat: Snapshot sync (#1299) --- .changeset/big-buckets-work.md | 5 + apps/hubble/package.json | 4 + apps/hubble/src/cli.ts | 64 +- apps/hubble/src/defaultConfig.ts | 6 + apps/hubble/src/hubble.ts | 183 ++- apps/hubble/src/network/sync/syncEngine.ts | 67 +- .../src/network/sync/syncEngineProfiler.ts | 13 + apps/hubble/src/network/sync/syncId.ts | 16 +- apps/hubble/src/profile/profile.ts | 12 +- apps/hubble/src/storage/db/rocksdb.ts | 96 +- .../src/storage/stores/storeEventHandler.ts | 18 +- apps/hubble/src/utils/logger.ts | 2 +- apps/hubble/src/utils/rateLimits.test.ts | 6 +- apps/hubble/src/utils/rateLimits.ts | 6 +- yarn.lock | 1006 ++++++++++++++++- 15 files changed, 1459 insertions(+), 45 deletions(-) create mode 100644 .changeset/big-buckets-work.md diff --git a/.changeset/big-buckets-work.md b/.changeset/big-buckets-work.md new file mode 100644 index 0000000000..217060cd37 --- /dev/null +++ b/.changeset/big-buckets-work.md @@ -0,0 +1,5 @@ +--- +"@farcaster/hubble": patch +--- + +feat: Snapshot sync diff --git a/apps/hubble/package.json b/apps/hubble/package.json index b63554de97..21bc370baf 100644 --- a/apps/hubble/package.json +++ b/apps/hubble/package.json @@ -44,6 +44,7 @@ "@types/node-cron": "^3.0.7", "@types/progress": "^2.0.5", "@types/rwlock": "^5.0.3", + "@types/tar": "^6.1.5", "@viem/anvil": "^0.0.6", "cargo-cp-artifact": "^0.1", "chance": "~1.1.11", @@ -58,6 +59,8 @@ "tsx": "~3.12.5" }, "dependencies": { + "@aws-sdk/client-s3": "^3.400.0", + "@aws-sdk/client-sts": "^3.398.0", "@chainsafe/libp2p-gossipsub": "6.1.0", "@chainsafe/libp2p-noise": "^11.0.0 ", "@faker-js/faker": "~7.6.0", @@ -87,6 +90,7 @@ "rate-limiter-flexible": "^2.4.1", "rwlock": "~5.0.0", "semver": "^7.5.2", + "tar": "^6.1.15", "tiny-typed-emitter": "~2.1.0", "viem": "^1.1.4" } diff --git a/apps/hubble/src/cli.ts b/apps/hubble/src/cli.ts index bcbd60bc1f..fe38141004 100644 --- a/apps/hubble/src/cli.ts +++ b/apps/hubble/src/cli.ts @@ -15,7 +15,7 @@ import { mkdir, readFile, writeFile } from "fs/promises"; import { Result, ResultAsync } from "neverthrow"; import { dirname, resolve } from "path"; import { exit } from "process"; -import { APP_VERSION, FARCASTER_VERSION, Hub, HubOptions } from "./hubble.js"; +import { APP_VERSION, FARCASTER_VERSION, Hub, HubOptions, S3_REGION } from "./hubble.js"; import { logger } from "./utils/logger.js"; import { addressInfoFromParts, hostPortFromString, ipMultiAddrStrFromAddressInfo, parseAddress } from "./utils/p2p.js"; import { DEFAULT_RPC_CONSOLE, startConsole } from "./console/console.js"; @@ -32,6 +32,7 @@ import { startupCheck, StartupCheckStatus } from "./utils/startupCheck.js"; import { goerli, mainnet, optimism } from "viem/chains"; import { finishAllProgressBars } from "./utils/progressBars.js"; import { MAINNET_BOOTSTRAP_PEERS } from "./bootstrapPeers.mainnet.js"; +import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts"; /** A CLI to accept options from the user and start the Hub */ @@ -124,6 +125,11 @@ app "RPC rate limit for peers specified in rpm. Set to -1 for none. (default: 20k/min)", ) + // Snapshots + .option("--enable-snapshot-to-s3", "Enable daily snapshots to be uploaded to S3. (default: disabled)") + .option("--s3-snapshot-bucket ", "The S3 bucket to upload snapshots to") + .option("--disable-snapshot-sync", "Disable syncing from snapshots. (default: enabled)") + // Metrics .option( "--statsd-metrics-server ", @@ -156,7 +162,7 @@ app const handleShutdownSignal = (signalName: string) => { logger.flush(); - logger.warn(`${signalName} received`); + logger.warn(`signal '${signalName}' received`); if (!isExiting) { isExiting = true; hub @@ -464,6 +470,13 @@ app const rebuildSyncTrie = cliOptions.rebuildSyncTrie ?? hubConfig.rebuildSyncTrie ?? false; const profileSync = cliOptions.profileSync ?? hubConfig.profileSync ?? false; + let enableSnapshotToS3 = cliOptions.enableSnapshotToS3 ?? hubConfig.enableSnapshotToS3 ?? false; + if (enableSnapshotToS3) { + // If we're uploading snapshots to S3, we need to make sure that the S3 credentials are set + const awsVerified = await verifyAWSCredentials(); + enableSnapshotToS3 = awsVerified; + } + const options: HubOptions = { peerId, ipMultiAddr: ipMultiAddrResult.value, @@ -507,8 +520,24 @@ app testUsers: testUsers, gossipMetricsEnabled: cliOptions.gossipMetricsEnabled ?? false, directPeers, + disableSnapshotSync: cliOptions.disableSnapshotSync ?? hubConfig.disableSnapshotSync ?? false, + enableSnapshotToS3, + s3SnapshotBucket: cliOptions.s3SnapshotBucket ?? hubConfig.s3SnapshotBucket, }; + if (options.enableSnapshotToS3) { + // Set the Hub to exit (and be automatically restarted) so that the snapshot is uploaded + // before the Hub starts syncing + // Calculate and set a timeout to run at 9:10 am UTC (2:10 am PST) + const millisTill9 = millisTillRestart(); + logger.info({ millisTill9 }, "Scheduling Hub to exit at 9:10 am UTC to upload snapshot to S3"); + + setTimeout(async () => { + logger.info("Exiting Hub to upload snapshot to S3"); + handleShutdownSignal("S3SnapshotUpload"); + }, millisTill9); + } + await startupCheck.rpcCheck(options.ethMainnetRpcUrl, mainnet, "L1"); await startupCheck.rpcCheck(options.l2RpcUrl, optimism, "L2", options.l2ChainId); @@ -879,3 +908,34 @@ const readPeerId = async (filePath: string) => { }; app.parse(process.argv); + +/////////////////////////////////////////////////////////////// +// UTILS +/////////////////////////////////////////////////////////////// +function millisTillRestart(): number { + // Calculate the number of milliseconds until 9:10 am UTC (2:10 am PST) + const now = new Date(); + const timeAt9 = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 9, 10, 0, 0).getTime(); + + const millisTill9Tomorrow = timeAt9 + 24 * 60 * 60 * 1000 - now.getTime(); + const millisTill9Today = timeAt9 - now.getTime(); + + return millisTill9Today > 0 ? millisTill9Today : millisTill9Tomorrow; +} + +// Verify that we have access to the AWS credentials. +// Either via environment variables or via the AWS credentials file +async function verifyAWSCredentials(): Promise { + const sts = new STSClient({ region: S3_REGION }); + + try { + const identity = await sts.send(new GetCallerIdentityCommand({})); + + logger.info({ accountId: identity.Account }, "Verified AWS credentials"); + + return true; + } catch (error) { + logger.error({ err: error }, "Failed to verify AWS credentials. No S3 snapshot upload will be performed."); + return false; + } +} diff --git a/apps/hubble/src/defaultConfig.ts b/apps/hubble/src/defaultConfig.ts index 42ae988b22..748b51e418 100644 --- a/apps/hubble/src/defaultConfig.ts +++ b/apps/hubble/src/defaultConfig.ts @@ -51,6 +51,8 @@ export const Config = { commitLockMaxPending: 1_000, /** Farcaster network */ network: DEFAULT_NETWORK, + /** Don't allow snapshot sync */ + // disableSnapshotSync: true, /** Start the admin server? */ adminServerEnabled: false, /** The admin server bind host */ @@ -61,4 +63,8 @@ export const Config = { directPeers: [], /** Disable progress bars and immediately print logs instead */ // disableConsoleStatus: false, + /** Enable backing up snapshots to S3 */ + // enableSnapshotToS3: false, + /** S3 bucket name */ + // s3BucketName: '', }; diff --git a/apps/hubble/src/hubble.ts b/apps/hubble/src/hubble.ts index 3d65ea760b..5b52e75cb9 100644 --- a/apps/hubble/src/hubble.ts +++ b/apps/hubble/src/hubble.ts @@ -32,7 +32,7 @@ import SyncEngine from "./network/sync/syncEngine.js"; import AdminServer from "./rpc/adminServer.js"; import Server from "./rpc/server.js"; import { getHubState, putHubState } from "./storage/db/hubState.js"; -import RocksDB from "./storage/db/rocksdb.js"; +import RocksDB, { createTarBackup, extractTarBackup } from "./storage/db/rocksdb.js"; import { RootPrefix } from "./storage/db/types.js"; import Engine from "./storage/engine/index.js"; import { PruneEventsJobScheduler } from "./storage/jobs/pruneEventsJob.js"; @@ -53,14 +53,12 @@ import { getPublicIp, ipFamilyToString, p2pMultiAddrStr, - parseAddress, } from "./utils/p2p.js"; import { PeriodicTestDataJobScheduler, TestUser } from "./utils/periodicTestDataJob.js"; import { ensureAboveMinFarcasterVersion, VersionSchedule } from "./utils/versions.js"; import { CheckFarcasterVersionJobScheduler } from "./storage/jobs/checkFarcasterVersionJob.js"; import { ValidateOrRevokeMessagesJobScheduler } from "./storage/jobs/validateOrRevokeMessagesJob.js"; import { GossipContactInfoJobScheduler } from "./storage/jobs/gossipContactInfoJob.js"; -import { MAINNET_BOOTSTRAP_PEERS } from "./bootstrapPeers.mainnet.js"; import StoreEventHandler from "./storage/stores/storeEventHandler.js"; import { FNameRegistryClient, FNameRegistryEventsProvider } from "./eth/fnameRegistryEventsProvider.js"; import { L2EventsProvider, OptimismConstants } from "./eth/l2EventsProvider.js"; @@ -75,13 +73,21 @@ import { NetworkConfig, applyNetworkConfig, fetchNetworkConfig } from "./network import { UpdateNetworkConfigJobScheduler } from "./storage/jobs/updateNetworkConfigJob.js"; import { statsd } from "./utils/statsd.js"; import { LATEST_DB_SCHEMA_VERSION, performDbMigrations } from "./storage/db/migrations/migrations.js"; -import { addProgressBar, finishAllProgressBars } from "./utils/progressBars.js"; +import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; +import path from "path"; +import { addProgressBar } from "./utils/progressBars.js"; + +import * as fs from "fs"; +import axios from "axios"; export type HubSubmitSource = "gossip" | "rpc" | "eth-provider" | "l2-provider" | "sync" | "fname-registry"; export const APP_VERSION = packageJson.version; export const APP_NICKNAME = process.env["HUBBLE_NAME"] ?? "Farcaster Hub"; +export const SNAPSHOT_S3_DEFAULT_BUCKET = "download.farcaster.xyz"; +export const S3_REGION = "us-east-1"; + export const FARCASTER_VERSION = "2023.8.23"; export const FARCASTER_VERSIONS_SCHEDULE: VersionSchedule[] = [ { version: "2023.3.1", expiresAt: 1682553600000 }, // expires at 4/27/23 00:00 UTC @@ -247,6 +253,15 @@ export interface HubOptions { /** A list of addresses the node directly peers with, provided in MultiAddr format */ directPeers?: AddrInfo[]; + + /** If set, snapshot sync is disabled */ + disableSnapshotSync?: boolean; + + /** Enable daily backups to S3 */ + enableSnapshotToS3?: boolean; + + /** S3 bucket to upload snapshots to */ + s3SnapshotBucket?: string; } /** @returns A randomized string of the format `rocksdb.tmp.*` used for the DB Name */ @@ -269,6 +284,8 @@ export class Hub implements HubInterface { private allowedPeerIds: string[] | undefined; private deniedPeerIds: string[]; + private s3_snapshot_bucket: string; + private pruneMessagesJobScheduler: PruneMessagesJobScheduler; private periodSyncJobScheduler: PeriodicSyncJobScheduler; private pruneEventsJobScheduler: PruneEventsJobScheduler; @@ -288,6 +305,8 @@ export class Hub implements HubInterface { this.rocksDB = new RocksDB(options.rocksDBName ? options.rocksDBName : randomDbName()); this.gossipNode = new GossipNode(this.rocksDB, this.options.network, this.options.gossipMetricsEnabled); + this.s3_snapshot_bucket = options.s3SnapshotBucket ?? SNAPSHOT_S3_DEFAULT_BUCKET; + if (!options.ethMainnetRpcUrl) { log.warn("No ETH mainnet RPC URL provided, unable to validate ens names"); throw new HubError("bad_request.invalid_param", "Invalid eth mainnet rpc url"); @@ -357,6 +376,9 @@ export class Hub implements HubInterface { profileLog.info({ method, p }); } + // Close the file stream + profile.writeOutNodeProfiles(); + // Also write to console for easy copy/paste console.log("\nTotal Time\n"); console.log(prettyPrintTable(profile.durationToPrettyPrintObject())); @@ -426,12 +448,44 @@ export class Hub implements HubInterface { if (!this.options.announceIp || this.options.announceIp.trim().length === 0) { const ipResult = await getPublicIp(); if (ipResult.isErr()) { - log.error(`failed to fetch public IP address, using ${this.options.ipMultiAddr}`, { error: ipResult.error }); + log.error({ error: ipResult.error }, `failed to fetch public IP address, using ${this.options.ipMultiAddr}`); } else { this.options.announceIp = ipResult.value; } } + // Snapshot Sync + if (!this.options.disableSnapshotSync) { + try { + const snapshotResult = await ResultAsync.fromPromise(this.snapshotSync(), (e) => e as Error); + if (snapshotResult.isErr()) { + log.error({ error: snapshotResult.error }, "failed to sync snapshot, falling back to regular sync"); + } + } catch (e) { + log.error({ error: e }, "failed to sync snapshot, falling back to regular sync"); + } + } + + if (this.options.enableSnapshotToS3) { + // Back up the DB before opening it + const tarResult = await createTarBackup(this.rocksDB.location); + + if (tarResult.isOk()) { + // Upload to S3. Run this in the background so we don't block startup. + setTimeout(async () => { + const s3Result = await this.uploadToS3(tarResult.value); + if (s3Result.isErr()) { + log.error({ error: s3Result.error, errMsg: s3Result.error.message }, "failed to upload snapshot to S3"); + } + + // Delete the tar file, ignore errors + fs.unlink(tarResult.value, () => {}); + }, 10); + } else { + log.error({ error: tarResult.error }, "failed to create tar backup for S3"); + } + } + let dbResult: Result; let retryCount = 0; @@ -620,6 +674,83 @@ export class Hub implements HubInterface { } } + async snapshotSync() { + // Check if the DB location is empty. If it is, we'll try to fetch a snapshot from S3. + const dbLocation = this.rocksDB.location; + const dbFiles = Result.fromThrowable( + () => fs.readdirSync(dbLocation), + (e) => e, + )(); + + if (dbFiles.isErr() || dbFiles.value.length === 0) { + log.info({ dbLocation }, "DB is empty, fetching snapshot from S3"); + + // Step 1: Download latest.json to get the latest snapshot name + const network = FarcasterNetwork[this.options.network].toString(); + const response = await axios.get(`https://download.farcaster.xyz/snapshots/${network}/latest.json`); + const { key } = response.data; + + const latestSnapshotKey = key as string; + const latestSnapshotName = path.basename(latestSnapshotKey); + + if (!latestSnapshotKey) { + log.error({ data: response.data }, "No latest snapshot name found in latest.json"); + return; + } + + log.info({ latestSnapshotKey, latestSnapshotName }, "found latest S3 snapshot"); + + // Step 2: Download the latest snapshot file + const snapshotUrl = `https://download.farcaster.xyz/${latestSnapshotKey}`; + const snapshotLocation = path.join(path.dirname(dbLocation), latestSnapshotName); + + const writeStream = fs.createWriteStream(snapshotLocation); + + const response2 = await axios.get(snapshotUrl, { responseType: "stream" }); + response2.data.pipe(writeStream); + + // Setup a progress bar to show download progress + const totalSize = parseInt(response2.headers["content-length"], 10); + let downloadedSize = 0; + const progressBar = addProgressBar("Getting snapshot", totalSize); + + // rome-ignore lint/suspicious/noExplicitAny: + response2.data.on("data", (chunk: any) => { + downloadedSize += chunk.length; + progressBar?.update(downloadedSize); + }); + + // Wait for the stream to finish + const streamResult = await new Promise>((resolve) => { + writeStream.on("finish", () => resolve(ok(true))); + writeStream.on("error", (e) => resolve(err(e.message))); + }); + + progressBar?.update(totalSize); + progressBar?.stop(); + writeStream.close(); + + if (streamResult.isErr()) { + log.error({ error: streamResult.error }, "failed to stream snapshot from S3"); + return; + } + + log.info({ snapshotLocation, bytesWritten: writeStream.bytesWritten }, "snapshot downloaded from S3"); + + // Extract the tar file + const extractProgressBar = addProgressBar("Extracting snapshot", totalSize); + const extractResult = await extractTarBackup(snapshotLocation, path.basename(dbLocation), extractProgressBar); + if (extractResult.isErr()) { + log.error({ error: extractResult.error }, "failed to extract snapshot from S3. Snapshot sync disabled"); + return; + } + + log.info({ dbLocation, bytesWritten: writeStream.bytesWritten }, "snapshot extracted from S3"); + // Delete the tar file, ignore errors + fs.unlink(snapshotLocation, () => {}); + } + } + async getContactInfoContent(): HubAsyncResult { const nodeMultiAddr = this.gossipAddresses[0] as Multiaddr; const family = nodeMultiAddr?.nodeAddress().family; @@ -1227,4 +1358,46 @@ export class Hub implements HubInterface { return true; } + + async uploadToS3(filePath: string): HubAsyncResult { + const network = FarcasterNetwork[this.options.network].toString(); + + const s3 = new S3Client({ + region: S3_REGION, + }); + + // The AWS key is "snapshots/{network}/snapshot-{yyyy-mm-dd}-{timestamp}.tar.gz" + const key = `snapshots/${network}/snapshot-${new Date().toISOString().split("T")[0]}-${Math.floor( + Date.now() / 1000, + )}.tar.gz`; + + const start = Date.now(); + log.info({ filePath }, "Uploading snapshot to S3"); + + const fileStream = fs.createReadStream(filePath); + fileStream.on("error", function (err) { + log.error(`S3 File Error: ${err}`); + }); + + const targzParams = { + Bucket: this.s3_snapshot_bucket, + Key: key, + Body: fileStream, + }; + + const latestJsonParams = { + Bucket: this.s3_snapshot_bucket, + Key: `snapshots/${network}/latest.json`, + Body: JSON.stringify({ key, timestamp: Date.now(), serverDate: new Date().toISOString() }), + }; + + try { + await s3.send(new PutObjectCommand(targzParams)); + await s3.send(new PutObjectCommand(latestJsonParams)); + log.info({ key, timeTakenMs: Date.now() - start }, "Snapshot uploaded to S3"); + return ok(key); + } catch (e: unknown) { + return err(new HubError("unavailable.network_failure", (e as Error).message)); + } + } } diff --git a/apps/hubble/src/network/sync/syncEngine.ts b/apps/hubble/src/network/sync/syncEngine.ts index bcc0986f7a..4ac6ee3336 100644 --- a/apps/hubble/src/network/sync/syncEngine.ts +++ b/apps/hubble/src/network/sync/syncEngine.ts @@ -24,7 +24,7 @@ import { err, ok, Result, ResultAsync } from "neverthrow"; import { TypedEmitter } from "tiny-typed-emitter"; import { APP_VERSION, FARCASTER_VERSION, Hub, HubInterface } from "../../hubble.js"; import { MerkleTrie, NodeMetadata } from "./merkleTrie.js"; -import { prefixToTimestamp, SyncId, timestampToPaddedTimestampPrefix } from "./syncId.js"; +import { formatPrefix, prefixToTimestamp, SyncId, timestampToPaddedTimestampPrefix } from "./syncId.js"; import { TrieSnapshot } from "./trieNode.js"; import { getManyMessages } from "../../storage/db/message.js"; import RocksDB from "../../storage/db/rocksdb.js"; @@ -43,9 +43,11 @@ import { SingleBar } from "cli-progress"; // attempt to sync messages that are older than this time. const SYNC_THRESHOLD_IN_SECONDS = 10; const HASHES_PER_FETCH = 128; +const SYNC_MAX_DURATION = 30 * 60 * 1000; // 30 minutes // 4x the number of CPUs, clamped between 2 and 16 const SYNC_PARALLELISM = Math.max(Math.min(os.cpus().length * 4, 16), 2); const SYNC_INTERRUPT_TIMEOUT = 30 * 1000; // 30 seconds + const COMPACTION_THRESHOLD = 100_000; // Sync const BAD_PEER_BLOCK_TIMEOUT = 5 * 60 * 60 * 1000; // 5 hours, arbitrary, may need to be adjusted as network grows const BAD_PEER_MESSAGE_THRESHOLD = 1000; // Number of messages we can't merge before we consider a peer "bad" @@ -115,6 +117,7 @@ class CurrentSyncStatus { fidRetryMessageQ = new Map(); seriousValidationFailures = 0; initialSync = false; + numParallelFetches = 0; constructor(peerId?: string) { if (peerId) { @@ -533,12 +536,15 @@ class SyncEngine extends TypedEmitter { log.info({ peerId }, "Perform sync: Start"); const start = Date.now(); - const fullSyncResult = new MergeResult(); - try { - this._currentSyncStatus = new CurrentSyncStatus(peerId); + this._currentSyncStatus = new CurrentSyncStatus(peerId); + const syncTimeout = setTimeout(() => { + this._currentSyncStatus.interruptSync = true; + log.warn({ peerId, durationMs: Date.now() - start }, "Perform sync: Sync timed out, interrupting sync"); + }, SYNC_MAX_DURATION); + try { // Get the snapshot of our trie, at the same prefix as the peer's snapshot const snapshot = await this.getSnapshot(otherSnapshot.prefix); if (snapshot.isErr()) { @@ -571,7 +577,7 @@ class SyncEngine extends TypedEmitter { "Divergence prefix", ); - await this.fetchMissingHashesByPrefix(divergencePrefix, rpcClient, async (missingIds: Uint8Array[]) => { + await this.compareNodeAtPrefix(divergencePrefix, rpcClient, async (missingIds: Uint8Array[]) => { const result = await this.fetchAndMergeMessages(missingIds, rpcClient); fullSyncResult.addResult(result); progressBar?.increment(result.total); @@ -607,6 +613,10 @@ class SyncEngine extends TypedEmitter { log.warn(e, "Perform sync: Error"); } finally { this._currentSyncStatus.isSyncing = false; + this._currentSyncStatus.interruptSync = false; + + clearTimeout(syncTimeout); + if (this._currentSyncStatus.initialSync) { finishAllProgressBars(true); } @@ -777,15 +787,15 @@ class SyncEngine extends TypedEmitter { return result; } - async fetchMissingHashesByPrefix( + async compareNodeAtPrefix( prefix: Uint8Array, rpcClient: HubRpcClient, onMissingHashes: (missingHashes: Uint8Array[]) => Promise, - ): Promise { + ): Promise { // Check if we should interrupt the sync if (this._currentSyncStatus.interruptSync) { log.info("Interrupting sync"); - return; + return -1; } const ourNode = await this._trie.getTrieNodeMetadata(prefix); @@ -799,14 +809,15 @@ class SyncEngine extends TypedEmitter { if (theirNodeResult.isErr()) { log.warn(theirNodeResult.error, `Error fetching metadata for prefix ${prefix}`); + return -2; } else if (theirNodeResult.value.numMessages === 0) { // If there are no messages, we're done, but something is probably wrong, since we should never have // a node with no messages. log.warn({ prefix, peerId: this._currentSyncStatus.peerId }, "No messages for prefix, skipping"); - return; + return -3; } else if (ourNode?.hash === theirNodeResult.value.hash) { // Hashes match, we're done. - return; + return 0; } else { await this.fetchMissingHashesByNode( fromNodeMetadataResponse(theirNodeResult.value), @@ -814,7 +825,7 @@ class SyncEngine extends TypedEmitter { rpcClient, onMissingHashes, ); - return; + return 1; } } @@ -829,6 +840,12 @@ class SyncEngine extends TypedEmitter { return; } + const start = Date.now(); + let fetchedMessages = 0; + let revokedSyncIds = 0; + let numChildrenFetched = 0; + let numChildrenSkipped = 0; + let fetchMessagesThreshold = HASHES_PER_FETCH; // If we have more messages but the hashes still mismatch, we need to find the exact message that's missing. if (ourNode && ourNode.numMessages >= 1) { @@ -883,12 +900,14 @@ class SyncEngine extends TypedEmitter { ); // Don't wait for this to finish, just return the messages we have. - this.revokeSyncIds(corruptedSyncIds); + await this.revokeSyncIds(corruptedSyncIds); + revokedSyncIds = corruptedSyncIds.length; } } } } } + fetchedMessages = missingHashes.length; await onMissingHashes(missingHashes); } } else if (theirNode.children) { @@ -900,25 +919,43 @@ class SyncEngine extends TypedEmitter { for (const [theirChildChar, theirChild] of reversedEntries) { // recursively fetch hashes for every node where the hashes don't match if (ourNode?.children?.get(theirChildChar)?.hash !== theirChild.hash) { - const r = this.fetchMissingHashesByPrefix(theirChild.prefix, rpcClient, onMissingHashes); + const r = this.compareNodeAtPrefix(theirChild.prefix, rpcClient, onMissingHashes); + numChildrenFetched += 1; // If we're fetching more than HASHES_PER_FETCH, we'll wait for the first batch to finish before starting // the next. - if (theirNode.numMessages < HASHES_PER_FETCH * SYNC_PARALLELISM) { + if (this._currentSyncStatus.numParallelFetches < SYNC_PARALLELISM) { promises.push(r); + + this._currentSyncStatus.numParallelFetches += 1; } else { await r; } + } else { + // Hashes match, not recursively fetching + numChildrenSkipped += 1; } } - await Promise.all(promises); + const r = await Promise.all(promises); + this._currentSyncStatus.numParallelFetches -= r.length; } else { log.error( { theirNode, ourNode }, `Their node has no children, but has more than ${fetchMessagesThreshold} messages`, ); } + + const end = Date.now(); + if (this._syncProfiler) { + this._syncProfiler.writeNodeProfile( + `${formatPrefix(theirNode.prefix)}, ${end - start}, ${ourNode?.numMessages ?? 0}, ${ + theirNode.numMessages + }, ${fetchedMessages}, ${revokedSyncIds}, ${numChildrenFetched}, ${numChildrenSkipped}, ${ + this._currentSyncStatus.numParallelFetches + }`, + ); + } } public findCorruptedSyncIDs(messages: Message[], syncIds: Uint8Array[]): Uint8Array[] { diff --git a/apps/hubble/src/network/sync/syncEngineProfiler.ts b/apps/hubble/src/network/sync/syncEngineProfiler.ts index 2ae1dd91c8..f19a8480ea 100644 --- a/apps/hubble/src/network/sync/syncEngineProfiler.ts +++ b/apps/hubble/src/network/sync/syncEngineProfiler.ts @@ -1,5 +1,6 @@ import { HubRpcClient } from "@farcaster/hub-nodejs"; import { formatNumber } from "../../profile/profile.js"; +import * as fs from "fs"; // Class to collect stats export class MethodCallProfile { @@ -86,6 +87,7 @@ export class MethodProfile { export class SyncEngineProfiler { private _methodProfiles: Map; private _syncStartTime: number; + private syncTrieNodeProfiles: fs.WriteStream; constructor() { this._methodProfiles = new Map(); @@ -96,6 +98,17 @@ export class SyncEngineProfiler { this._methodProfiles.set("mergeMessages", new MethodProfile("mergeMessages")); this._syncStartTime = 0; + + // Open a new file called "nodeprofiles.log" and write to it + this.syncTrieNodeProfiles = fs.createWriteStream("nodeprofiles.log"); + } + + public writeNodeProfile(nodeProfile: string) { + this.syncTrieNodeProfiles.write(nodeProfile + "\n"); + } + + public writeOutNodeProfiles() { + this.syncTrieNodeProfiles.end(); } public getAllMethodProfiles(): Map { diff --git a/apps/hubble/src/network/sync/syncId.ts b/apps/hubble/src/network/sync/syncId.ts index c97a3d39fe..8d80c76534 100644 --- a/apps/hubble/src/network/sync/syncId.ts +++ b/apps/hubble/src/network/sync/syncId.ts @@ -73,4 +73,18 @@ const prefixToTimestamp = (prefix: string): number => { return parseInt(prefix.padEnd(TIMESTAMP_LENGTH, "0"), 10); }; -export { SyncId, timestampToPaddedTimestampPrefix, prefixToTimestamp, TIMESTAMP_LENGTH, HASH_LENGTH }; +const prettyFormatPrefix = (prefix: Uint8Array): string => { + const timePart = Buffer.from(prefix.slice(0, TIMESTAMP_LENGTH)).toString(); + const hashPart = Buffer.from(prefix.slice(TIMESTAMP_LENGTH)).toString("hex"); + + return `${timePart}${hashPart ? `/${hashPart}` : ""}`; +}; + +export { + SyncId, + timestampToPaddedTimestampPrefix, + prefixToTimestamp, + prettyFormatPrefix as formatPrefix, + TIMESTAMP_LENGTH, + HASH_LENGTH, +}; diff --git a/apps/hubble/src/profile/profile.ts b/apps/hubble/src/profile/profile.ts index f4ee655f0f..e4a81ee649 100644 --- a/apps/hubble/src/profile/profile.ts +++ b/apps/hubble/src/profile/profile.ts @@ -2,6 +2,7 @@ import { RootPrefix, UserMessagePostfixMax, UserPostfix } from "../storage/db/ty import { logger } from "../utils/logger.js"; import RocksDB from "../storage/db/rocksdb.js"; import { createWriteStream, unlinkSync } from "fs"; +import { Result } from "neverthrow"; // rome-ignore lint/suspicious/noExplicitAny: Generic check for enums needs 'any' function getMaxValue(enumType: any): number { @@ -310,7 +311,7 @@ export async function profileStorageUsed(rocksDB: RocksDB, fidProfileFileName?: ); // Caclulate the individual message sizes - const valueStats = Array.from({ length: 7 }, (_v, i: number) => new ValueStats(UserPostfix[i]?.toString())); + const valueStats = Array.from({ length: 8 }, (_v, i: number) => new ValueStats(UserPostfix[i]?.toString())); const allFids = new Map(); // Iterate over all the keys in the DB @@ -337,7 +338,7 @@ export async function profileStorageUsed(rocksDB: RocksDB, fidProfileFileName?: (userPostfixKeys[postfix] as KeysProfile).keyBytes += key?.length || 0; (userPostfixKeys[postfix] as KeysProfile).valueBytes += value?.length || 0; - if (postfix <= UserPostfix.UserDataMessage) { + if (postfix < UserMessagePostfixMax) { const fid = key.slice(1, 5).readUint32BE(); let fidProfile; @@ -346,7 +347,7 @@ export async function profileStorageUsed(rocksDB: RocksDB, fidProfileFileName?: fidProfile = allFids.get(fid) as ValueStats[]; } else { fidProfile = Array.from( - { length: 7 }, + { length: 8 }, (_v, i: number) => new ValueStats(UserPostfix[i]?.toString()), ); allFids.set(fid, fidProfile); @@ -400,7 +401,10 @@ export async function profileStorageUsed(rocksDB: RocksDB, fidProfileFileName?: if (fidProfileFileName) { // Remove file if it exists - unlinkSync(fidProfileFileName); + Result.fromThrowable( + () => unlinkSync(fidProfileFileName), + (e) => e, + )(); // Open a CSV file for writing const csvStream = createWriteStream(fidProfileFileName); diff --git a/apps/hubble/src/storage/db/rocksdb.ts b/apps/hubble/src/storage/db/rocksdb.ts index afb62e5de7..63e5d56073 100644 --- a/apps/hubble/src/storage/db/rocksdb.ts +++ b/apps/hubble/src/storage/db/rocksdb.ts @@ -1,9 +1,15 @@ -import { bytesIncrement, HubError, isHubError } from "@farcaster/hub-nodejs"; +import { bytesIncrement, HubError, HubResult, isHubError } from "@farcaster/hub-nodejs"; import { AbstractBatch, AbstractChainedBatch, AbstractIterator } from "abstract-leveldown"; import { mkdir } from "fs"; import AbstractRocksDB from "@farcaster/rocksdb"; import { logger } from "../../utils/logger.js"; -import { statsd } from "../../utils/statsd.js"; +import * as tar from "tar"; +import * as zlib from "zlib"; +import * as fs from "fs"; +import { err, ok, Result } from "neverthrow"; +import path from "path"; +import { Transform } from "stream"; +import { SingleBar } from "cli-progress"; export const DB_DIRECTORY = ".rocks"; export const MAX_DB_ITERATOR_OPEN_MILLISECONDS = 60 * 1000; // 1 min @@ -422,3 +428,89 @@ class RocksDB { } export default RocksDB; + +export async function createTarBackup(inputDir: string): Promise> { + // Output path is {dirname}-{date as yyyy-mm-dd}-{timestamp}.tar.gz + const outputFilePath = `${inputDir}-${new Date().toISOString().split("T")[0]}-${Math.floor( + Date.now() / 1000, + )}.tar.gz`; + + const start = Date.now(); + log.info({ inputDir, outputFilePath }, "Creating tarball"); + + return new Promise((resolve) => { + tar + .c({ gzip: true, file: outputFilePath, cwd: path.dirname(inputDir) }, [path.basename(inputDir)]) + .then(() => { + const stats = fs.statSync(outputFilePath); + log.info({ size: stats.size, outputFilePath, timeTakenMs: Date.now() - start }, "Tarball created"); + resolve(ok(outputFilePath)); + }) + .catch((e: Error) => { + log.error({ error: e, inputDir, outputFilePath }, "Error creating tarball"); + resolve(err(e)); + }); + }); +} +export async function extractTarBackup( + tarFilePath: string, + newTopLevelDir: string, + progressBar?: SingleBar, +): Promise> { + // Output directory is the same name as the tar file without the extension + const outputDir = path.dirname(tarFilePath); + const totalSize = progressBar?.getTotal() ?? 1; + let bytesProcessed = 0; + + return new Promise((resolve) => { + const gunzip = zlib.createGunzip(); + const parseStream = new tar.Parse(); + + parseStream.on("entry", (entry) => { + const newPath = path.join(outputDir, newTopLevelDir, ...entry.path.split(path.sep).slice(1)); + const newDir = path.dirname(newPath); + + if (entry.type === "Directory") { + fs.mkdirSync(newPath, { recursive: true }); + entry.resume(); + } else { + fs.mkdirSync(newDir, { recursive: true }); + entry.pipe(fs.createWriteStream(newPath)); + } + }); + + const handleError = (e: Error) => { + log.error({ error: e, tarFilePath, outputDir }, "Error extracting tarball"); + resolve(err(e)); + }; + + const progressStream = new Transform({ + transform(chunk, _encoding, callback) { + bytesProcessed += chunk.length; + progressBar?.update(bytesProcessed); + callback(null, chunk); + }, + }); + + try { + fs.createReadStream(tarFilePath) + .on("error", handleError) + .pipe(progressStream) + .pipe(gunzip) // Ungzip on the fly + .on("error", handleError) + .pipe(parseStream) + .on("end", () => { + log.info({ tarFilePath, newTopLevelDir, outputDir }, "Tarball extracted with new top-level directory"); + + progressBar?.update(totalSize); + progressBar?.stop(); + + resolve(ok(outputDir)); + }); + } catch (e) { + handleError(e as Error); + progressBar?.update(totalSize); + progressBar?.stop(); + } + }); +} diff --git a/apps/hubble/src/storage/stores/storeEventHandler.ts b/apps/hubble/src/storage/stores/storeEventHandler.ts index d06a40c931..cce8125edb 100644 --- a/apps/hubble/src/storage/stores/storeEventHandler.ts +++ b/apps/hubble/src/storage/stores/storeEventHandler.ts @@ -345,13 +345,17 @@ class StoreEventHandler extends TypedEmitter { return err(iteratorOpts.error); } - const result = await this._db.forEachIterator(async (key, _value) => { - const result = await ResultAsync.fromPromise(this._db.del(key as Buffer), (e) => e as HubError); - if (result.isErr()) { - return err(result.error); - } - return false; - }, iteratorOpts.value); + const result = await this._db.forEachIterator( + async (key, _value) => { + const result = await ResultAsync.fromPromise(this._db.del(key as Buffer), (e) => e as HubError); + if (result.isErr()) { + return err(result.error); + } + return false; + }, + iteratorOpts.value, + 10 * 60 * 1000, // 10 minutes + ); if (result) { return err(result.error); diff --git a/apps/hubble/src/utils/logger.ts b/apps/hubble/src/utils/logger.ts index 61f771ec66..e1e4fb0056 100644 --- a/apps/hubble/src/utils/logger.ts +++ b/apps/hubble/src/utils/logger.ts @@ -46,7 +46,7 @@ const MAX_BUFFERLOG_SIZE = 1_000_000; // Disable logging in tests and CI to reduce noise if (process.env["NODE_ENV"] === "test" || process.env["CI"]) { - // defaultOptions.level = 'debug'; + // defaultOptions.level = "debug"; defaultOptions.level = "silent"; } else if (process.env["LOG_LEVEL"]) { defaultOptions.level = process.env["LOG_LEVEL"]; diff --git a/apps/hubble/src/utils/rateLimits.test.ts b/apps/hubble/src/utils/rateLimits.test.ts index e5801ccab0..c6a85b1658 100644 --- a/apps/hubble/src/utils/rateLimits.test.ts +++ b/apps/hubble/src/utils/rateLimits.test.ts @@ -24,7 +24,7 @@ describe("test rate limits", () => { if (i < 10) { expect(result.isOk()).toBeTruthy(); } else { - expect(result._unsafeUnwrapErr().message).toEqual("Too many requests"); + expect(result._unsafeUnwrapErr().message).toEqual("Too many requests for testip"); } } }); @@ -52,7 +52,7 @@ describe("test rate limits", () => { if (i < 10) { expect(result1.isOk()).toBeTruthy(); } else { - expect(result1._unsafeUnwrapErr().message).toEqual("Too many requests"); + expect(result1._unsafeUnwrapErr().message).toEqual("Too many requests for 3000"); } // same key, but different rate limiter should pass till the 11th message @@ -60,7 +60,7 @@ describe("test rate limits", () => { if (i < 11) { expect(result2.isOk()).toBeTruthy(); } else { - expect(result2._unsafeUnwrapErr().message).toEqual("Too many requests"); + expect(result2._unsafeUnwrapErr().message).toEqual("Too many requests for 3000"); } } }); diff --git a/apps/hubble/src/utils/rateLimits.ts b/apps/hubble/src/utils/rateLimits.ts index c6c7ca6794..9c4e2d2176 100644 --- a/apps/hubble/src/utils/rateLimits.ts +++ b/apps/hubble/src/utils/rateLimits.ts @@ -34,11 +34,11 @@ export const rateLimitByIp = async (ip: string, limiter: RateLimiterAbstract): H }; /** Rate limit by key for the limiter */ -export const rateLimitByKey = async (fid: string, limiter: RateLimiterAbstract): HubAsyncResult => { +export const rateLimitByKey = async (key: string, limiter: RateLimiterAbstract): HubAsyncResult => { try { - await limiter.consume(fid); + await limiter.consume(key); return ok(true); } catch (e) { - return err(new HubError("unavailable", "Too many requests")); + return err(new HubError("unavailable", `Too many requests for ${key}`)); } }; diff --git a/yarn.lock b/yarn.lock index a101d4279a..39e437aa31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -58,6 +58,546 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@aws-crypto/crc32@3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" + integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/crc32c@3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz#016c92da559ef638a84a245eecb75c3e97cb664f" + integrity sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/ie11-detection@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz#640ae66b4ec3395cee6a8e94ebcd9f80c24cd688" + integrity sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/sha1-browser@3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz#f9083c00782b24714f528b1a1fef2174002266a3" + integrity sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw== + dependencies: + "@aws-crypto/ie11-detection" "^3.0.0" + "@aws-crypto/supports-web-crypto" "^3.0.0" + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-browser@3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz#05f160138ab893f1c6ba5be57cfd108f05827766" + integrity sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ== + dependencies: + "@aws-crypto/ie11-detection" "^3.0.0" + "@aws-crypto/sha256-js" "^3.0.0" + "@aws-crypto/supports-web-crypto" "^3.0.0" + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz#f06b84d550d25521e60d2a0e2a90139341e007c2" + integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/supports-web-crypto@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz#5d1bf825afa8072af2717c3e455f35cda0103ec2" + integrity sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/util@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0" + integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/client-s3@^3.400.0": + version "3.400.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.400.0.tgz#579dfa12c93bf12f0d8654fcbfe36f7989209a4d" + integrity sha512-lnv0pb79Czl8fCMs/z7yM56LvoKTri1I4jX/V33trHMFKPQDoy8i24wxG8+TZl3MUmnUyoQS7tlukh7IFkii1Q== + dependencies: + "@aws-crypto/sha1-browser" "3.0.0" + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/client-sts" "3.398.0" + "@aws-sdk/credential-provider-node" "3.398.0" + "@aws-sdk/middleware-bucket-endpoint" "3.398.0" + "@aws-sdk/middleware-expect-continue" "3.398.0" + "@aws-sdk/middleware-flexible-checksums" "3.400.0" + "@aws-sdk/middleware-host-header" "3.398.0" + "@aws-sdk/middleware-location-constraint" "3.398.0" + "@aws-sdk/middleware-logger" "3.398.0" + "@aws-sdk/middleware-recursion-detection" "3.398.0" + "@aws-sdk/middleware-sdk-s3" "3.398.0" + "@aws-sdk/middleware-signing" "3.398.0" + "@aws-sdk/middleware-ssec" "3.398.0" + "@aws-sdk/middleware-user-agent" "3.398.0" + "@aws-sdk/signature-v4-multi-region" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-endpoints" "3.398.0" + "@aws-sdk/util-user-agent-browser" "3.398.0" + "@aws-sdk/util-user-agent-node" "3.398.0" + "@aws-sdk/xml-builder" "3.310.0" + "@smithy/config-resolver" "^2.0.5" + "@smithy/eventstream-serde-browser" "^2.0.5" + "@smithy/eventstream-serde-config-resolver" "^2.0.5" + "@smithy/eventstream-serde-node" "^2.0.5" + "@smithy/fetch-http-handler" "^2.0.5" + "@smithy/hash-blob-browser" "^2.0.5" + "@smithy/hash-node" "^2.0.5" + "@smithy/hash-stream-node" "^2.0.5" + "@smithy/invalid-dependency" "^2.0.5" + "@smithy/md5-js" "^2.0.5" + "@smithy/middleware-content-length" "^2.0.5" + "@smithy/middleware-endpoint" "^2.0.5" + "@smithy/middleware-retry" "^2.0.5" + "@smithy/middleware-serde" "^2.0.5" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/node-http-handler" "^2.0.5" + "@smithy/protocol-http" "^2.0.5" + "@smithy/smithy-client" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.5" + "@smithy/util-defaults-mode-node" "^2.0.5" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-stream" "^2.0.5" + "@smithy/util-utf8" "^2.0.0" + "@smithy/util-waiter" "^2.0.5" + fast-xml-parser "4.2.5" + tslib "^2.5.0" + +"@aws-sdk/client-sso@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.398.0.tgz#68ce0a4d359794b629e5a7efe43a24ed9b52211e" + integrity sha512-CygL0jhfibw4kmWXG/3sfZMFNjcXo66XUuPC4BqZBk8Rj5vFoxp1vZeMkDLzTIk97Nvo5J5Bh+QnXKhub6AckQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.398.0" + "@aws-sdk/middleware-logger" "3.398.0" + "@aws-sdk/middleware-recursion-detection" "3.398.0" + "@aws-sdk/middleware-user-agent" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-endpoints" "3.398.0" + "@aws-sdk/util-user-agent-browser" "3.398.0" + "@aws-sdk/util-user-agent-node" "3.398.0" + "@smithy/config-resolver" "^2.0.5" + "@smithy/fetch-http-handler" "^2.0.5" + "@smithy/hash-node" "^2.0.5" + "@smithy/invalid-dependency" "^2.0.5" + "@smithy/middleware-content-length" "^2.0.5" + "@smithy/middleware-endpoint" "^2.0.5" + "@smithy/middleware-retry" "^2.0.5" + "@smithy/middleware-serde" "^2.0.5" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/node-http-handler" "^2.0.5" + "@smithy/protocol-http" "^2.0.5" + "@smithy/smithy-client" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.5" + "@smithy/util-defaults-mode-node" "^2.0.5" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/client-sts@3.398.0", "@aws-sdk/client-sts@^3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.398.0.tgz#8c569760d05b9fe663f82fc092d39b093096f7cc" + integrity sha512-/3Pa9wLMvBZipKraq3AtbmTfXW6q9kyvhwOno64f1Fz7kFb8ijQFMGoATS70B2pGEZTlxkUqJFWDiisT6Q6dFg== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/credential-provider-node" "3.398.0" + "@aws-sdk/middleware-host-header" "3.398.0" + "@aws-sdk/middleware-logger" "3.398.0" + "@aws-sdk/middleware-recursion-detection" "3.398.0" + "@aws-sdk/middleware-sdk-sts" "3.398.0" + "@aws-sdk/middleware-signing" "3.398.0" + "@aws-sdk/middleware-user-agent" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-endpoints" "3.398.0" + "@aws-sdk/util-user-agent-browser" "3.398.0" + "@aws-sdk/util-user-agent-node" "3.398.0" + "@smithy/config-resolver" "^2.0.5" + "@smithy/fetch-http-handler" "^2.0.5" + "@smithy/hash-node" "^2.0.5" + "@smithy/invalid-dependency" "^2.0.5" + "@smithy/middleware-content-length" "^2.0.5" + "@smithy/middleware-endpoint" "^2.0.5" + "@smithy/middleware-retry" "^2.0.5" + "@smithy/middleware-serde" "^2.0.5" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/node-http-handler" "^2.0.5" + "@smithy/protocol-http" "^2.0.5" + "@smithy/smithy-client" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.5" + "@smithy/util-defaults-mode-node" "^2.0.5" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + fast-xml-parser "4.2.5" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-env@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.398.0.tgz#28d0d4d2de85dd35fdf83298191ea495da8f8646" + integrity sha512-Z8Yj5z7FroAsR6UVML+XUdlpoqEe9Dnle8c2h8/xWwIC2feTfIBhjLhRVxfbpbM1pLgBSNEcZ7U8fwq5l7ESVQ== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-ini@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.398.0.tgz#723264d8d8adb01963fdfe9fe9005aa20def3a56" + integrity sha512-AsK1lStK3nB9Cn6S6ODb1ktGh7SRejsNVQVKX3t5d3tgOaX+aX1Iwy8FzM/ZEN8uCloeRifUGIY9uQFygg5mSw== + dependencies: + "@aws-sdk/credential-provider-env" "3.398.0" + "@aws-sdk/credential-provider-process" "3.398.0" + "@aws-sdk/credential-provider-sso" "3.398.0" + "@aws-sdk/credential-provider-web-identity" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@smithy/credential-provider-imds" "^2.0.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-node@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.398.0.tgz#afc6e6417b071a5a5b242329fd9c80aacba40f7d" + integrity sha512-odmI/DSKfuWUYeDnGTCEHBbC8/MwnF6yEq874zl6+owoVv0ZsYP8qBHfiJkYqrwg7wQ7Pi40sSAPC1rhesGwzg== + dependencies: + "@aws-sdk/credential-provider-env" "3.398.0" + "@aws-sdk/credential-provider-ini" "3.398.0" + "@aws-sdk/credential-provider-process" "3.398.0" + "@aws-sdk/credential-provider-sso" "3.398.0" + "@aws-sdk/credential-provider-web-identity" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@smithy/credential-provider-imds" "^2.0.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-process@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.398.0.tgz#bae46e14bcb664371d33926118bad61866184317" + integrity sha512-WrkBL1W7TXN508PA9wRXPFtzmGpVSW98gDaHEaa8GolAPHMPa5t2QcC/z/cFpglzrcVv8SA277zu9Z8tELdZhg== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-sso@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.398.0.tgz#b8a094e5e62cea233d77e27c8b7e2ce65e9f7559" + integrity sha512-2Dl35587xbnzR/GGZqA2MnFs8+kS4wbHQO9BioU0okA+8NRueohNMdrdQmQDdSNK4BfIpFspiZmFkXFNyEAfgw== + dependencies: + "@aws-sdk/client-sso" "3.398.0" + "@aws-sdk/token-providers" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-web-identity@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.398.0.tgz#0396a34bf9d2e4b48530c2f899cbb4101b592db8" + integrity sha512-iG3905Alv9pINbQ8/MIsshgqYMbWx+NDQWpxbIW3W0MkSH3iAqdVpSCteYidYX9G/jv2Um1nW3y360ib20bvNg== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-bucket-endpoint@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.398.0.tgz#1cff84e1f71043346277f3c1a6268763c631a984" + integrity sha512-+iDHiRofK/vIY94RWAXkSnR4rBPzc2dPHmLp+FDKywq1y708H9W7TOT37dpn+KSFeO4k2FfddFjzWBHsaeakCA== + dependencies: + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-arn-parser" "3.310.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/util-config-provider" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-expect-continue@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.398.0.tgz#a43cbe0a5b339238f5f307c69798da8f69e5c111" + integrity sha512-d6he+Qqwh1yqml9duXSv5iKJ2lS0PVrF2UEsVew2GFxfUif0E/davTZJjvWtnelbuIGcTP+wDKVVjLwBN2sN/g== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-flexible-checksums@3.400.0": + version "3.400.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.400.0.tgz#f3cb1e9f42968d2177b583a83e5027b4d3f70e67" + integrity sha512-lpsumd5/G+eAMTr61h/cJQZ8+i+xzC6OG3bvUcbRHqcjN49XgeNLcPfYcr6Rzf0QHxmuCN4te/4XGU3Fif2YVA== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@aws-crypto/crc32c" "3.0.0" + "@aws-sdk/types" "3.398.0" + "@smithy/is-array-buffer" "^2.0.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-host-header@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.398.0.tgz#4e5eeaa8ead96237e70cb6930dfb813a9c21ae8c" + integrity sha512-m+5laWdBaxIZK2ko0OwcCHJZJ5V1MgEIt8QVQ3k4/kOkN9ICjevOYmba751pHoTnbOYB7zQd6D2OT3EYEEsUcA== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-location-constraint@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.398.0.tgz#ec7d046401d1f547d8dd55bf1c94ed067b10224b" + integrity sha512-it+olJf1Lf2bmH8OL/N1jMOFB0zEVYs4rIzgFrluTRCuPatRuDi4LsXS8zqYxkBa05JE8JmqwW5gCzAmWyLLqw== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-logger@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.398.0.tgz#1f336c329861c2aa7cc267d84ef41e74e98b1502" + integrity sha512-CiJjW+FL12elS6Pn7/UVjVK8HWHhXMfvHZvOwx/Qkpy340sIhkuzOO6fZEruECDTZhl2Wqn81XdJ1ZQ4pRKpCg== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-recursion-detection@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.398.0.tgz#e456d67fc88afac73004a8feae497d3ab24231e4" + integrity sha512-7QpOqPQAZNXDXv6vsRex4R8dLniL0E/80OPK4PPFsrCh9btEyhN9Begh4i1T+5lL28hmYkztLOkTQ2N5J3hgRQ== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-sdk-s3@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.398.0.tgz#3277c50438a34faedc0f1b6380e62196aeffe331" + integrity sha512-yweSMc/TyiFtqc52hFMKQJvTm3i1KCoW5mB3o/Sla6zsHBh+nS6TTaBmo+2kcDIR7AKODwW+FLCTHWiazb7J3Q== + dependencies: + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-arn-parser" "3.310.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-sdk-sts@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.398.0.tgz#f7383c86eedba80666b1a009256a1127d1c4edc6" + integrity sha512-+JH76XHEgfVihkY+GurohOQ5Z83zVN1nYcQzwCFnCDTh4dG4KwhnZKG+WPw6XJECocY0R+H0ivofeALHvVWJtQ== + dependencies: + "@aws-sdk/middleware-signing" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-signing@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.398.0.tgz#ad8f73c2e7ab564eea95568e2e109f41af6128ec" + integrity sha512-O0KqXAix1TcvZBFt1qoFkHMUNJOSgjJTYS7lFTRKSwgsD27bdW2TM2r9R8DAccWFt5Amjkdt+eOwQMIXPGTm8w== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/signature-v4" "^2.0.0" + "@smithy/types" "^2.2.2" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-ssec@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.398.0.tgz#0c4f291e009833858935eb589a94d386cfc45a49" + integrity sha512-QtKr/hPcRugKSIZAH4+7hbUfdW7Lg+OQvD25nJn7ic1JHRZ+eDctEFxdsmnt68lE6aZxOcHCWHAW6/umcA93Dw== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-user-agent@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.398.0.tgz#42542b3697ee6812cb8f81fd19757dc1592af0e0" + integrity sha512-nF1jg0L+18b5HvTcYzwyFgfZQQMELJINFqI0mi4yRKaX7T5a3aGp5RVLGGju/6tAGTuFbfBoEhkhU3kkxexPYQ== + dependencies: + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-endpoints" "3.398.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/signature-v4-multi-region@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.398.0.tgz#3afc781f59a657962e9fd69c0c82a2b083e349d4" + integrity sha512-8fTqTxRDWE03T7ClaWlCfbwuSae//01XMNVy2a9g5QgaelQh7ZZyU3ZIJiV8gIj8v6ZM0NGn9Bz1liI/vmNmcw== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/signature-v4" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/token-providers@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.398.0.tgz#62fc8f5379df0e94486d71b96df975fb7e7d04cc" + integrity sha512-nrYgjzavGCKJL/48Vt0EL+OlIc5UZLfNGpgyUW9cv3XZwl+kXV0QB+HH0rHZZLfpbBgZ2RBIJR9uD5ieu/6hpQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.398.0" + "@aws-sdk/middleware-logger" "3.398.0" + "@aws-sdk/middleware-recursion-detection" "3.398.0" + "@aws-sdk/middleware-user-agent" "3.398.0" + "@aws-sdk/types" "3.398.0" + "@aws-sdk/util-endpoints" "3.398.0" + "@aws-sdk/util-user-agent-browser" "3.398.0" + "@aws-sdk/util-user-agent-node" "3.398.0" + "@smithy/config-resolver" "^2.0.5" + "@smithy/fetch-http-handler" "^2.0.5" + "@smithy/hash-node" "^2.0.5" + "@smithy/invalid-dependency" "^2.0.5" + "@smithy/middleware-content-length" "^2.0.5" + "@smithy/middleware-endpoint" "^2.0.5" + "@smithy/middleware-retry" "^2.0.5" + "@smithy/middleware-serde" "^2.0.5" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/node-http-handler" "^2.0.5" + "@smithy/property-provider" "^2.0.0" + "@smithy/protocol-http" "^2.0.5" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/smithy-client" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.1.0" + "@smithy/util-defaults-mode-browser" "^2.0.5" + "@smithy/util-defaults-mode-node" "^2.0.5" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/types@3.398.0", "@aws-sdk/types@^3.222.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.398.0.tgz#8ce02559536670f9188cddfce32e9dd12b4fe965" + integrity sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/util-arn-parser@3.310.0": + version "3.310.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz#861ff8810851be52a320ec9e4786f15b5fc74fba" + integrity sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-endpoints@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.398.0.tgz#cb1cc5fe3e4b3839e4e1cc6a66f834cf0dde20ee" + integrity sha512-Fy0gLYAei/Rd6BrXG4baspCnWTUSd0NdokU1pZh4KlfEAEN1i8SPPgfiO5hLk7+2inqtCmqxVJlfqbMVe9k4bw== + dependencies: + "@aws-sdk/types" "3.398.0" + tslib "^2.5.0" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.310.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz#b071baf050301adee89051032bd4139bba32cc40" + integrity sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-browser@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.398.0.tgz#5c3e430032eb867b7cbe48dda51a6d8c4ea000a8" + integrity sha512-A3Tzx1tkDHlBT+IgxmsMCHbV8LM7SwwCozq2ZjJRx0nqw3MCrrcxQFXldHeX/gdUMO+0Oocb7HGSnVODTq+0EA== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/types" "^2.2.2" + bowser "^2.11.0" + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-node@3.398.0": + version "3.398.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.398.0.tgz#1707737ee67c864d74a03137003b6d2b28172ee6" + integrity sha512-RTVQofdj961ej4//fEkppFf4KXqKGMTCqJYghx3G0C/MYXbg7MGl7LjfNGtJcboRE8pfHHQ/TUWBDA7RIAPPlQ== + dependencies: + "@aws-sdk/types" "3.398.0" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + +"@aws-sdk/xml-builder@3.310.0": + version "3.310.0" + resolved "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz#f0236f2103b438d16117e0939a6305ad69b7ff76" + integrity sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw== + dependencies: + tslib "^2.5.0" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" @@ -2267,6 +2807,433 @@ dependencies: "@sinonjs/commons" "^2.0.0" +"@smithy/abort-controller@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.5.tgz#9602a9b362e84c0d043d820c4aba5d9b78028a84" + integrity sha512-byVZ2KWLMPYAZGKjRpniAzLcygJO4ruClZKdJTuB0eCB76ONFTdptBHlviHpAZXknRz7skYWPfcgO9v30A1SyA== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/chunked-blob-reader-native@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.0.tgz#f6d0eeeb5481026b68b054f45540d924c194d558" + integrity sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ== + dependencies: + "@smithy/util-base64" "^2.0.0" + tslib "^2.5.0" + +"@smithy/chunked-blob-reader@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz#c44fe2c780eaf77f9e5381d982ac99a880cce51b" + integrity sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg== + dependencies: + tslib "^2.5.0" + +"@smithy/config-resolver@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.5.tgz#d64c1c83a773ca5a038146d4b537c202b6c6bfaf" + integrity sha512-n0c2AXz+kjALY2FQr7Zy9zhYigXzboIh1AuUUVCqFBKFtdEvTwnwPXrTDoEehLiRTUHNL+4yzZ3s+D0kKYSLSg== + dependencies: + "@smithy/types" "^2.2.2" + "@smithy/util-config-provider" "^2.0.0" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@smithy/credential-provider-imds@^2.0.0", "@smithy/credential-provider-imds@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.5.tgz#59e6f8d30beed9e966d418f47108bb4da371bbae" + integrity sha512-KFcf/e0meFkQNyteJ65f1G19sgUEY1e5zL7hyAEUPz2SEfBmC9B37WyRq87G3MEEsvmAWwCRu7nFFYUKtR3svQ== + dependencies: + "@smithy/node-config-provider" "^2.0.5" + "@smithy/property-provider" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + tslib "^2.5.0" + +"@smithy/eventstream-codec@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.5.tgz#771f50657f1958db3e19b9f2726d62e2e0672546" + integrity sha512-iqR6OuOV3zbQK8uVs9o+9AxhVk8kW9NAxA71nugwUB+kTY9C35pUd0A5/m4PRT0Y0oIW7W4kgnSR3fdYXQjECw== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@smithy/types" "^2.2.2" + "@smithy/util-hex-encoding" "^2.0.0" + tslib "^2.5.0" + +"@smithy/eventstream-serde-browser@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.5.tgz#5f4d3d78a9fcb0a5a6f5b20f69141c8cc6b0ef6b" + integrity sha512-8NU51y94qFJbxL6SmvgWDfITHO/svvbAigkLYk2pckX17TGCSf4EXuGpGLliJp5Ljh5+vASC7mUH2jYX7MWBxA== + dependencies: + "@smithy/eventstream-serde-universal" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/eventstream-serde-config-resolver@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.5.tgz#1e551a308dc2e91b8c732815077dbf99beb1300f" + integrity sha512-u3gvukRaTH4X6tsryuZ4T1WGIEP34fPaTTzphFDJe8GJz/k11oBW1MPnkcaucBMxLnObK9swCF85j5cp1Kj1oA== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/eventstream-serde-node@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.5.tgz#ceea04afcef95caf0e4148c606721c1882a1d9b5" + integrity sha512-/C8jb+k/vKUBIe80D30vzjvRXlJf76kG2AJY7/NwiqWuD2usRuuDFCDaswXdVsSh9P1+FeaxZ48chsK10yDryQ== + dependencies: + "@smithy/eventstream-serde-universal" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/eventstream-serde-universal@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.5.tgz#5a656557575ee4ad69515434e45f19f7816f09f8" + integrity sha512-+vHvbQtlSVYTQ/20tNpVaKi0EpTR7E8GoEUHJypRZIRgiT03b3h2MAWk+SNaqMrCJrYG9vKLkJFzDylRlUvDWg== + dependencies: + "@smithy/eventstream-codec" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/fetch-http-handler@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.0.5.tgz#822510720598b4306e7c71e839eea34b6928c66b" + integrity sha512-EzFoMowdBNy1VqtvkiXgPFEdosIAt4/4bgZ8uiDiUyfhmNXq/3bV+CagPFFBsgFOR/X2XK4zFZHRsoa7PNHVVg== + dependencies: + "@smithy/protocol-http" "^2.0.5" + "@smithy/querystring-builder" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/util-base64" "^2.0.0" + tslib "^2.5.0" + +"@smithy/hash-blob-browser@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.5.tgz#5cc622f6d448f3e87134eb6d4c4b608b5a4e2002" + integrity sha512-ZVAUBtJXGf9bEko4/RwWcTK6d3b/ZmQMxJMrxOOcQhVDiqny9zI0mzgstO4Oxz3135R7S3V/bbGw3w3woCYpQg== + dependencies: + "@smithy/chunked-blob-reader" "^2.0.0" + "@smithy/chunked-blob-reader-native" "^2.0.0" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/hash-node@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.5.tgz#f3558c1553f846148c3e5d10a815429e1b357668" + integrity sha512-mk551hIywBITT+kXruRNXk7f8Fy7DTzBjZJSr/V6nolYKmUHIG3w5QU6nO9qPYEQGKc/yEPtkpdS28ndeG93lA== + dependencies: + "@smithy/types" "^2.2.2" + "@smithy/util-buffer-from" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/hash-stream-node@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.5.tgz#98175965ee7057312b464fcd63e8e1bd4142e38e" + integrity sha512-XiR4Aoux5kXy8OWPLQisKy3GPmm0l6deHepvPvr4MUzIwa5XWazG3JdbZXy+mk93CvEZrOwKPHU5Kul6QybJiQ== + dependencies: + "@smithy/types" "^2.2.2" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/invalid-dependency@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.5.tgz#b07bdbc43403977b8bcae6de19a96e184f2eb655" + integrity sha512-0wEi+JT0hM+UUwrJVYbqjuGFhy5agY/zXyiN7BNAJ1XoCDjU5uaNSj8ekPWsXd/d4yM6NSe8UbPd8cOc1+3oBQ== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/is-array-buffer@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz#8fa9b8040651e7ba0b2f6106e636a91354ff7d34" + integrity sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug== + dependencies: + tslib "^2.5.0" + +"@smithy/md5-js@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.5.tgz#02173e4e21105819efa8ebaa17eab23d5663f896" + integrity sha512-k5EOte/Ye2r7XBVaXv2rhiehk6l3T4uRiPF+pnxKEc+G9Fwd1xAXBDZrtOq1syFPBKBmVfNszG4nevngST7NKg== + dependencies: + "@smithy/types" "^2.2.2" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/middleware-content-length@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.5.tgz#b2008c6b664c4c67fb255ef5a9fd5f4bd2c914f6" + integrity sha512-E7VwV5H02fgZIUGRli4GevBCAPvkyEI/fgl9SU47nPPi3DAAX3nEtUb8xfGbXjOcJ5BdSUoWWZn42tEd/blOqA== + dependencies: + "@smithy/protocol-http" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/middleware-endpoint@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.5.tgz#6a16361dc527262958194e48343733ac6285776b" + integrity sha512-tyzDuoNTbsMQCq5Xkc4QOt6e2GACUllQIV8SQ5fc59FtOIV9/vbf58/GxVjZm2o8+MMbdDBANjTDZe/ijZKfyA== + dependencies: + "@smithy/middleware-serde" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/url-parser" "^2.0.5" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@smithy/middleware-retry@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.5.tgz#bbf8858aeccdfe11837f89635cb6ce8a8e304518" + integrity sha512-ulIfbFyzQTVnJbLjUl1CTSi0etg6tej/ekwaLp0Gn8ybUkDkKYa+uB6CF/m2J5B6meRwyJlsryR+DjaOVyiicg== + dependencies: + "@smithy/protocol-http" "^2.0.5" + "@smithy/service-error-classification" "^2.0.0" + "@smithy/types" "^2.2.2" + "@smithy/util-middleware" "^2.0.0" + "@smithy/util-retry" "^2.0.0" + tslib "^2.5.0" + uuid "^8.3.2" + +"@smithy/middleware-serde@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.5.tgz#3f3635cb437a3fba46cd1407d3adf53d41328574" + integrity sha512-in0AA5sous74dOfTGU9rMJBXJ0bDVNxwdXtEt5lh3FVd2sEyjhI+rqpLLRF1E4ixbw3RSEf80hfRpcPdjg4vvQ== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/middleware-stack@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.0.tgz#cd9f442c2788b1ef0ea6b32236d80c76b3c342e9" + integrity sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ== + dependencies: + tslib "^2.5.0" + +"@smithy/node-config-provider@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.5.tgz#239a6281e1d0bc2a0dd8fdab7826bacd25dfbf00" + integrity sha512-LRtjV9WkhONe2lVy+ipB/l1GX60ybzBmFyeRUoLUXWKdnZ3o81jsnbKzMK8hKq8eFSWPk+Lmyx6ZzCQabGeLxg== + dependencies: + "@smithy/property-provider" "^2.0.5" + "@smithy/shared-ini-file-loader" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/node-http-handler@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.0.5.tgz#19c1bdd4d61502bc9c793dddb8ce995626ca6585" + integrity sha512-lZm5DZf4b3V0saUw9WTC4/du887P6cy2fUyQgQQKRRV6OseButyD5yTzeMmXE53CaXJBMBsUvvIQ0hRVxIq56w== + dependencies: + "@smithy/abort-controller" "^2.0.5" + "@smithy/protocol-http" "^2.0.5" + "@smithy/querystring-builder" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/property-provider@^2.0.0", "@smithy/property-provider@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.5.tgz#7cc88bc56706a4758076754a71c6a9ebf5daa8a7" + integrity sha512-cAFSUhX6aiHcmpWfrCLKvwBtgN1F6A0N8qY/8yeSi0LRLmhGqsY1/YTxFE185MCVzYbqBGXVr9TBv4RUcIV4rA== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/protocol-http@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-2.0.5.tgz#ff7779fc8fcd3fe52e71fd07565b518f0937e8ba" + integrity sha512-d2hhHj34mA2V86doiDfrsy2fNTnUOowGaf9hKb0hIPHqvcnShU4/OSc4Uf1FwHkAdYF3cFXTrj5VGUYbEuvMdw== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/querystring-builder@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.5.tgz#c5a873769de56ef57ae3b4d2c58fc7f68184a89c" + integrity sha512-4DCX9krxLzATj+HdFPC3i8pb7XTAWzzKqSw8aTZMjXjtQY+vhe4azMAqIvbb6g7JKwIkmkRAjK6EXO3YWSnJVQ== + dependencies: + "@smithy/types" "^2.2.2" + "@smithy/util-uri-escape" "^2.0.0" + tslib "^2.5.0" + +"@smithy/querystring-parser@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.5.tgz#aec6733ed4497402634978e7026d0d00661594d6" + integrity sha512-C2stCULH0r54KBksv3AWcN8CLS3u9+WsEW8nBrvctrJ5rQTNa1waHkffpVaiKvcW2nP0aIMBPCobD/kYf/q9mA== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/service-error-classification@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.0.tgz#bbce07c9c529d9333d40db881fd4a1795dd84892" + integrity sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw== + +"@smithy/shared-ini-file-loader@^2.0.0", "@smithy/shared-ini-file-loader@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.5.tgz#c2b28b499f2b9928e892a80fcdeb259b2938475c" + integrity sha512-Mvtk6FwMtfbKRC4YuSsIqRYp9WTxsSUJVVo2djgyhcacKGMqicHDWSAmgy3sDrKv+G/G6xTZCPwm6pJARtdxVg== + dependencies: + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/signature-v4@^2.0.0": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.5.tgz#48fbc1a25f2f44bbd9217927518c8fe439419f4d" + integrity sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A== + dependencies: + "@smithy/eventstream-codec" "^2.0.5" + "@smithy/is-array-buffer" "^2.0.0" + "@smithy/types" "^2.2.2" + "@smithy/util-hex-encoding" "^2.0.0" + "@smithy/util-middleware" "^2.0.0" + "@smithy/util-uri-escape" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/smithy-client@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.0.5.tgz#7941449f146d2c61d34670779d77d4a085141bc1" + integrity sha512-kCTFr8wfOAWKDzGvfBElc6shHigWtHNhMQ1IbosjC4jOlayFyZMSs2PysKB+Ox/dhQ41KqOzgVjgiQ+PyWqHMQ== + dependencies: + "@smithy/middleware-stack" "^2.0.0" + "@smithy/types" "^2.2.2" + "@smithy/util-stream" "^2.0.5" + tslib "^2.5.0" + +"@smithy/types@^2.2.2": + version "2.2.2" + resolved "https://registry.npmjs.org/@smithy/types/-/types-2.2.2.tgz#bd8691eb92dd07ac33b83e0e1c45f283502b1bf7" + integrity sha512-4PS0y1VxDnELGHGgBWlDksB2LJK8TG8lcvlWxIsgR+8vROI7Ms8h1P4FQUx+ftAX2QZv5g1CJCdhdRmQKyonyw== + dependencies: + tslib "^2.5.0" + +"@smithy/url-parser@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.5.tgz#09fa623076bb5861892930628bf368d5c79fd7d9" + integrity sha512-OdMBvZhpckQSkugCXNJQCvqJ71wE7Ftxce92UOQLQ9pwF6hoS5PLL7wEfpnuEXtStzBqJYkzu1C1ZfjuFGOXAA== + dependencies: + "@smithy/querystring-parser" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/util-base64@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz#1beeabfb155471d1d41c8d0603be1351f883c444" + integrity sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA== + dependencies: + "@smithy/util-buffer-from" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-body-length-browser@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz#5447853003b4c73da3bc5f3c5e82c21d592d1650" + integrity sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg== + dependencies: + tslib "^2.5.0" + +"@smithy/util-body-length-node@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz#313a5f7c5017947baf5fa018bfc22628904bbcfa" + integrity sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw== + dependencies: + tslib "^2.5.0" + +"@smithy/util-buffer-from@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz#7eb75d72288b6b3001bc5f75b48b711513091deb" + integrity sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw== + dependencies: + "@smithy/is-array-buffer" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-config-provider@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz#4dd6a793605559d94267312fd06d0f58784b4c38" + integrity sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg== + dependencies: + tslib "^2.5.0" + +"@smithy/util-defaults-mode-browser@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.5.tgz#36d5424749d324bd69f37c74ea20a183f8c2286e" + integrity sha512-yciP6TPttLsj731aHTvekgyuCGXQrEAJibEwEWAh3kzaDsfGAVCuZSBlyvC2Dl3TZmHKCOQwHV8mIE7KQCTPuQ== + dependencies: + "@smithy/property-provider" "^2.0.5" + "@smithy/types" "^2.2.2" + bowser "^2.11.0" + tslib "^2.5.0" + +"@smithy/util-defaults-mode-node@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.5.tgz#504dd39a603fd2d67e53537c794dd57e6541baae" + integrity sha512-M07t99rWasXt+IaDZDyP3BkcoEm/mgIE1RIMASrE49LKSNxaVN7PVcgGc77+4uu2kzBAyqJKy79pgtezuknyjQ== + dependencies: + "@smithy/config-resolver" "^2.0.5" + "@smithy/credential-provider-imds" "^2.0.5" + "@smithy/node-config-provider" "^2.0.5" + "@smithy/property-provider" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + +"@smithy/util-hex-encoding@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz#0aa3515acd2b005c6d55675e377080a7c513b59e" + integrity sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-middleware@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.0.tgz#706681d4a1686544a2275f68266304233f372c99" + integrity sha512-eCWX4ECuDHn1wuyyDdGdUWnT4OGyIzV0LN1xRttBFMPI9Ff/4heSHVxneyiMtOB//zpXWCha1/SWHJOZstG7kA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-retry@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.0.tgz#7ac5d5f12383a9d9b2a43f9ff25f3866c8727c24" + integrity sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg== + dependencies: + "@smithy/service-error-classification" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-stream@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.5.tgz#a59f6e5327dfa23c3302f578ea023674fc7fa42f" + integrity sha512-ylx27GwI05xLpYQ4hDIfS15vm+wYjNN0Sc2P0FxuzgRe8v0BOLHppGIQ+Bezcynk8C9nUzsUue3TmtRhjut43g== + dependencies: + "@smithy/fetch-http-handler" "^2.0.5" + "@smithy/node-http-handler" "^2.0.5" + "@smithy/types" "^2.2.2" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-buffer-from" "^2.0.0" + "@smithy/util-hex-encoding" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-uri-escape@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz#19955b1a0f517a87ae77ac729e0e411963dfda95" + integrity sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw== + dependencies: + tslib "^2.5.0" + +"@smithy/util-utf8@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz#b4da87566ea7757435e153799df9da717262ad42" + integrity sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ== + dependencies: + "@smithy/util-buffer-from" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-waiter@^2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.5.tgz#e42161e03c53cf6726dca049ad9a105ea0967435" + integrity sha512-1lkkUmI/bhaDX+LIT3RiUNAn+NzPmsWjE7beMq0oQ3H1/CffaILIN67riDA0aE1YBj6xll7uWMIy4tJqc+peXw== + dependencies: + "@smithy/abort-controller" "^2.0.5" + "@smithy/types" "^2.2.2" + tslib "^2.5.0" + "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -2731,6 +3698,14 @@ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/tar@^6.1.5": + version "6.1.5" + resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.5.tgz#90ccb3b6a35430e7427410d50eed564e85feaaff" + integrity sha512-qm2I/RlZij5RofuY7vohTpYNaYcrSQlN2MyjucQc7ZweDwaEWkdN/EeNh6e9zjK6uEm6PwjdMXkcj05BxZdX1Q== + dependencies: + "@types/node" "*" + minipass "^4.0.0" + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -3281,6 +4256,11 @@ bn.js@^5.2.1: resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -4657,6 +5637,13 @@ fast-safe-stringify@^2.1.1: resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== +fast-xml-parser@4.2.5: + version "4.2.5" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" + integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g== + dependencies: + strnum "^1.0.5" + fast-uri@^2.0.0, fast-uri@^2.1.0: version "2.2.0" resolved "https://registry.npmjs.org/fast-uri/-/fast-uri-2.2.0.tgz#519a0f849bef714aad10e9753d69d8f758f7445a" @@ -6850,6 +7837,11 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +minipass@^4.0.0: + version "4.2.8" + resolved "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + minipass@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" @@ -8418,6 +9410,11 @@ strip-outer@^2.0.0: resolved "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz#c45c724ed9b1ff6be5f660503791404f4714084b" integrity sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg== +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + strtok3@^7.0.0-alpha.9: version "7.0.0" resolved "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5" @@ -8464,7 +9461,7 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -tar@^6.1.11, tar@^6.1.2: +tar@^6.1.11, tar@^6.1.15, tar@^6.1.2: version "6.1.15" resolved "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== @@ -8665,7 +9662,7 @@ tslib@2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.8.1: +tslib@^1.11.1, tslib@^1.8.1: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -8675,6 +9672,11 @@ tslib@^2.1.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tslib@^2.3.1, tslib@^2.5.0: + version "2.6.2" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsup@^6.5.0: version "6.6.3" resolved "https://registry.npmjs.org/tsup/-/tsup-6.6.3.tgz#f6f975a8656cfd9b8e115f33b1aa0f0fd4df78e2"