From 1e5286d99d227aa61a51b65c85bf3fcd6ea20332 Mon Sep 17 00:00:00 2001 From: Markus Tacker Date: Wed, 16 Jun 2021 16:14:24 +0200 Subject: [PATCH] Simplify runner (#115) This removes the usage of AWS IoT jobs to orchestrate the runs of firmware CI jobs. Instead, [GitHub Actions are used](https://github.com/NordicSemiconductor/asset-tracker-cloud-docs/issues/194). BREAKING CHANGE: this removes the CLI See https://github.com/NordicSemiconductor/cloud-aws-firmware-ci-schedule-action/issues/282 --- cli/cli.ts | 94 --- cli/commands/CommandDefinition.ts | 6 - cli/commands/cancelJob.ts | 21 - cli/commands/run.ts | 80 -- cli/commands/runFromFile.ts | 33 - cli/commands/scheduleJob.ts | 53 -- cli/commands/waitForJob.ts | 37 - cli/index.js | 27 +- deviceHasConnected.ts | 40 + export.ts | 1 - job/cancel.ts | 18 - job/index.ts | 4 - job/job.ts | 23 - job/schedule.ts | 95 --- job/wait.ts | 95 --- package-lock.json | 1124 +++++++++++++++++------------ package.json | 7 +- run.ts | 345 +++++++++ runner/publishReport.ts | 27 - runner/runJob.ts | 184 ----- runner/runner.ts | 144 ---- scheduleFOTA.ts | 66 ++ 22 files changed, 1134 insertions(+), 1390 deletions(-) delete mode 100644 cli/cli.ts delete mode 100644 cli/commands/CommandDefinition.ts delete mode 100644 cli/commands/cancelJob.ts delete mode 100644 cli/commands/run.ts delete mode 100644 cli/commands/runFromFile.ts delete mode 100644 cli/commands/scheduleJob.ts delete mode 100644 cli/commands/waitForJob.ts create mode 100644 deviceHasConnected.ts delete mode 100644 export.ts delete mode 100644 job/cancel.ts delete mode 100644 job/index.ts delete mode 100644 job/job.ts delete mode 100644 job/schedule.ts delete mode 100644 job/wait.ts create mode 100644 run.ts delete mode 100644 runner/publishReport.ts delete mode 100644 runner/runJob.ts delete mode 100644 runner/runner.ts create mode 100644 scheduleFOTA.ts diff --git a/cli/cli.ts b/cli/cli.ts deleted file mode 100644 index 5468a2c3..00000000 --- a/cli/cli.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as program from 'commander' -import * as chalk from 'chalk' -import { scheduleJobCommand } from './commands/scheduleJob' -import { waitForJobCommand } from './commands/waitForJob' -import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts' -import { promises as fs } from 'fs' -import { runCommand } from './commands/run' -import * as path from 'path' -import { runFromFileCommand } from './commands/runFromFile' -import { cancelJobCommand } from './commands/cancelJob' - -const bucketName = process.env.BUCKET_NAME ?? '' -const region = process.env.AWS_REGION ?? 'us-east-1' -const ciDeviceName = process.env.CI_DEVICE ?? '' - -const CLI = async ({ isCI }: { isCI: boolean }) => { - const { version } = JSON.parse( - await fs.readFile( - path.normalize(path.join(__dirname, '..', '..', 'package.json')), - 'utf-8', - ), - ) - - program.description( - `Bifravst Firmware CI Command Line Interface (${version})`, - ) - program.version(version) - - const { Account: accountId } = await new STSClient({ - region, - }).send(new GetCallerIdentityCommand({})) - - const commands = [ - scheduleJobCommand({ - bucketName, - region, - ciDeviceArn: `arn:aws:iot:${region}:${accountId}:thing/${ciDeviceName}`, - }), - waitForJobCommand({ - region, - }), - cancelJobCommand({ region }), - ] - - if (isCI) { - console.error('Running on CI...') - } else { - commands.push(runCommand()) - commands.push(runFromFileCommand()) - } - - let ran = false - commands.forEach(({ command, action, help, options }) => { - const cmd = program.command(command) - cmd - .action(async (...args) => { - try { - ran = true - await action(...args) - } catch (error) { - console.error( - chalk.red.inverse(' ERROR '), - chalk.red(`${command} failed!`), - ) - console.error(chalk.red.inverse(' ERROR '), chalk.red(error)) - process.exit(1) - } - }) - .on('--help', () => { - console.log('') - console.log(chalk.yellow(help)) - console.log('') - }) - if (options) { - options.forEach(({ flags, description, defaultValue }) => - cmd.option(flags, description, defaultValue), - ) - } - }) - - program.parse(process.argv) - - if (!ran) { - program.outputHelp(chalk.yellow) - throw new Error('No command selected!') - } -} - -CLI({ - isCI: process.env.CI === '1', -}).catch((err) => { - console.error(chalk.red(err)) - process.exit(1) -}) diff --git a/cli/commands/CommandDefinition.ts b/cli/commands/CommandDefinition.ts deleted file mode 100644 index 1fc54d54..00000000 --- a/cli/commands/CommandDefinition.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type CommandDefinition = { - command: string - action: (...args: any) => Promise - options?: { flags: string; description?: string; defaultValue?: any }[] - help: string -} diff --git a/cli/commands/cancelJob.ts b/cli/commands/cancelJob.ts deleted file mode 100644 index 18c551e3..00000000 --- a/cli/commands/cancelJob.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CommandDefinition } from './CommandDefinition' -import { IoTClient } from '@aws-sdk/client-iot' -import { cancel } from '../../job/cancel' - -export const cancelJobCommand = ({ - region, -}: { - region: string -}): CommandDefinition => ({ - command: 'cancel ', - action: async (jobId) => { - console.log('') - await cancel({ - iot: new IoTClient({ - region, - }), - jobId, - }) - }, - help: 'Cancel the job', -}) diff --git a/cli/commands/run.ts b/cli/commands/run.ts deleted file mode 100644 index 1e97cabd..00000000 --- a/cli/commands/run.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { CommandDefinition } from './CommandDefinition' -import { runner } from '../../runner/runner' -import { atHostHexfile } from '@nordicsemiconductor/firmware-ci-device-helpers' -import * as chalk from 'chalk' - -const defaultPowerCycleWaitSeconds = 10 -const defaultPowerCycleWaitAfterOnSeconds = 5 - -export const runCommand = (): CommandDefinition => ({ - command: 'run ', - options: [ - { - flags: '-t, --thingy', - description: `Connected DK is a thingy`, - }, - { - flags: '-poff, --power-cycle-off ', - description: 'Turn off device before running the job using .', - }, - { - flags: '-pon, --power-cycle-on ', - description: 'Turn on device before running the job using .', - }, - { - flags: '-w, --power-cycle-wait ', - description: `Turn off device for this amount of seconds during power cycle. Defaults to ${defaultPowerCycleWaitSeconds} seconds.`, - }, - { - flags: '-wafter, --power-cycle-wait-after-on ', - description: `Wait for this amount of seconds after turning on the device. Defaults to ${defaultPowerCycleWaitAfterOnSeconds} seconds.`, - }, - ], - action: async ( - device, - certificateJSON, - { - thingy, - powerCycleOff, - powerCycleOn, - powerCycleWait, - powerCycleWaitAfterOn, - }, - ) => { - const waitSeconds = parseInt( - powerCycleWait ?? `${defaultPowerCycleWaitSeconds}`, - 10, - ) - const waitSecondsAfterOn = parseInt( - powerCycleWaitAfterOn ?? `${defaultPowerCycleWaitAfterOnSeconds}`, - 10, - ) - if (powerCycleOff !== undefined && powerCycleOn !== undefined) { - console.debug('') - console.debug(chalk.gray(`Will power cycle device before each run:`)) - console.debug(chalk.red(' Off ', chalk.blue(powerCycleOff))) - console.debug(chalk.yellow(' Wait', chalk.blue(`${waitSeconds} seconds`))) - console.debug(chalk.green(' On ', chalk.blue(powerCycleOn))) - console.debug( - chalk.yellow(' Wait', chalk.blue(`${waitSecondsAfterOn} seconds`)), - ) - console.debug('') - } - await runner({ - certificateJSON, - atHostHexfile: - thingy === true ? atHostHexfile.thingy91 : atHostHexfile['9160dk'], - device, - powerCycle: - powerCycleOff !== undefined && powerCycleOn !== undefined - ? { - offCmd: powerCycleOff, - onCmd: powerCycleOn, - waitSeconds, - waitSecondsAfterOn, - } - : undefined, - }) - }, - help: 'Execute firmware CI jobs', -}) diff --git a/cli/commands/runFromFile.ts b/cli/commands/runFromFile.ts deleted file mode 100644 index 8a461340..00000000 --- a/cli/commands/runFromFile.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CommandDefinition } from './CommandDefinition' -import { - atHostHexfile, - download, -} from '@nordicsemiconductor/firmware-ci-device-helpers' -import { runJob } from '../../runner/runJob' -import { promises as fs } from 'fs' - -export const runFromFileCommand = (): CommandDefinition => ({ - command: 'run-once ', - options: [ - { - flags: '-t, --thingy', - description: `Connected DK is a thingy`, - }, - ], - action: async (device, jobFile, { thingy }) => { - const doc = JSON.parse(await fs.readFile(jobFile, 'utf-8')) - const hexfile = await download({ - fw: doc.fw, - target: `${doc.id}.hex`, - }) - await runJob({ - doc, - hexfile, - device, - atHostHexfile: - thingy === true ? atHostHexfile.thingy91 : atHostHexfile['9160dk'], - }) - await fs.unlink(hexfile) - }, - help: 'Execute one firmware CI job from a file', -}) diff --git a/cli/commands/scheduleJob.ts b/cli/commands/scheduleJob.ts deleted file mode 100644 index 3d485612..00000000 --- a/cli/commands/scheduleJob.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { CommandDefinition } from './CommandDefinition' -import { IoTClient } from '@aws-sdk/client-iot' -import { S3Client } from '@aws-sdk/client-s3' -import { schedule } from '../../job/schedule' - -const defaultTarget = 'thingy91_nrf9160ns' -const defaultNetwork = 'ltem' -const defaultSecTag = 42 - -export const scheduleJobCommand = ({ - bucketName, - region, - ciDeviceArn, -}: { - bucketName: string - region: string - ciDeviceArn: string -}): CommandDefinition => ({ - command: 'schedule ', - options: [ - { - flags: '-t, --target ', - description: `Target board, default: ${defaultTarget}`, - }, - { - flags: '-n, --network ', - description: `Target network, default: ${defaultNetwork}`, - }, - { - flags: '-s, --sec-tag ', - description: `Credentials secTag, default: ${defaultSecTag}`, - }, - ], - action: async (firmwareUrl, certificateJSON, { target, network, secTag }) => { - await schedule({ - bucketName, - region, - ciDeviceArn, - iot: new IoTClient({ - region, - }), - s3: new S3Client({ - region, - }), - certificateJSON, - firmwareUrl, - network: network ?? defaultNetwork, - secTag: secTag === undefined ? defaultSecTag : parseInt(secTag, 10), - target: target ?? defaultTarget, - }) - }, - help: 'Schedules a new Firmware CI job.', -}) diff --git a/cli/commands/waitForJob.ts b/cli/commands/waitForJob.ts deleted file mode 100644 index c26714c9..00000000 --- a/cli/commands/waitForJob.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { CommandDefinition } from './CommandDefinition' -import { IoTClient } from '@aws-sdk/client-iot' -import { - waitDefaultIntervalInSeconds, - waitDefaultTimeoutInMinutes, - wait, -} from '../../job/wait' - -export const waitForJobCommand = ({ - region, -}: { - region: string -}): CommandDefinition => ({ - command: 'wait ', - options: [ - { - flags: '-t, --timout ', - description: `Timeout in minutes, default: ${waitDefaultTimeoutInMinutes}`, - }, - { - flags: '-i, --interval ', - description: `Interval in seconds, default: ${waitDefaultIntervalInSeconds}`, - }, - ], - action: async (jobId, { timeout, interval }) => { - console.log('') - await wait({ - iot: new IoTClient({ - region, - }), - interval, - timeoutInMinutes: timeout, - jobId, - }) - }, - help: 'Wait for a job to complete', -}) diff --git a/cli/index.js b/cli/index.js index 686f5b36..9c6233e1 100755 --- a/cli/index.js +++ b/cli/index.js @@ -1,5 +1,7 @@ #!/usr/bin/env node +const fs = require('fs') + const die = (err, origin) => { console.error(`An unhandled exception occured!`) console.error(`Exception origin: ${JSON.stringify(origin)}`) @@ -10,5 +12,26 @@ const die = (err, origin) => { process.on('uncaughtException', die) process.on('unhandledRejection', die) -// eslint-disable-next-line -require('../dist/cli/cli') +const { run } = require('../dist/run') +run({ + target: process.env.RUN_TARGET ?? 'nrf9160dk_nrf9160ns', + device: process.env.RUN_DEVICE ?? '/dev/ttyACM0', +})(JSON.parse(fs.readFileSync(0, 'utf-8'))) + .then((res) => { + if (res.timeout) { + console.error(`Timed out.`) + process.exit(-1) + } + if (res.abort) { + console.error('Aborted.') + process.exit(-2) + } + if (!res.connected) { + console.error('Did not connect.') + process.exit(-3) + } + }) + .catch((err) => { + console.error(err.message) + process.exit(-99) + }) diff --git a/deviceHasConnected.ts b/deviceHasConnected.ts new file mode 100644 index 00000000..bdc30ac1 --- /dev/null +++ b/deviceHasConnected.ts @@ -0,0 +1,40 @@ +import { log } from '@nordicsemiconductor/firmware-ci-device-helpers' +import { + IoTDataPlaneClient, + GetThingShadowCommand, +} from '@aws-sdk/client-iot-data-plane' +import { TextDecoder } from 'util' + +export const deviceHasConnected = async ({ + deviceId, + iotData, +}: { + deviceId: string + iotData: IoTDataPlaneClient +}): Promise => { + const { progress, success, error } = log({ + prefixes: ['connection', deviceId], + }) + + progress(`Checking if device has connected ...`) + try { + const shadow = await iotData.send( + new GetThingShadowCommand({ + thingName: deviceId, + }), + ) + const { state } = JSON.parse( + new TextDecoder('utf-8').decode(shadow.payload), + ) + progress('Device has connected.') + if (state?.reported?.dev === undefined) { + error('Device has not reported device information, yet.') + return false + } + success('Device has connected and reported device information.') + return true + } catch { + error('Device has not connected.', error) + return false + } +} diff --git a/export.ts b/export.ts deleted file mode 100644 index d53291f0..00000000 --- a/export.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './job' diff --git a/job/cancel.ts b/job/cancel.ts deleted file mode 100644 index ae54e5ea..00000000 --- a/job/cancel.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as chalk from 'chalk' -import { DeleteJobCommand, IoTClient } from '@aws-sdk/client-iot' - -export const cancel = async ({ - iot, - jobId, -}: { - iot: IoTClient - jobId: string -}): Promise => { - await iot.send(new DeleteJobCommand({ jobId, force: true })) - console.log( - chalk.green('Job'), - chalk.blueBright(jobId), - chalk.green('cancelled.'), - ) - console.log() -} diff --git a/job/index.ts b/job/index.ts deleted file mode 100644 index 41330396..00000000 --- a/job/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './job' -export * from './schedule' -export * from './wait' -export * from './cancel' diff --git a/job/job.ts b/job/job.ts deleted file mode 100644 index d5cf48d2..00000000 --- a/job/job.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const defaultTimeoutInMinutes = 2 - -export type FirmwareCIJobDocument = { - timeoutInMinutes?: number - reportPublishUrl: string - reportUrl: string - fw: string - target: string - expires: string - credentials?: { - secTag: number - privateKey: string - clientCert: string - caCert: string - } - abortOn?: string[] - endOn?: string[] -} - -export type RunningFirmwareCIJobDocument = { - id: string - timeoutInMinutes: number -} & FirmwareCIJobDocument diff --git a/job/schedule.ts b/job/schedule.ts deleted file mode 100644 index fd7587d4..00000000 --- a/job/schedule.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { v4 } from 'uuid' -import * as chalk from 'chalk' -import { createPresignedPost } from '@aws-sdk/s3-presigned-post' -import { CreateJobCommand, IoTClient } from '@aws-sdk/client-iot' -import { promises as fs } from 'fs' -import { FirmwareCIJobDocument } from './job' -import { S3Client } from '@aws-sdk/client-s3' - -const queryString = (s: Record): string => - Object.entries(s) - .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) - .join('&') - -export const schedule = async ({ - firmwareUrl, - certificateJSON, - target, - network, - secTag, - bucketName, - region, - s3, - ciDeviceArn, - jobId, - iot, - timeoutInMinutes, - abortOn, - endOn, -}: { - iot: IoTClient - firmwareUrl: string - certificateJSON: string - target: string - network: string - secTag: number - bucketName: string - region: string - s3: S3Client - ciDeviceArn: string - jobId?: string - timeoutInMinutes?: number - abortOn?: string[] - endOn?: string[] -}): Promise => { - jobId = jobId ?? v4() - console.log('') - const { url, fields } = await createPresignedPost(s3, { - Bucket: bucketName, - Key: `${jobId}.json`, - }) - - const { caCert, clientCert, privateKey } = JSON.parse( - await fs.readFile(certificateJSON, 'utf-8'), - ) - - const jobDocument: FirmwareCIJobDocument = { - reportPublishUrl: `${url}?${queryString(fields)}`, - reportUrl: `https://${bucketName}.s3.${region}.amazonaws.com/${jobId}.json`, - fw: firmwareUrl, - target: `${target}:${network}`, - expires: new Date(Date.now() + 60 * 60 * 1000).toISOString(), - credentials: { - secTag, - privateKey, - clientCert, - caCert, - }, - timeoutInMinutes, - abortOn, - endOn, - } - - await iot.send( - new CreateJobCommand({ - jobId, - targets: [ciDeviceArn], - document: JSON.stringify(jobDocument), - description: `Firmware CI job for a ${target} with ${network}`, - targetSelection: 'SNAPSHOT', - timeoutConfig: { - inProgressTimeoutInMinutes: 60, - }, - }), - ) - - console.log( - chalk.green('Job'), - chalk.blueBright(jobId), - chalk.green('created.'), - ) - console.log() - console.log(chalk.green('You can observe the job execution using:')) - console.log(chalk.greenBright('node cli wait'), chalk.blueBright(jobId)) - return jobDocument -} diff --git a/job/wait.ts b/job/wait.ts deleted file mode 100644 index b94a7d3a..00000000 --- a/job/wait.ts +++ /dev/null @@ -1,95 +0,0 @@ -import * as chalk from 'chalk' -import { - DescribeJobCommand, - GetJobDocumentCommand, - IoTClient, - Job, -} from '@aws-sdk/client-iot' -import { log } from '@nordicsemiconductor/firmware-ci-device-helpers' -import { FirmwareCIJobDocument } from './job' - -export const waitDefaultTimeoutInMinutes = 5 -export const waitDefaultIntervalInSeconds = 30 - -export const wait = async ({ - iot, - timeoutInMinutes, - interval, - jobId, -}: { - iot: IoTClient - timeoutInMinutes?: number - interval?: number - jobId: string -}): Promise<{ - job: Job - jobDocument: FirmwareCIJobDocument -}> => - new Promise((resolve, reject) => { - const { progress, success, warn } = log({ withTimestamp: true }) - const t = setTimeout( - () => - reject(new Error(`Timed out waiting for job ${jobId} to complete.`)), - (timeoutInMinutes ?? waitDefaultTimeoutInMinutes) * 60 * 1000, - ) - let i: NodeJS.Timeout | undefined = undefined - const cleanUp = () => { - if (i !== undefined) clearInterval(i) - clearTimeout(t) - } - const checkJob = async () => { - try { - const { job } = await iot.send( - new DescribeJobCommand({ - jobId, - }), - ) - if (job === undefined) { - cleanUp() - throw new Error(`Job ${jobId} not found.`) - } - if (job.status === 'COMPLETED') { - cleanUp() - progress(job.status) - if ((job.jobProcessDetails?.numberOfFailedThings ?? 0) > 0) { - warn( - `${job.jobProcessDetails?.numberOfFailedThings} failed executions.`, - ) - return reject(new Error(`Job ${jobId} failed!`)) - } - success( - `${job.jobProcessDetails?.numberOfFailedThings} failed executions.`, - ) - return resolve({ - job, - jobDocument: JSON.parse( - ( - await iot.send( - new GetJobDocumentCommand({ - jobId: job.jobId as string, - }), - ) - ).document as string, - ) as FirmwareCIJobDocument, - }) - } else if (job.status === 'DELETION_IN_PROGRESS') { - cleanUp() - return reject(new Error(`Job ${jobId} is being deleted.`)) - } else { - progress( - chalk.yellow(job.status), - chalk.blueBright( - job.jobProcessDetails?.numberOfInProgressThings ?? 0, - ), - chalk.yellow('things have started the job'), - ) - } - } catch (err) { - warn(chalk.red(err.message)) - cleanUp() - return reject(new Error(`Job ${jobId} not found.`)) - } - } - void checkJob() - i = setInterval(checkJob, (interval ?? waitDefaultIntervalInSeconds) * 1000) - }) diff --git a/package-lock.json b/package-lock.json index 197fd6b2..5b7ce0fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { + "@aws-sdk/client-cloudformation": "3.18.0", "@aws-sdk/client-iot": "3.18.0", + "@aws-sdk/client-iot-data-plane": "3.18.0", "@aws-sdk/client-s3": "3.18.0", "@aws-sdk/client-sts": "3.18.0", "@aws-sdk/s3-presigned-post": "3.18.0", @@ -20,6 +22,7 @@ "commander": "7.2.0", "form-data": "4.0.0", "node-fetch": "2.6.1", + "semver": "7.3.5", "serialport": "9.1.0", "shell-quote": "*", "uuid": "8.3.2" @@ -33,8 +36,9 @@ "@nordicsemiconductor/asset-tracker-cloud-code-style": "9.0.4", "@nordicsemiconductor/eslint-config-asset-tracker-cloud-typescript": "7.0.25", "@types/aws-iot-device-sdk": "2.2.2", - "@types/node": "15.3.1", + "@types/node": "15.12.2", "@types/node-fetch": "2.5.10", + "@types/semver": "7.3.6", "@types/serialport": "8.0.1", "@types/shell-quote": "*", "@types/uuid": "8.3.0", @@ -153,6 +157,51 @@ "tslib": "^2.0.0" } }, + "node_modules/@aws-sdk/client-cloudformation": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.18.0.tgz", + "integrity": "sha512-8l2YPwER/Fqsl/OVMWkzFtw4R5Spsz/H/E0YB0b/Al2INiY0EYcMrL6uH1DkR1J4O/h8ZZ55ccD/WFvaTZEmCA==", + "dependencies": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/client-sts": "3.18.0", + "@aws-sdk/config-resolver": "3.18.0", + "@aws-sdk/credential-provider-node": "3.18.0", + "@aws-sdk/fetch-http-handler": "3.18.0", + "@aws-sdk/hash-node": "3.18.0", + "@aws-sdk/invalid-dependency": "3.18.0", + "@aws-sdk/middleware-content-length": "3.18.0", + "@aws-sdk/middleware-host-header": "3.18.0", + "@aws-sdk/middleware-logger": "3.18.0", + "@aws-sdk/middleware-retry": "3.18.0", + "@aws-sdk/middleware-serde": "3.18.0", + "@aws-sdk/middleware-signing": "3.18.0", + "@aws-sdk/middleware-stack": "3.18.0", + "@aws-sdk/middleware-user-agent": "3.18.0", + "@aws-sdk/node-config-provider": "3.18.0", + "@aws-sdk/node-http-handler": "3.18.0", + "@aws-sdk/protocol-http": "3.18.0", + "@aws-sdk/smithy-client": "3.18.0", + "@aws-sdk/types": "3.18.0", + "@aws-sdk/url-parser": "3.18.0", + "@aws-sdk/util-base64-browser": "3.18.0", + "@aws-sdk/util-base64-node": "3.18.0", + "@aws-sdk/util-body-length-browser": "3.18.0", + "@aws-sdk/util-body-length-node": "3.18.0", + "@aws-sdk/util-user-agent-browser": "3.18.0", + "@aws-sdk/util-user-agent-node": "3.18.0", + "@aws-sdk/util-utf8-browser": "3.18.0", + "@aws-sdk/util-utf8-node": "3.18.0", + "@aws-sdk/util-waiter": "3.18.0", + "entities": "2.2.0", + "fast-xml-parser": "3.19.0", + "tslib": "^2.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@aws-sdk/client-iot": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-iot/-/client-iot-3.18.0.tgz", @@ -195,6 +244,47 @@ "node": ">=10.0.0" } }, + "node_modules/@aws-sdk/client-iot-data-plane": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-iot-data-plane/-/client-iot-data-plane-3.18.0.tgz", + "integrity": "sha512-wjwGmXNMrMHNIBbii9pzH/c6x4kga8A89Twxr3VsNsWMZnCwLywRzyNfA6hqDyQof1tk3/OdZWLFQyq4LSxeSA==", + "dependencies": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/client-sts": "3.18.0", + "@aws-sdk/config-resolver": "3.18.0", + "@aws-sdk/credential-provider-node": "3.18.0", + "@aws-sdk/fetch-http-handler": "3.18.0", + "@aws-sdk/hash-node": "3.18.0", + "@aws-sdk/invalid-dependency": "3.18.0", + "@aws-sdk/middleware-content-length": "3.18.0", + "@aws-sdk/middleware-host-header": "3.18.0", + "@aws-sdk/middleware-logger": "3.18.0", + "@aws-sdk/middleware-retry": "3.18.0", + "@aws-sdk/middleware-serde": "3.18.0", + "@aws-sdk/middleware-signing": "3.18.0", + "@aws-sdk/middleware-stack": "3.18.0", + "@aws-sdk/middleware-user-agent": "3.18.0", + "@aws-sdk/node-config-provider": "3.18.0", + "@aws-sdk/node-http-handler": "3.18.0", + "@aws-sdk/protocol-http": "3.18.0", + "@aws-sdk/smithy-client": "3.18.0", + "@aws-sdk/types": "3.18.0", + "@aws-sdk/url-parser": "3.18.0", + "@aws-sdk/util-base64-browser": "3.18.0", + "@aws-sdk/util-base64-node": "3.18.0", + "@aws-sdk/util-body-length-browser": "3.18.0", + "@aws-sdk/util-body-length-node": "3.18.0", + "@aws-sdk/util-user-agent-browser": "3.18.0", + "@aws-sdk/util-user-agent-node": "3.18.0", + "@aws-sdk/util-utf8-browser": "3.18.0", + "@aws-sdk/util-utf8-node": "3.18.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@aws-sdk/client-s3": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.18.0.tgz", @@ -1053,21 +1143,16 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.6.1.tgz", - "integrity": "sha512-xXJmtCNa1Sku2JkCx0RHRyXmTMBAraup6L14a5vgLrV2TNL89HRy2iybbe/6LqG8hg9QC3HFtr3QsXQXrsBI8Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.18.0.tgz", + "integrity": "sha512-Lj2O9KaXCn+gPW23l3ydcSWe4HK0jH6teeSymbaFTwTjKtr4oLfDDKAOFoG5YyppQstEPqsL/RidVey4kOFfcg==", "dependencies": { - "tslib": "^1.8.0" + "tslib": "^2.0.0" }, "engines": { "node": ">= 10.0.0" } }, - "node_modules/@aws-sdk/util-locate-window/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@aws-sdk/util-uri-escape": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.18.0.tgz", @@ -1156,20 +1241,26 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/highlight/node_modules/ansi-styles": { @@ -1213,6 +1304,15 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/@babel/highlight/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=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1723,9 +1823,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.1.tgz", - "integrity": "sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "node_modules/@types/node-fetch": { @@ -1764,6 +1864,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/@types/semver": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.6.tgz", + "integrity": "sha512-0caWDWmpCp0uifxFh+FaqK3CuZ2SkRR/ZRxAV5+zNdC3QVUi6wyOJnefhPvtNt8NQWXB5OA93BUvZsXpWat2Xw==", + "dev": true + }, "node_modules/@types/serialport": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@types/serialport/-/serialport-8.0.1.tgz", @@ -1786,9 +1892,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-d/7W23JAXPodQNbOZNXvl2K+bqAQrCMwlh/nuQsPSQk6Fq0opHoPrUw43aHsvSbIiQPr8Of2hkFbnz1XBFVyZQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -1850,24 +1956,6 @@ "eslint": "*" } }, - "node_modules/@typescript-eslint/experimental-utils/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": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, "node_modules/@typescript-eslint/parser": { "version": "4.27.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.27.0.tgz", @@ -2029,12 +2117,12 @@ } }, "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "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.11.0" + "type-fest": "^0.21.3" }, "engines": { "node": ">=8" @@ -2044,12 +2132,12 @@ } }, "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "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": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2242,10 +2330,30 @@ "node": ">= 6" } }, + "node_modules/aws-iot-device-sdk/node_modules/ws": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", + "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2474,6 +2582,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2502,14 +2616,6 @@ "minimist": "^1.1.0" } }, - "node_modules/commist/node_modules/leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -2909,12 +3015,15 @@ } }, "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { @@ -2999,6 +3108,33 @@ } }, "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": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "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, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/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==", @@ -3013,7 +3149,7 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "node_modules/eslint/node_modules/eslint-utils/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==", @@ -3022,27 +3158,6 @@ "node": ">=4" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -3149,6 +3264,29 @@ "es5-ext": "~0.10.14" } }, + "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": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -3167,9 +3305,9 @@ } }, "node_modules/ext/node_modules/type": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.3.0.tgz", - "integrity": "sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", "dev": true }, "node_modules/extend": { @@ -3233,21 +3371,6 @@ "reusify": "^1.0.4" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3455,6 +3578,18 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/git-raw-commits": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", @@ -3480,9 +3615,9 @@ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3577,22 +3712,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "dependencies": { "array-union": "^2.1.0", @@ -3690,6 +3813,15 @@ "node": ">=10" } }, + "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, + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/husky": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", @@ -4051,6 +4183,14 @@ "node": ">=0.10.0" } }, + "node_modules/leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4099,60 +4239,14 @@ "url": "https://opencollective.com/lint-staged" } }, - "node_modules/lint-staged/node_modules/execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "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": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/lint-staged/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/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, - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/listr2": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.8.2.tgz", - "integrity": "sha512-E28Fw7Zd3HQlCJKzb9a8C8M0HtFWQeucE+S8YrSrqZObuCLPRHMRrR8gNmYt65cU9orXYHwvN5agXC36lYt7VQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.10.0.tgz", + "integrity": "sha512-eP40ZHihu70sSmqFNbNy2NL1YwImmlMmPh9WO5sLmPDleurMHt3n+SwEWNu2kzKScexZnkyFtc1VI0z/TGlmpw==", "dev": true, "dependencies": { - "chalk": "^4.1.1", "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", + "colorette": "^1.2.2", "log-update": "^4.0.0", "p-map": "^4.0.0", "rxjs": "^6.6.7", @@ -4274,7 +4368,6 @@ "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": { "yallist": "^4.0.0" }, @@ -4360,19 +4453,19 @@ } }, "node_modules/mime-db": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", - "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.29", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", - "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "dependencies": { - "mime-db": "1.46.0" + "mime-db": "1.48.0" }, "engines": { "node": ">= 0.6" @@ -4554,11 +4647,6 @@ "node": "4.x || >=6.0.0" } }, - "node_modules/noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" - }, "node_modules/normalize-package-data": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", @@ -4786,9 +4874,9 @@ } }, "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "node_modules/path-type": { @@ -4801,9 +4889,9 @@ } }, "node_modules/picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true, "engines": { "node": ">=8.6" @@ -4837,9 +4925,9 @@ } }, "node_modules/prebuild-install": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.2.tgz", - "integrity": "sha512-PzYWIKZeP+967WuKYXlTOhYBgGOvTRSfaKI89XnfJ0ansRAH7hDU45X+K+FZeI1Wb/7p/NnuctPH3g0IqKUuSQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.3.tgz", + "integrity": "sha512-iqqSR84tNYQUQHRXalSKdIaM8Ov1QxOVuBNWI7+BzZWv6Ih9k75wOnH1rGQ9WWTaaLkTpxWKIciOF0KyfM74+Q==", "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -4848,7 +4936,6 @@ "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", - "noop-logger": "^0.1.1", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", @@ -5080,6 +5167,15 @@ "node": ">=8" } }, + "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", @@ -5130,6 +5226,11 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/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==" + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -5144,9 +5245,9 @@ } }, "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { "node": ">=8" @@ -5297,15 +5398,28 @@ "dev": true }, "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==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -5461,9 +5575,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "node_modules/split2": { @@ -5506,6 +5620,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/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==" + }, "node_modules/string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -5626,9 +5745,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5800,9 +5919,9 @@ } }, "node_modules/trim-newlines": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true, "engines": { "node": ">=8" @@ -5818,9 +5937,9 @@ } }, "node_modules/tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -5873,12 +5992,15 @@ } }, "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==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typedarray": { @@ -5899,6 +6021,11 @@ "node": ">=4.2.0" } }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -5948,9 +6075,9 @@ } }, "node_modules/v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "node_modules/validate-npm-package-license": { @@ -5976,21 +6103,6 @@ "xtend": "^4.0.0" } }, - "node_modules/websocket-stream/node_modules/ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, - "node_modules/websocket-stream/node_modules/ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dependencies": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6085,25 +6197,20 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } }, + "node_modules/ws/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==" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -6124,13 +6231,12 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, "engines": { "node": ">= 6" @@ -6286,6 +6392,48 @@ "tslib": "^2.0.0" } }, + "@aws-sdk/client-cloudformation": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.18.0.tgz", + "integrity": "sha512-8l2YPwER/Fqsl/OVMWkzFtw4R5Spsz/H/E0YB0b/Al2INiY0EYcMrL6uH1DkR1J4O/h8ZZ55ccD/WFvaTZEmCA==", + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/client-sts": "3.18.0", + "@aws-sdk/config-resolver": "3.18.0", + "@aws-sdk/credential-provider-node": "3.18.0", + "@aws-sdk/fetch-http-handler": "3.18.0", + "@aws-sdk/hash-node": "3.18.0", + "@aws-sdk/invalid-dependency": "3.18.0", + "@aws-sdk/middleware-content-length": "3.18.0", + "@aws-sdk/middleware-host-header": "3.18.0", + "@aws-sdk/middleware-logger": "3.18.0", + "@aws-sdk/middleware-retry": "3.18.0", + "@aws-sdk/middleware-serde": "3.18.0", + "@aws-sdk/middleware-signing": "3.18.0", + "@aws-sdk/middleware-stack": "3.18.0", + "@aws-sdk/middleware-user-agent": "3.18.0", + "@aws-sdk/node-config-provider": "3.18.0", + "@aws-sdk/node-http-handler": "3.18.0", + "@aws-sdk/protocol-http": "3.18.0", + "@aws-sdk/smithy-client": "3.18.0", + "@aws-sdk/types": "3.18.0", + "@aws-sdk/url-parser": "3.18.0", + "@aws-sdk/util-base64-browser": "3.18.0", + "@aws-sdk/util-base64-node": "3.18.0", + "@aws-sdk/util-body-length-browser": "3.18.0", + "@aws-sdk/util-body-length-node": "3.18.0", + "@aws-sdk/util-user-agent-browser": "3.18.0", + "@aws-sdk/util-user-agent-node": "3.18.0", + "@aws-sdk/util-utf8-browser": "3.18.0", + "@aws-sdk/util-utf8-node": "3.18.0", + "@aws-sdk/util-waiter": "3.18.0", + "entities": "2.2.0", + "fast-xml-parser": "3.19.0", + "tslib": "^2.0.0", + "uuid": "^8.3.2" + } + }, "@aws-sdk/client-iot": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-iot/-/client-iot-3.18.0.tgz", @@ -6325,6 +6473,44 @@ "uuid": "^8.3.2" } }, + "@aws-sdk/client-iot-data-plane": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-iot-data-plane/-/client-iot-data-plane-3.18.0.tgz", + "integrity": "sha512-wjwGmXNMrMHNIBbii9pzH/c6x4kga8A89Twxr3VsNsWMZnCwLywRzyNfA6hqDyQof1tk3/OdZWLFQyq4LSxeSA==", + "requires": { + "@aws-crypto/sha256-browser": "^1.0.0", + "@aws-crypto/sha256-js": "^1.0.0", + "@aws-sdk/client-sts": "3.18.0", + "@aws-sdk/config-resolver": "3.18.0", + "@aws-sdk/credential-provider-node": "3.18.0", + "@aws-sdk/fetch-http-handler": "3.18.0", + "@aws-sdk/hash-node": "3.18.0", + "@aws-sdk/invalid-dependency": "3.18.0", + "@aws-sdk/middleware-content-length": "3.18.0", + "@aws-sdk/middleware-host-header": "3.18.0", + "@aws-sdk/middleware-logger": "3.18.0", + "@aws-sdk/middleware-retry": "3.18.0", + "@aws-sdk/middleware-serde": "3.18.0", + "@aws-sdk/middleware-signing": "3.18.0", + "@aws-sdk/middleware-stack": "3.18.0", + "@aws-sdk/middleware-user-agent": "3.18.0", + "@aws-sdk/node-config-provider": "3.18.0", + "@aws-sdk/node-http-handler": "3.18.0", + "@aws-sdk/protocol-http": "3.18.0", + "@aws-sdk/smithy-client": "3.18.0", + "@aws-sdk/types": "3.18.0", + "@aws-sdk/url-parser": "3.18.0", + "@aws-sdk/util-base64-browser": "3.18.0", + "@aws-sdk/util-base64-node": "3.18.0", + "@aws-sdk/util-body-length-browser": "3.18.0", + "@aws-sdk/util-body-length-node": "3.18.0", + "@aws-sdk/util-user-agent-browser": "3.18.0", + "@aws-sdk/util-user-agent-node": "3.18.0", + "@aws-sdk/util-utf8-browser": "3.18.0", + "@aws-sdk/util-utf8-node": "3.18.0", + "tslib": "^2.0.0" + } + }, "@aws-sdk/client-s3": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.18.0.tgz", @@ -7027,18 +7213,11 @@ } }, "@aws-sdk/util-locate-window": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.6.1.tgz", - "integrity": "sha512-xXJmtCNa1Sku2JkCx0RHRyXmTMBAraup6L14a5vgLrV2TNL89HRy2iybbe/6LqG8hg9QC3HFtr3QsXQXrsBI8Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.18.0.tgz", + "integrity": "sha512-Lj2O9KaXCn+gPW23l3ydcSWe4HK0jH6teeSymbaFTwTjKtr4oLfDDKAOFoG5YyppQstEPqsL/RidVey4kOFfcg==", "requires": { - "tslib": "^1.8.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.0.0" } }, "@aws-sdk/util-uri-escape": { @@ -7114,18 +7293,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, "@babel/highlight": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", - "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -7165,6 +7344,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "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=", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -7526,9 +7711,9 @@ "dev": true }, "@types/node": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.1.tgz", - "integrity": "sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "@types/node-fetch": { @@ -7566,6 +7751,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/semver": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.6.tgz", + "integrity": "sha512-0caWDWmpCp0uifxFh+FaqK3CuZ2SkRR/ZRxAV5+zNdC3QVUi6wyOJnefhPvtNt8NQWXB5OA93BUvZsXpWat2Xw==", + "dev": true + }, "@types/serialport": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@types/serialport/-/serialport-8.0.1.tgz", @@ -7588,9 +7779,9 @@ "dev": true }, "@types/ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-d/7W23JAXPodQNbOZNXvl2K+bqAQrCMwlh/nuQsPSQk6Fq0opHoPrUw43aHsvSbIiQPr8Of2hkFbnz1XBFVyZQ==", "dev": true, "requires": { "@types/node": "*" @@ -7624,17 +7815,6 @@ "@typescript-eslint/typescript-estree": "4.27.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" - }, - "dependencies": { - "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, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - } } }, "@typescript-eslint/parser": { @@ -7732,18 +7912,18 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "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, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" }, "dependencies": { "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "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 } } @@ -7896,13 +8076,19 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "ws": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz", + "integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw==", + "requires": {} } } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -8064,6 +8250,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -8084,13 +8276,6 @@ "requires": { "leven": "^2.1.0", "minimist": "^1.1.0" - }, - "dependencies": { - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" - } } }, "compare-func": { @@ -8425,9 +8610,9 @@ "dev": true }, "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": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint": { @@ -8477,11 +8662,22 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "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 + "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, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "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 + } + } } } }, @@ -8503,26 +8699,18 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "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 - } + "eslint-visitor-keys": "^2.0.0" } }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "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 }, "espree": { @@ -8606,6 +8794,23 @@ "es5-ext": "~0.10.14" } }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, "expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -8621,9 +8826,9 @@ }, "dependencies": { "type": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.3.0.tgz", - "integrity": "sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", "dev": true } } @@ -8679,15 +8884,6 @@ "reusify": "^1.0.4" } }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -8847,6 +9043,12 @@ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", "dev": true }, + "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 + }, "git-raw-commits": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz", @@ -8866,9 +9068,9 @@ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -8939,20 +9141,12 @@ "dev": true, "requires": { "type-fest": "^0.20.2" - }, - "dependencies": { - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } } }, "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -9033,6 +9227,12 @@ "lru-cache": "^6.0.0" } }, + "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 + }, "husky": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", @@ -9290,6 +9490,11 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9327,49 +9532,16 @@ "please-upgrade-node": "^3.2.0", "string-argv": "0.3.1", "stringify-object": "^3.3.0" - }, - "dependencies": { - "execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "dev": true, - "requires": { - "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-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 - }, - "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 - } } }, "listr2": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.8.2.tgz", - "integrity": "sha512-E28Fw7Zd3HQlCJKzb9a8C8M0HtFWQeucE+S8YrSrqZObuCLPRHMRrR8gNmYt65cU9orXYHwvN5agXC36lYt7VQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.10.0.tgz", + "integrity": "sha512-eP40ZHihu70sSmqFNbNy2NL1YwImmlMmPh9WO5sLmPDleurMHt3n+SwEWNu2kzKScexZnkyFtc1VI0z/TGlmpw==", "dev": true, "requires": { - "chalk": "^4.1.1", "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", + "colorette": "^1.2.2", "log-update": "^4.0.0", "p-map": "^4.0.0", "rxjs": "^6.6.7", @@ -9460,7 +9632,6 @@ "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, "requires": { "yallist": "^4.0.0" } @@ -9521,16 +9692,16 @@ } }, "mime-db": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", - "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { - "version": "2.1.29", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", - "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "requires": { - "mime-db": "1.46.0" + "mime-db": "1.48.0" } }, "mimic-fn": { @@ -9681,11 +9852,6 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, - "noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" - }, "normalize-package-data": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", @@ -9850,9 +10016,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { @@ -9862,9 +10028,9 @@ "dev": true }, "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pinst": { @@ -9886,9 +10052,9 @@ } }, "prebuild-install": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.2.tgz", - "integrity": "sha512-PzYWIKZeP+967WuKYXlTOhYBgGOvTRSfaKI89XnfJ0ansRAH7hDU45X+K+FZeI1Wb/7p/NnuctPH3g0IqKUuSQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.3.tgz", + "integrity": "sha512-iqqSR84tNYQUQHRXalSKdIaM8Ov1QxOVuBNWI7+BzZWv6Ih9k75wOnH1rGQ9WWTaaLkTpxWKIciOF0KyfM74+Q==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -9897,7 +10063,6 @@ "mkdirp-classic": "^0.5.3", "napi-build-utils": "^1.0.1", "node-abi": "^2.21.0", - "noop-logger": "^0.1.1", "npmlog": "^4.0.1", "pump": "^3.0.0", "rc": "^1.2.7", @@ -10092,6 +10257,12 @@ "requires": { "p-limit": "^2.2.0" } + }, + "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 } } }, @@ -10107,6 +10278,13 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" + }, + "dependencies": { + "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==" + } } }, "redent": { @@ -10120,9 +10298,9 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "reinterval": { @@ -10224,15 +10402,14 @@ } }, "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==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -10350,9 +10527,9 @@ } }, "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "split2": { @@ -10392,6 +10569,13 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "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==" + } } }, "string-argv": { @@ -10483,9 +10667,9 @@ }, "dependencies": { "ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -10637,9 +10821,9 @@ } }, "trim-newlines": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "trim-off-newlines": { @@ -10649,9 +10833,9 @@ "dev": true }, "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "tsutils": { "version": "3.21.0", @@ -10694,9 +10878,9 @@ } }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "typedarray": { @@ -10710,6 +10894,11 @@ "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -10750,9 +10939,9 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "validate-npm-package-license": { @@ -10776,23 +10965,6 @@ "safe-buffer": "^5.1.2", "ws": "^3.2.0", "xtend": "^4.0.0" - }, - "dependencies": { - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - } } }, "which": { @@ -10864,10 +11036,21 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", - "requires": {} + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + }, + "dependencies": { + "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==" + } + } }, "xtend": { "version": "4.0.2", @@ -10883,13 +11066,12 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index 60faa6d0..268e72df 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "@nordicsemiconductor/firmware-ci-runner-aws", "version": "0.0.0-development", "description": "Exposes real nRF9160 hardware to be used for end-to-end tests. Runs on AWS.", - "main": "./dist/export.js", "bin": "./cli/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", @@ -28,7 +27,9 @@ }, "homepage": "https://github.com/NordicSemiconductor/cloud-aws-firmware-ci-runner-js#readme", "dependencies": { + "@aws-sdk/client-cloudformation": "3.18.0", "@aws-sdk/client-iot": "3.18.0", + "@aws-sdk/client-iot-data-plane": "3.18.0", "@aws-sdk/client-s3": "3.18.0", "@aws-sdk/client-sts": "3.18.0", "@aws-sdk/s3-presigned-post": "3.18.0", @@ -38,6 +39,7 @@ "commander": "7.2.0", "form-data": "4.0.0", "node-fetch": "2.6.1", + "semver": "7.3.5", "serialport": "9.1.0", "shell-quote": "*", "uuid": "8.3.2" @@ -48,8 +50,9 @@ "@nordicsemiconductor/asset-tracker-cloud-code-style": "9.0.4", "@nordicsemiconductor/eslint-config-asset-tracker-cloud-typescript": "7.0.25", "@types/aws-iot-device-sdk": "2.2.2", - "@types/node": "15.3.1", + "@types/node": "15.12.2", "@types/node-fetch": "2.5.10", + "@types/semver": "7.3.6", "@types/serialport": "8.0.1", "@types/shell-quote": "*", "@types/uuid": "8.3.0", diff --git a/run.ts b/run.ts new file mode 100644 index 00000000..e8a7feff --- /dev/null +++ b/run.ts @@ -0,0 +1,345 @@ +import { + flash, + connect, + flashCredentials, + allSeen, + log, + runCmd, + anySeen, + atHostHexfile, +} from '@nordicsemiconductor/firmware-ci-device-helpers' +import { promises as fs } from 'fs' +import * as path from 'path' +import * as semver from 'semver' +import { schedulaFOTA } from './scheduleFOTA' +import { + DeleteObjectCommand, + PutObjectCommand, + S3Client, +} from '@aws-sdk/client-s3' +import { IoTClient } from '@aws-sdk/client-iot' +import { IoTDataPlaneClient } from '@aws-sdk/client-iot-data-plane' +import { CloudFormationClient } from '@aws-sdk/client-cloudformation' +import { stackOutput } from '@nordicsemiconductor/cloudformation-helpers' +import { deviceHasConnected } from './deviceHasConnected' +import { connected } from 'process' + +const defaultPort = '/dev/ttyACM0' +const defaultSecTag = 42 + +type Result = { + connected: boolean + timeout: boolean + abort: boolean + deviceLog: string[] + flashLog: string[] +} + +type Args = { + deviceId: string + appVersion: string + network: 'ltem' | 'nbiot' + secTag?: number + timeoutInMinutes: number + hexFile: string + fotaFile: string + abortOn?: string[] + endOn?: string[] + endOnWaitSeconds?: number + testEnv: { + accessKeyId: string + secretAccessKey: string + region: string + brokerHostname: string + stackName: string + } + certDir: string + powerCycle?: { + offCmd: string + onCmd: string + waitSecondsAfterOff: number + waitSecondsAfterOn: number + } + flashLogLocation: string + deviceLogLocation: string +} + +// FIXME: implement scheduling FOTA +export const run = ({ + port, + target, +}: { + port?: string + target: 'thingy91_nrf9160ns' | 'nrf9160dk_nrf9160ns' +}): ((args: Args) => Promise) => { + const { progress, warn, debug } = log({ withTimestamp: true }) + debug('port', port ?? defaultPort) + debug('target', target) + + return async ({ + deviceId, + appVersion, + network, + secTag, + timeoutInMinutes, + hexFile, + fotaFile, + abortOn, + endOn, + endOnWaitSeconds, + testEnv, + certDir, + powerCycle, + flashLogLocation, + deviceLogLocation, + }: Args): Promise => { + debug('appVersion', appVersion) + debug('network', network) + debug('secTag', secTag ?? defaultSecTag) + debug('timeoutInMinutes', timeoutInMinutes) + debug('hexFile', hexFile) + debug('fotaFile', fotaFile) + debug('abortOn', abortOn) + debug('endOn', endOn) + debug('endOn wait seconds', endOnWaitSeconds) + debug('testEnv', testEnv) + debug('certDir', certDir) + debug('powerCycle', powerCycle) + debug('flashLogLocation', flashLogLocation) + debug('deviceLogLocation', deviceLogLocation) + const atHost = + target === 'thingy91_nrf9160ns' + ? atHostHexfile.thingy91 + : atHostHexfile['9160dk'] + + const awsConfig = { + region: testEnv.region, + credentials: { + accessKeyId: testEnv.accessKeyId, + secretAccessKey: testEnv.secretAccessKey, + }, + } + const s3 = new S3Client(awsConfig) + const iot = new IoTClient(awsConfig) + const iotData = new IoTDataPlaneClient(awsConfig) + const { bucketName } = await stackOutput( + new CloudFormationClient(awsConfig), + )<{ bucketName: string }>(`${testEnv.stackName}-firmware-ci`) + const fotaFileName = `${deviceId.substr(0, 8)}.bin` + + if (powerCycle !== undefined) { + progress(`Power cycling device`) + progress(`Turning off ...`) + progress(powerCycle.offCmd) + await runCmd({ cmd: powerCycle.offCmd }) + progress(`Waiting ${powerCycle.waitSecondsAfterOff} seconds ...`) + await new Promise((resolve) => + setTimeout(resolve, powerCycle.waitSecondsAfterOff * 1000), + ) + progress(`Turning on ...`) + progress(powerCycle.onCmd) + await runCmd({ cmd: powerCycle.onCmd }) + + progress(`Waiting ${powerCycle.waitSecondsAfterOn} seconds ...`) + await new Promise((resolve) => + setTimeout(resolve, powerCycle.waitSecondsAfterOn * 1000), + ) + } + + let flashLog: string[] = [] + + try { + const res = await new Promise((resolve, reject) => { + let done = false + let connected = false + let schedulaFotaTimeout: NodeJS.Timeout + progress(`Connecting to ${port ?? defaultPort}`) + connect({ + device: port ?? defaultPort, + atHostHexfile: atHost, + ...log(), + }) + .then(async ({ connection, deviceLog, onData, onEnd }) => { + const credentials = JSON.parse( + await fs.readFile( + path.resolve(certDir, `device-${deviceId}.json`), + 'utf-8', + ), + ) + + progress(`Setting timeout to ${timeoutInMinutes} minutes`) + const jobTimeout = setTimeout(async () => { + done = true + warn('Timeout reached.') + await connection.end() + if (schedulaFotaTimeout !== undefined) + clearTimeout(schedulaFotaTimeout) + resolve({ + connected, + timeout: true, + abort: false, + deviceLog, + flashLog, + }) + }, timeoutInMinutes * 60 * 1000) + + onEnd(async (_, timeout) => { + if (timeout) { + done = true + clearTimeout(jobTimeout) + if (schedulaFotaTimeout !== undefined) + clearTimeout(schedulaFotaTimeout) + warn('Device read timeout occurred.') + resolve({ + connected, + timeout: true, + abort: false, + deviceLog, + flashLog, + }) + } + await flash({ + hexfile: atHost, + ...log({ + withTimestamp: true, + prefixes: ['Resetting device with AT Host'], + }), + }) + }) + + const mfwv = (await connection.at('AT+CGMR'))[0] + if (mfwv !== undefined) { + progress(`Firmware version:`, mfwv) + const v = mfwv.split('_')[2] + if (semver.satisfies(v, '>=1.3.0')) { + progress(`Resetting modem settings`, port ?? defaultPort) + await connection.at('AT%XFACTORYRESET=0') + } else { + warn(`Please update your modem firmware!`) + } + } + + progress('Flashing credentials') + await flashCredentials({ + ...credentials, + ...connection, + secTag: secTag ?? defaultSecTag, + }) + flashLog = await flash({ + hexfile: hexFile, + ...log({ + withTimestamp: true, + prefixes: ['Flash Firmware'], + }), + }) + + const terminateOn = ( + type: 'abortOn' | 'endOn', + s: string[], + t: (s: string[]) => (s: string) => boolean, + ) => { + progress( + `<${type}>`, + `Setting up ${type} traps. Job will terminate if output contains:`, + ) + s?.map((s) => progress(`<${type}>`, s)) + const terminateCheck = t(s) + onData(async (data) => { + s?.forEach(async (s) => { + if (data.includes(s)) { + warn(`<${type}>`, 'Termination criteria seen:', s) + } + }) + if (terminateCheck(data)) { + if (!done) { + done = true + warn( + `<${type}>`, + 'All termination criteria have been seen.', + ) + clearTimeout(jobTimeout) + if (schedulaFotaTimeout !== undefined) + clearTimeout(schedulaFotaTimeout) + if (type === 'endOn') + await new Promise((resolve) => + setTimeout(resolve, (endOnWaitSeconds ?? 60) * 1000), + ) + await connection.end() + resolve({ + connected, + abort: type === 'abortOn', + timeout: false, + deviceLog, + flashLog, + }) + } + } + }) + } + + if (abortOn !== undefined) terminateOn('abortOn', abortOn, anySeen) + if (endOn !== undefined) terminateOn('endOn', endOn, allSeen) + + // Schedule Firmware update, if device has connected + const tryScheduleFota = async () => { + if ( + await deviceHasConnected({ + deviceId, + iotData, + }) + ) { + connected = true + + // Upload FOTA file + await s3.send( + new PutObjectCommand({ + Bucket: bucketName, + Key: fotaFileName, + Body: await fs.readFile(fotaFile), + ContentType: 'text/octet-stream', + }), + ) + + // Schedula + await schedulaFOTA({ + deviceId, + iot, + iotData, + bucketName, + appVersion, + fotaFile, + fotaFileName, + region: awsConfig.region, + }) + + // Done, do not reschedule + return + } + // Reschedule + schedulaFotaTimeout = setTimeout(tryScheduleFota, 60 * 1000) + } + schedulaFotaTimeout = setTimeout(tryScheduleFota, 60 * 1000) + }) + .catch(reject) + }) + // Delete FOTA file + if (connected) { + await s3.send( + new DeleteObjectCommand({ + Bucket: bucketName, + Key: fotaFileName, + }), + ) + } + + await Promise.all([ + fs.writeFile(flashLogLocation, res.flashLog.join('\n'), 'utf-8'), + fs.writeFile(deviceLogLocation, res.deviceLog.join('\n'), 'utf-8'), + ]) + return res + } catch (error) { + console.error(error) + process.exit(-1) + } + } +} diff --git a/runner/publishReport.ts b/runner/publishReport.ts deleted file mode 100644 index 80d88121..00000000 --- a/runner/publishReport.ts +++ /dev/null @@ -1,27 +0,0 @@ -import fetch from 'node-fetch' -import * as FormData from 'form-data' -import { parse } from 'url' -import * as querystring from 'querystring' - -export const uploadToS3 = async ( - url: string, - payload: Record, -): Promise => { - const formData = new FormData() - const u = parse(url) - Object.entries(querystring.parse(u.query as string)).forEach(([k, v]) => { - formData.append(k, v) - }) - formData.append('file', JSON.stringify(payload, null, 2)) - const res = await fetch(`${u.protocol}//${u.host}${u.pathname}`, { - method: 'POST', - body: formData, - }) - if (res.status >= 400) { - throw new Error( - `Failed to upload to S3: ${res.statusText} (${ - res.status - }). ${await res.text()}`, - ) - } -} diff --git a/runner/runJob.ts b/runner/runJob.ts deleted file mode 100644 index 2a91223f..00000000 --- a/runner/runJob.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { - flash, - connect, - Connection, - flashCredentials, - allSeen, - log, - runCmd, - anySeen, -} from '@nordicsemiconductor/firmware-ci-device-helpers' -import { RunningFirmwareCIJobDocument } from '../job/job' - -type Result = { timeout: boolean; abort: boolean } - -export const runJob = async ({ - doc, - hexfile, - atHostHexfile, - device, - powerCycle, - endOnWaitSeconds, -}: { - doc: RunningFirmwareCIJobDocument - hexfile: string - atHostHexfile: string - device: string - powerCycle?: { - offCmd: string - onCmd: string - waitSeconds: number - waitSecondsAfterOn: number - } - endOnWaitSeconds?: number -}): Promise<{ - result: Result - connection: Connection - deviceLog: string[] - flashLog: string[] -}> => { - const { progress, warn } = log({ withTimestamp: true, prefixes: [doc.id] }) - - if (powerCycle !== undefined) { - progress(`Power cycling device`) - progress(`Turning off ...`) - progress(powerCycle.offCmd) - await runCmd({ cmd: powerCycle.offCmd }) - progress(`Waiting ${powerCycle.waitSeconds} seconds ...`) - await new Promise((resolve) => - setTimeout(resolve, powerCycle.waitSeconds * 1000), - ) - progress(`Turning on ...`) - progress(powerCycle.onCmd) - await runCmd({ cmd: powerCycle.onCmd }) - - progress(`Waiting ${powerCycle.waitSecondsAfterOn} seconds ...`) - await new Promise((resolve) => - setTimeout(resolve, powerCycle.waitSecondsAfterOn * 1000), - ) - } - - return new Promise((resolve, reject) => { - let done = false - progress(`Connecting to ${device}`) - connect({ - device: device, - atHostHexfile, - ...log(), - }) - .then(async ({ connection, deviceLog, onData, onEnd }) => { - let flashLog: string[] = [] - const { credentials } = doc - - progress(`Setting timeout to ${doc.timeoutInMinutes} minutes`) - const jobTimeout = setTimeout(async () => { - done = true - warn('Timeout reached.') - await connection.end() - resolve({ - result: { timeout: true, abort: false }, - connection, - deviceLog, - flashLog, - }) - }, doc.timeoutInMinutes * 60 * 1000) - - onEnd(async (_, timeout) => { - if (timeout) { - done = true - clearTimeout(jobTimeout) - warn(doc.id, 'Device read timeout occurred.') - resolve({ - result: { timeout: true, abort: false }, - connection, - deviceLog, - flashLog, - }) - } - await flash({ - hexfile: atHostHexfile, - ...log({ - withTimestamp: true, - prefixes: ['Resetting device with AT Host'], - }), - }) - }) - if (credentials !== undefined) { - progress('Flashing credentials') - await flashCredentials({ - ...credentials, - ...connection, - }) - } - flashLog = await flash({ - hexfile, - ...log({ - withTimestamp: true, - prefixes: ['Flash Firmware'], - }), - }) - - const terminateOn = ( - type: 'abortOn' | 'endOn', - result: Result, - s: string[], - t: (s: string[]) => (s: string) => boolean, - ) => { - progress( - `<${type}>`, - `Setting up ${type} traps. Job will terminate if output contains:`, - ) - s?.map((s) => progress(`<${type}>`, s)) - const terminateCheck = t(s) - onData(async (data) => { - s?.forEach(async (s) => { - if (data.includes(s)) { - warn(doc.id, `<${type}>`, 'Termination criteria seen:', s) - } - }) - if (terminateCheck(data)) { - if (!done) { - done = true - warn(`<${type}>`, 'All termination criteria have been seen.') - clearTimeout(jobTimeout) - if (type === 'endOn') - await new Promise((resolve) => - setTimeout(resolve, (endOnWaitSeconds ?? 60) * 1000), - ) - await connection.end() - resolve({ - result, - connection, - deviceLog, - flashLog, - }) - } - } - }) - } - - if (doc.abortOn !== undefined) - terminateOn( - 'abortOn', - { - abort: true, - timeout: false, - }, - doc.abortOn, - anySeen, - ) - - if (doc.endOn !== undefined) - terminateOn( - 'endOn', - { - abort: false, - timeout: false, - }, - doc.endOn, - allSeen, - ) - }) - .catch(reject) - }) -} diff --git a/runner/runner.ts b/runner/runner.ts deleted file mode 100644 index ba378b04..00000000 --- a/runner/runner.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { jobs, job } from 'aws-iot-device-sdk' -import { promises as fs } from 'fs' -import { download, log } from '@nordicsemiconductor/firmware-ci-device-helpers' -import { runJob } from './runJob' -import { - defaultTimeoutInMinutes, - FirmwareCIJobDocument, - RunningFirmwareCIJobDocument, -} from '../job/job' -import { uploadToS3 } from './publishReport' - -const isUndefined = (a?: any): boolean => a === null || a === undefined - -export const runner = async ({ - certificateJSON, - atHostHexfile, - device, - powerCycle, -}: { - certificateJSON: string - atHostHexfile: string - device: string - powerCycle?: { - offCmd: string - onCmd: string - waitSeconds: number - waitSecondsAfterOn: number - } -}): Promise => { - const { clientId, brokerHostname, caCert, clientCert, privateKey } = - JSON.parse(await fs.readFile(certificateJSON, 'utf-8')) - - const { progress, debug, success, warn } = log({ withTimestamp: true }) - - debug(' MQTT endpoint: ', brokerHostname) - debug(' Device ID: ', clientId) - debug(' Host: ', atHostHexfile) - - await new Promise((resolve, reject) => { - progress('Connecting') - const connection = new jobs({ - privateKey: Buffer.from(privateKey.replace(/\\n/g, '\n')), - clientCert: Buffer.from(clientCert.replace(/\\n/g, '\n')), - caCert: Buffer.from(caCert.replace(/\\n/g, '\n')), - clientId, - host: brokerHostname, - }) - - connection.on('connect', () => { - success(`Connected to ${brokerHostname} as ${clientId}.`) - connection.subscribeToJobs( - clientId, - // There is a bug in the TypeScript definition - // @ts-ignore - async (err: Error, job: job): Promise => { - if (isUndefined(err)) { - progress( - clientId, - 'default job handler invoked, jobId:', - job.id.toString(), - ) - const doc: RunningFirmwareCIJobDocument = { - id: job.id.toString(), - timeoutInMinutes: defaultTimeoutInMinutes, - ...(job.document as FirmwareCIJobDocument), - } - if ( - new Date(doc.expires).getTime() < - Date.now() + doc.timeoutInMinutes * 60 * 1000 - ) { - job.failed({ - progress: `aborted due to job expiry`, - }) - } - progress(clientId, 'job document', doc) - job.inProgress({ - progress: `downloading ${doc.fw}`, - }) - const hexfile = await download({ - fw: doc.fw, - target: `${doc.id}.hex`, - }) - job.inProgress({ - progress: 'running', - }) - const report: Record = {} - let connection - let conclusion - try { - const run = await runJob({ - doc, - hexfile, - device, - atHostHexfile, - powerCycle, - }) - const { result, deviceLog, flashLog } = run - connection = run.connection - conclusion = () => { - job.succeeded({ - progress: 'success', - }) - } - success(job.id, 'success') - report.result = result - report.flashLog = flashLog - report.deviceLog = deviceLog - report.connection = connection - // Publish report - progress(`Publishing report to`, doc.reportUrl) - await uploadToS3(doc.reportPublishUrl, report) - } catch (err) { - warn(job.id, 'failed', err.message) - report.error = err.message - conclusion = () => { - job.failed({ - progress: err.message, - }) - } - } - // Remove hexfile - await fs.unlink(hexfile) - success(job.id, 'HEX file deleted') - conclusion?.() - } else { - warn(clientId, err) - } - }, - ) - }) - - connection.startJobNotifications(clientId, (err) => { - if (isUndefined(err)) { - success(clientId, `registered for jobs.`) - resolve(connection) - } else { - warn(clientId, err) - reject(err) - } - }) - - connection.on('error', reject) - }) -} diff --git a/scheduleFOTA.ts b/scheduleFOTA.ts new file mode 100644 index 00000000..a8378a47 --- /dev/null +++ b/scheduleFOTA.ts @@ -0,0 +1,66 @@ +import { log } from '@nordicsemiconductor/firmware-ci-device-helpers' +import { IoTDataPlaneClient } from '@aws-sdk/client-iot-data-plane' +import { + IoTClient, + DescribeThingCommand, + CreateJobCommand, +} from '@aws-sdk/client-iot' +import { promises as fs } from 'fs' +import { v4 } from 'uuid' + +export const schedulaFOTA = async ({ + deviceId, + iot, + fotaFile, + fotaFileName, + region, + bucketName, + appVersion, +}: { + deviceId: string + iot: IoTClient + iotData: IoTDataPlaneClient + fotaFile: string + fotaFileName: string + region: string + bucketName: string + appVersion: string +}): Promise => { + const { progress } = log({ prefixes: ['FOTA', deviceId] }) + + const { thingArn } = await iot.send( + new DescribeThingCommand({ + thingName: deviceId, + }), + ) + if (thingArn === undefined) + throw new Error(`Failed to describe thing ${deviceId}!`) + + const stat = await fs.stat(fotaFile) + const fotaJobDocument = { + operation: 'app_fw_update', + size: stat.size, + filename: fotaFileName, + location: { + protocol: 'https', + host: `${bucketName}.s3-${region}.amazonaws.com`, + path: fotaFileName, + }, + fwversion: `${appVersion}-upgraded`, + targetBoard: '9160DK', + } + const jobId = v4() + await iot.send( + new CreateJobCommand({ + jobId, + targets: [thingArn], + document: JSON.stringify(fotaJobDocument), + description: `Upgrade ${ + thingArn.split('/')[1] + } to version ${appVersion}-upgraded.`, + targetSelection: 'SNAPSHOT', + }), + ) + progress(`FOTA job "${jobId}" created.`) + return jobId +}