├── .dockerignore
├── .github
├── FUNDING.yml
├── dependabot.yml
└── workflows
│ └── publish.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── package.json
├── src
├── config.ts
├── config_schema.ts
├── home_assistant.ts
├── index.ts
├── log.ts
├── mqtt.ts
├── net-snmp.d.ts
├── safe-eval.d.ts
├── snmp.ts
├── types.ts
└── util.ts
├── tsconfig.json
└── yarn.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: https://www.buymeacoffee.com/dchesterton
2 |
3 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | ignore:
8 | - dependency-name: "@types/node"
9 | commit-message:
10 | prefix: ""
11 | prefix-development: "[ci skip]"
12 | - package-ecosystem: "github-actions"
13 | directory: "/"
14 | schedule:
15 | interval: "daily"
16 | commit-message:
17 | prefix: "[ci skip]"
18 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | docker-publish:
10 | name: Publish to Docker Hub
11 | if: "!contains(github.event.head_commit.message, '[ci skip]')"
12 | runs-on: ubuntu-20.04
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v2.4.0
16 | - name: Automated version bump
17 | uses: phips28/gh-action-bump-version@master
18 | id: bump
19 | env:
20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21 | - name: Extract version
22 | run: |
23 | RE='[^0-9]*\([0-9]*\)[.]\([0-9]*\)[.]\([0-9]*\)\([0-9A-Za-z-]*\)'
24 | MAJOR=`echo $version | sed -e "s#$RE#\1#"`
25 | MINOR=`echo $version | sed -e "s#$RE#\2#"`
26 | PATCH=`echo $version | sed -e "s#$RE#\3#"`
27 | echo "::set-output name=version::$MAJOR.$MINOR.$PATCH"
28 | echo "::set-output name=major::$MAJOR"
29 | echo "::set-output name=minor::$MAJOR.$MINOR"
30 | id: version
31 | env:
32 | version: ${{ steps.bump.outputs.newTag }}
33 | - name: Set up QEMU
34 | uses: docker/setup-qemu-action@v1.2.0
35 | - name: Set up Docker Buildx
36 | uses: docker/setup-buildx-action@v1.6.0
37 | - name: Login to DockerHub
38 | uses: docker/login-action@v1.12.0
39 | with:
40 | username: ${{ secrets.DOCKER_USERNAME }}
41 | password: ${{ secrets.DOCKER_PASSWORD }}
42 | - name: Build and push
43 | uses: docker/build-push-action@v2.7.0
44 | with:
45 | push: true
46 | platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x
47 | tags: |
48 | dchesterton/snmp2mqtt:latest
49 | dchesterton/snmp2mqtt:${{ steps.version.outputs.version }}
50 | labels: "version=${{ steps.version.outputs.version }}"
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | coverage
3 | dist
4 | node_modules
5 | config.yml
6 | yarn-error.log
7 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16-alpine AS base
2 | FROM base as builder
3 |
4 | WORKDIR /app
5 |
6 | COPY package.json /app
7 | COPY yarn.lock /app
8 | COPY tsconfig.json /app
9 | COPY src /app/src
10 |
11 | RUN yarn install --frozen-lockfile
12 | RUN yarn build
13 |
14 | RUN mv /app/node_modules /app/node_modules_dev
15 | RUN yarn install --frozen-lockfile --production
16 |
17 | FROM base
18 | STOPSIGNAL SIGINT
19 | WORKDIR /app
20 |
21 | COPY --from=builder /app/node_modules /app/node_modules
22 | COPY --from=builder /app/dist /app/dist
23 | COPY --from=builder /app/package.json /app/package.json
24 |
25 | CMD [ "node", "/app/dist/index.js" ]
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Daniel Chesterton
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # snmp2mqtt
2 |
3 | Expose SNMP sensors to MQTT.
4 |
5 | ## config.yml
6 |
7 | ```yaml
8 | log: debug # Optional: debug, info, warning or error (default: info)
9 |
10 | mqtt:
11 | host: 192.168.1.5 # Optional: broker URL or IP address (default: localhost)
12 | port: 1884 # Optional: broker port (default: 1883 or 8883 for TLS connections)
13 | username: my_user # Optional: broker user (default: none)
14 | password: my_password # Optional: broker password (default: none)
15 | client_id: snmp2mqtt # Optional: client ID (default: snmp2mqtt)
16 | keepalive: 30 # Optional: keepalive in seconds (default: 10)
17 | clean: true # Optional: clean session (default: true)
18 | retain: true # Optional: retain (default: true)
19 | qos: 2 # Optional: QoS (default: 0)
20 | ca: /cert/ca.pem # Optional: CA for TLS connection (default: none)
21 | cert: /cert/cert.pem # Optional: certificate for TLS connection (default: none)
22 | key: /cert/key.pem # Optional: private key for TLS connection (default: none)
23 | reject_unauthorized: true # Optional: if not false, the server certificate is verified against the list of supplied CAs. Override with caution (default: true when using TLS)
24 |
25 | homeassistant:
26 | discovery: true # Optional: enable Home Assistant discovery (default: false)
27 | prefix: "home-assistant" # Optional: Home Assistant MQTT topic prefix (default: homeassistant)
28 |
29 | targets:
30 | - host: 192.168.0.2 # Required: target IP address
31 | name: Raspberry Pi # Optional: target name
32 | scan_interval: 30 # Optional: fetch interval in seconds (default: 10)
33 | device_manufacturer: Raspberry Pi # Optional: set the device manufacturer in Home Assistant
34 | device_model: 3 Model B # Optional: set the device model in Home Assistant
35 | suggested_area: Bedroom # Optional: set the area in Home Assistant
36 | auth_key: password # Optional: set the auth password for SNMPv3
37 | auth_protocol: sha # Optional: set the auth protocol for SNMPv3, one of sha or md5
38 | priv_key: password # Optional: set the privilege password for SNMPv3
39 | priv_protocol: des # Optional: set the privilege protocol for SNMPv3, one of des, aes, aes256b or aes256r
40 | version: "3" # Optional: 1, 2c or 3 (default: 1)
41 | sensors:
42 | - oid: 1.3.6.1.2.1.25.1.1.0 # Required: SNMP oid
43 | name: Raspberry Pi Uptime # Required: sensor name
44 | unit_of_measurement: days # Optional: set the unit of measurement in Home Assistant
45 | transform: "value / 6000" # Optional: a transform function written in JavaScript
46 | icon: mdi:calendar-clock # Optional: set an icon in Home Assistant
47 | binary_sensor: false # Optional: whether to expose the sensor as a binary sensor in Home Assistant
48 |
49 | - host: 192.168.0.3
50 | name: Raspberry Pi 2
51 | version: 2c
52 | sensors:
53 | - oid: 1.3.6.1.2.1.25.1.1.0
54 | name: Raspberry Pi 2 Uptime
55 | unit_of_measurement: days
56 | transform: "Math.floor(value / 6000 / 60 / 24)"
57 | icon: mdi:calendar-clock
58 |
59 | - oid: 1.3.6.1.4.1.2021.11.11.0
60 | name: Raspberry Pi 2 CPU
61 | unit_of_measurement: "%"
62 | transform: "100 - value"
63 | icon: mdi:cpu-64-bit
64 | ```
65 |
66 | ## Running the app
67 |
68 | The easiest way to run the app is via Docker Compose, e.g.
69 |
70 | ```yaml
71 | version: "3"
72 | services:
73 | snmp2mqtt:
74 | container_name: snmp2mqtt
75 | image: dchesterton/snmp2mqtt:latest
76 | restart: unless-stopped
77 | volumes:
78 | - ./config.yml:/app/config.yml
79 | ```
80 |
81 | ## Buy Me A ~~Coffee~~ Beer 🍻
82 |
83 | A few people have kindly requested a way to donate a small amount of money. If you feel so inclined I've set up a "Buy Me A Coffee"
84 | page where you can donate a small sum. Please do not feel obligated to donate in any way - I work on the app because it's
85 | useful to myself and others, not for any financial gain - but any token of appreciation is much appreciated 🙂
86 |
87 |
88 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "snmp2mqtt",
3 | "version": "0.2.4",
4 | "license": "MIT",
5 | "bin": {
6 | "snmp2mqtt": "dist/index.js"
7 | },
8 | "author": "Daniel Chesterton",
9 | "dependencies": {
10 | "ajv": "^8.8.2",
11 | "async-mqtt": "^2.6.1",
12 | "better-ajv-errors": "^1.1.2",
13 | "bigint-buffer": "^1.1.5",
14 | "js-yaml": "^4.1.0",
15 | "luxon": "^2.3.0",
16 | "net-snmp": "^3.5.8",
17 | "slugify": "^1.6.5"
18 | },
19 | "devDependencies": {
20 | "@tsconfig/node16": "^1.0.2",
21 | "@types/js-yaml": "^4.0.5",
22 | "@types/luxon": "^2.0.8",
23 | "@types/node": "^14.14.27",
24 | "prettier": "^2.5.1",
25 | "ts-node": "^10.4.0",
26 | "typescript": "^4.5.4"
27 | },
28 | "scripts": {
29 | "build": "rm -rf dist && tsc",
30 | "start": "ts-node --files src/index.ts",
31 | "prettier:write": "prettier src --write"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import Ajv from "ajv";
2 | import betterAjvErrors from "better-ajv-errors";
3 | import * as fs from "fs";
4 | import { JSON_SCHEMA, load } from "js-yaml";
5 |
6 | import { schema } from "./config_schema";
7 | import { createLogger } from "./log";
8 | import { Config } from "./types";
9 |
10 | export function loadConfig(): Config {
11 | const yamlConfig = loadYamlConfig();
12 |
13 | if (yamlConfig) {
14 | return validate(yamlConfig);
15 | }
16 |
17 | throw new Error("Could not find config file");
18 | }
19 |
20 | function validate(userConfig: unknown) {
21 | const ajv = new Ajv({
22 | allowUnionTypes: true,
23 | useDefaults: true,
24 | allErrors: true,
25 | });
26 |
27 | const validator = ajv.compile(schema);
28 |
29 | if (!validator(userConfig)) {
30 | const errors = betterAjvErrors(schema, userConfig, validator.errors!, {
31 | format: "js",
32 | });
33 |
34 | if (errors && errors.length) {
35 | const log = createLogger("ERROR");
36 |
37 | log.error(
38 | `${errors.length} error${
39 | errors.length > 1 ? "s" : ""
40 | } found in config...`
41 | );
42 | for (const error of errors) {
43 | log.error(error.error);
44 | }
45 |
46 | process.exit(1);
47 | }
48 | }
49 |
50 | return userConfig as Config;
51 | }
52 |
53 | function loadYamlConfig() {
54 | const fileName = `${process.cwd()}/config.yml`;
55 |
56 | if (!fs.existsSync(fileName)) {
57 | return false;
58 | }
59 |
60 | try {
61 | return load(fs.readFileSync(fileName, "utf8"), {
62 | schema: JSON_SCHEMA,
63 | });
64 | } catch (e) {
65 | throw new Error(`Error loading config file: ${e}`);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/config_schema.ts:
--------------------------------------------------------------------------------
1 | export const schema = {
2 | $schema: "http://json-schema.org/draft-07/schema",
3 | $id: "https://github.com/dchesterton/snmp2mqtt/tree/master/src/config_schema.json",
4 | type: "object",
5 | definitions: {
6 | target: {
7 | type: "object",
8 | required: ["host", "sensors"],
9 | properties: {
10 | host: {
11 | type: "string",
12 | },
13 | name: {
14 | type: "string",
15 | },
16 | device_manufacturer: {
17 | type: "string",
18 | },
19 | device_model: {
20 | type: "string",
21 | },
22 | suggested_area: {
23 | type: "string",
24 | },
25 | port: {
26 | type: "number",
27 | },
28 | community: {
29 | type: "string",
30 | },
31 | version: {
32 | type: ["string", "number"],
33 | },
34 | scan_interval: {
35 | type: "number",
36 | },
37 | username: {
38 | type: "string",
39 | },
40 | auth_key: {
41 | type: "string",
42 | },
43 | auth_protocol: {
44 | type: "string",
45 | enum: ["sha", "md5"],
46 | },
47 | priv_key: {
48 | type: "string",
49 | },
50 | priv_protocol: {
51 | type: "string",
52 | enum: ["des", "aes", "aes256b", "aes256r"],
53 | },
54 | sensors: {
55 | type: "array",
56 | default: [],
57 | items: { $ref: "#/definitions/sensor" },
58 | },
59 | user: {
60 | type: "string",
61 | },
62 | level: {
63 | type: "string",
64 | enum: ["noAuthNoPriv", "authNoPriv", "authPriv"],
65 | },
66 | },
67 | additionalProperties: false,
68 | },
69 | sensor: {
70 | type: "object",
71 | required: ["oid", "name"],
72 | properties: {
73 | oid: {
74 | type: "string",
75 | },
76 | name: {
77 | type: "string",
78 | },
79 | transform: {
80 | type: "string",
81 | },
82 | unit_of_measurement: {
83 | type: "string",
84 | },
85 | device_class: {
86 | type: "string",
87 | },
88 | icon: {
89 | type: "string",
90 | },
91 | binary_sensor: {
92 | type: "boolean",
93 | },
94 | },
95 | additionalProperties: false,
96 | },
97 | },
98 | properties: {
99 | mqtt: {
100 | type: "object",
101 | default: {},
102 | properties: {
103 | client_id: {
104 | type: "string",
105 | default: "snmp2mqtt",
106 | },
107 | host: {
108 | type: "string",
109 | default: "localhost",
110 | },
111 | port: {
112 | type: "number",
113 | },
114 | keepalive: {
115 | type: "number",
116 | default: 10,
117 | },
118 | password: {
119 | type: "string",
120 | default: "",
121 | },
122 | qos: {
123 | enum: [0, 1, 2],
124 | type: "number",
125 | default: 0,
126 | },
127 | retain: {
128 | type: "boolean",
129 | default: true,
130 | },
131 | username: {
132 | type: "string",
133 | default: "",
134 | },
135 | ca: {
136 | type: "string",
137 | },
138 | cert: {
139 | type: "string",
140 | },
141 | key: {
142 | type: "string",
143 | },
144 | reject_unauthorized: {
145 | type: "boolean",
146 | },
147 | clean: {
148 | type: "boolean",
149 | default: true,
150 | },
151 | },
152 | additionalProperties: false,
153 | },
154 | homeassistant: {
155 | type: "object",
156 | default: {},
157 | properties: {
158 | discovery: {
159 | type: "boolean",
160 | default: false,
161 | },
162 | prefix: {
163 | type: "string",
164 | default: "homeassistant",
165 | },
166 | },
167 | additionalProperties: false,
168 | },
169 | targets: {
170 | type: "array",
171 | default: [],
172 | items: { $ref: "#/definitions/target" },
173 | },
174 | log: {
175 | type: "string",
176 | enum: ["debug", "error", "info", "warning"],
177 | default: "info",
178 | },
179 | },
180 | additionalProperties: false,
181 | };
182 |
--------------------------------------------------------------------------------
/src/home_assistant.ts:
--------------------------------------------------------------------------------
1 | import { Client } from "./mqtt";
2 | import { TargetConfig } from "./types";
3 | import { md5, slugify } from "./util";
4 |
5 | export const createHomeAssistantTopics = async (
6 | mqtt: Client,
7 | targets: Array,
8 | prefix: string
9 | ) => {
10 | const promises = [];
11 |
12 | for (const target of targets) {
13 | const device: any = {
14 | name: target.name ?? target.host,
15 | identifiers: target.host,
16 | via_device: "snmp2mqtt",
17 | };
18 |
19 | if (target.suggested_area) {
20 | device.suggested_area = target.suggested_area;
21 | }
22 | if (target.device_manufacturer) {
23 | device.manufacturer = target.device_manufacturer;
24 | }
25 | if (target.device_model) {
26 | device.model = target.device_model;
27 | }
28 |
29 | for (const sensor of target.sensors) {
30 | const sensorType = sensor.binary_sensor
31 | ? "binary_sensor"
32 | : "sensor";
33 | const sensorName = slugify(sensor.name);
34 | const topic = `${prefix}/${sensorType}/snmp2mqtt/${sensorName}/config`;
35 |
36 | const discovery: any = {
37 | availability: [
38 | {
39 | topic: mqtt.STATUS_TOPIC,
40 | },
41 | {
42 | topic: mqtt.sensorStatusTopic(sensor, target),
43 | },
44 | ],
45 | availability_mode: "all",
46 | device,
47 | name: sensor.name,
48 | unique_id: `snmp2mqtt.${md5(`${target.host}-${sensor.oid}`)}`,
49 | state_topic: mqtt.sensorValueTopic(sensor, target),
50 | qos: mqtt.qos,
51 | entity_category: "diagnostic",
52 | };
53 |
54 | if (sensor.unit_of_measurement) {
55 | discovery.unit_of_measurement = sensor.unit_of_measurement;
56 | }
57 | if (sensor.device_class) {
58 | discovery.device_class = sensor.device_class;
59 | }
60 | if (sensor.icon) {
61 | discovery.icon = sensor.icon;
62 | }
63 |
64 | promises.push(mqtt.publish(topic, discovery));
65 | }
66 | }
67 |
68 | await Promise.all(promises);
69 | };
70 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { createLogger } from "./log";
2 | import { createClient } from "./mqtt";
3 | import { Target } from "./snmp";
4 | import { loadConfig } from "./config";
5 | import { TargetConfig } from "./types";
6 | import { createHomeAssistantTopics } from "./home_assistant";
7 | import { readFileSync } from "fs";
8 |
9 | const config = loadConfig();
10 | const log = createLogger(config.log);
11 |
12 | (async () => {
13 | const version: string = JSON.parse(
14 | readFileSync(`${__dirname}/../package.json`).toString()
15 | ).version;
16 |
17 | log.info(`Starting snmp2mqtt v${version}...`);
18 |
19 | const mqtt = await createClient(config.mqtt, log, version);
20 |
21 | if (config.homeassistant.discovery) {
22 | await createHomeAssistantTopics(
23 | mqtt,
24 | config.targets,
25 | config.homeassistant.prefix
26 | );
27 | }
28 |
29 | const publishSensors = async (
30 | values: Array,
31 | target: TargetConfig
32 | ) => {
33 | const promises: Array> = [];
34 |
35 | for (const i in values) {
36 | const value = values[i];
37 | const sensor = target.sensors[i];
38 |
39 | if (value instanceof Error) {
40 | log.warning(
41 | `Error ${value.message} fetching sensor ${JSON.stringify(
42 | sensor
43 | )} from ${target.host}`
44 | );
45 |
46 | promises.push(
47 | mqtt.publish(
48 | mqtt.sensorStatusTopic(sensor, target),
49 | mqtt.OFFLINE
50 | )
51 | );
52 | } else {
53 | log.info(
54 | `[${target.host}] ${sensor.name}: ${value}${
55 | sensor.unit_of_measurement
56 | ? `${sensor.unit_of_measurement}`
57 | : ""
58 | }`
59 | );
60 |
61 | promises.push(
62 | mqtt.publish(mqtt.sensorValueTopic(sensor, target), value),
63 | mqtt.publish(
64 | mqtt.sensorStatusTopic(sensor, target),
65 | mqtt.ONLINE
66 | )
67 | );
68 | }
69 | }
70 |
71 | await Promise.all(promises);
72 | };
73 |
74 | const clients: Target[] = [];
75 |
76 | for (const target of config.targets) {
77 | const client = new Target(target, log);
78 | client.on("response", publishSensors);
79 | client.connect();
80 |
81 | clients.push(client);
82 | }
83 |
84 | const pauseClients = () => {
85 | log.warning("MQTT client disconnected");
86 | clients.forEach((client) => client.pause());
87 | };
88 |
89 | mqtt.on("close", pauseClients);
90 |
91 | mqtt.on("connect", () => {
92 | clients.forEach((client) => client.resume());
93 | });
94 |
95 | const exit = async (code: number = 0) => {
96 | log.info("Exiting program...");
97 | mqtt.off("close", pauseClients);
98 |
99 | await mqtt.end();
100 |
101 | for (const client of clients) {
102 | await client.end();
103 | }
104 |
105 | process.exit(code);
106 | };
107 |
108 | process.on("SIGINT", async () => {
109 | log.info("Caught interrupt signal, exiting gracefully...");
110 | await exit(0);
111 | });
112 |
113 | process.on("unhandledRejection", async (error) => {
114 | log.error(`Unhandled rejection - ${error}`);
115 | await exit(1);
116 | });
117 | })();
118 |
--------------------------------------------------------------------------------
/src/log.ts:
--------------------------------------------------------------------------------
1 | import { DateTime } from "luxon";
2 |
3 | enum LogLevel {
4 | DEBUG = 0,
5 | INFO = 1,
6 | WARNING = 2,
7 | ERROR = 3,
8 | }
9 |
10 | export type LogLevelStrings = keyof typeof LogLevel;
11 | export type Logger = ReturnType;
12 |
13 | export const createLogger = (minLevel: LogLevelStrings) => {
14 | const n = LogLevel[minLevel.toUpperCase() as LogLevelStrings];
15 |
16 | const createLevelFn = (level: LogLevel, min: LogLevel) => (msg: string) => {
17 | if (level < min) {
18 | return;
19 | }
20 |
21 | const timestampStr = DateTime.utc().toFormat("yyyy-LL-dd HH:mm:ss");
22 | console.log(`${timestampStr} - ${LogLevel[level]}: ${msg}`);
23 | };
24 |
25 | const debug = createLevelFn(LogLevel.DEBUG, n);
26 | const info = createLevelFn(LogLevel.INFO, n);
27 | const warning = createLevelFn(LogLevel.WARNING, n);
28 | const error = createLevelFn(LogLevel.ERROR, n);
29 |
30 | return { debug, info, warning, error };
31 | };
32 |
--------------------------------------------------------------------------------
/src/mqtt.ts:
--------------------------------------------------------------------------------
1 | import { IClientOptions, connectAsync, AsyncMqttClient } from "async-mqtt";
2 | import { MQTTConfig, SensorConfig, TargetConfig } from "./types";
3 | import { readFileSync } from "fs";
4 | import { slugify } from "./util";
5 | import { Logger } from "./log";
6 | import { EventEmitter } from "events";
7 |
8 | const OFFLINE = "offline";
9 | const ONLINE = "online";
10 |
11 | const STATUS_TOPIC = "snmp2mqtt/status";
12 | const CONFIG_TOPIC = "snmp2mqtt/config";
13 |
14 | const connect = (config: MQTTConfig) => {
15 | const port = config.port ? config.port : config.ca ? 8883 : 1883;
16 |
17 | const options: IClientOptions = {
18 | hostname: config.host,
19 | protocol: "mqtt",
20 | port,
21 | will: {
22 | topic: STATUS_TOPIC,
23 | payload: OFFLINE,
24 | retain: config.retain,
25 | qos: config.qos,
26 | },
27 | clientId: config.client_id,
28 | clean: config.clean,
29 | keepalive: config.keepalive,
30 | reconnectPeriod: 5000,
31 | rejectUnauthorized: config.reject_unauthorized,
32 | };
33 |
34 | console.log(config);
35 |
36 | if (config.username) {
37 | options.username = config.username;
38 | }
39 |
40 | if (config.password) {
41 | options.password = config.password;
42 | }
43 |
44 | if (config.ca) {
45 | options.ca = readFileSync(config.ca);
46 | options.protocol = "mqtts";
47 | }
48 |
49 | if (config.cert) {
50 | options.cert = readFileSync(config.cert);
51 | options.protocol = "mqtts";
52 | }
53 |
54 | if (config.key) {
55 | options.key = readFileSync(config.key);
56 | options.protocol = "mqtts";
57 | }
58 |
59 | return connectAsync(options);
60 | };
61 |
62 | export const createClient = async (
63 | config: MQTTConfig,
64 | log: Logger,
65 | version: string
66 | ) => {
67 | const emitter = new EventEmitter();
68 |
69 | let client: AsyncMqttClient = await connect(config);
70 |
71 | const publish = (
72 | topic: string,
73 | message: string | Record | number | bigint
74 | ) => {
75 | if (!client.connected) {
76 | log.warning(`Skipping publish to ${topic}, MQTT connection closed`);
77 | return Promise.resolve(null);
78 | }
79 | const payload =
80 | typeof message === "object"
81 | ? JSON.stringify(message)
82 | : String(message);
83 |
84 | log.debug(
85 | `Writing to ${topic} (QOS: ${config.qos}, retain: ${
86 | config.retain ? "true" : "false"
87 | })`
88 | );
89 |
90 | return client.publish(topic, payload, {
91 | qos: config.qos,
92 | retain: config.retain,
93 | });
94 | };
95 |
96 | const onConnect = async () => {
97 | await publish(STATUS_TOPIC, ONLINE);
98 | await publish(CONFIG_TOPIC, { version });
99 | emitter.emit("connect");
100 | };
101 |
102 | client.on("close", async () => {
103 | emitter.emit("close");
104 | });
105 |
106 | client.on("connect", onConnect);
107 |
108 | await onConnect();
109 |
110 | return {
111 | publish,
112 | sensorStatusTopic: (sensor: SensorConfig, target: TargetConfig) =>
113 | `snmp2mqtt/${target.host}/${slugify(sensor.name)}/status`,
114 | sensorValueTopic: (sensor: SensorConfig, target: TargetConfig) =>
115 | `snmp2mqtt/${target.host}/${slugify(sensor.name)}/value`,
116 | STATUS_TOPIC,
117 | ONLINE,
118 | OFFLINE,
119 | on: (event: "close" | "connect", cb: () => void) =>
120 | emitter.on(event, cb),
121 | off: (event: "close" | "connect", cb: () => void) =>
122 | emitter.off(event, cb),
123 | end: async () => {
124 | await client.publish(STATUS_TOPIC, OFFLINE);
125 | await client.end();
126 | },
127 | qos: config.qos,
128 | };
129 | };
130 |
131 | type ThenArg = T extends PromiseLike ? U : T;
132 | export type Client = ThenArg>;
133 |
--------------------------------------------------------------------------------
/src/net-snmp.d.ts:
--------------------------------------------------------------------------------
1 | declare module "net-snmp";
2 |
--------------------------------------------------------------------------------
/src/safe-eval.d.ts:
--------------------------------------------------------------------------------
1 | declare module "safe-eval";
2 |
--------------------------------------------------------------------------------
/src/snmp.ts:
--------------------------------------------------------------------------------
1 | import * as snmp from "net-snmp";
2 |
3 | import { TargetConfig, VersionConfig } from "./types";
4 | import { EventEmitter } from "events";
5 | import { Logger } from "./log";
6 | import { toBigIntBE } from "bigint-buffer";
7 |
8 | const versionToNetSnmp = (version?: VersionConfig) => {
9 | switch (version) {
10 | case "2c":
11 | return snmp.Version2c as number;
12 | case 3:
13 | case "3":
14 | return snmp.Version3 as number;
15 | default:
16 | return snmp.Version1 as number;
17 | }
18 | };
19 |
20 | export declare interface Target {
21 | on(
22 | event: "response",
23 | listener: (
24 | values: Array,
25 | target: TargetConfig
26 | ) => void
27 | ): this;
28 | }
29 |
30 | export class Target extends EventEmitter {
31 | private session: any;
32 | private interval?: NodeJS.Timer;
33 | private ending: boolean = false;
34 |
35 | public constructor(private options: TargetConfig, private log: Logger) {
36 | super();
37 | }
38 |
39 | public pause() {
40 | if (this.interval) {
41 | clearInterval(this.interval);
42 | }
43 | }
44 |
45 | public resume() {
46 | this.interval = setInterval(() => {
47 | this.fetch();
48 | }, this.getScanInterval());
49 |
50 | this.fetch();
51 | }
52 |
53 | public end() {
54 | this.ending = true;
55 |
56 | return new Promise((res) => {
57 | this.session.on("close", () => {
58 | res();
59 | });
60 | this.session.close();
61 | });
62 | }
63 |
64 | private getScanInterval() {
65 | return (this.options.scan_interval ?? 10) * 1000;
66 | }
67 |
68 | public connect() {
69 | const scanIntervalMs = this.getScanInterval();
70 |
71 | const options: any = {
72 | port: this.options.port ?? 161,
73 | retries: 3,
74 | timeout: scanIntervalMs > 5000 ? 5000 : scanIntervalMs / 2,
75 | backoff: 1.0,
76 | version: versionToNetSnmp(this.options.version),
77 | };
78 |
79 | if (options.version === snmp.Version3) {
80 | const user: any = {
81 | name: this.options.username,
82 | };
83 |
84 | if (this.options.auth_key && this.options.priv_key) {
85 | user.level = snmp.SecurityLevel.authPriv;
86 | } else if (this.options.auth_key && !this.options.priv_key) {
87 | user.level = snmp.SecurityLevel.authNoPriv;
88 | } else {
89 | user.level = snmp.SecurityLevel.noAuthNoPriv;
90 | }
91 |
92 | if (this.options.auth_protocol) {
93 | user.authProtocol =
94 | snmp.AuthProtocols[this.options.auth_protocol];
95 | }
96 | if (this.options.auth_key) {
97 | user.authKey = this.options.auth_key;
98 | }
99 |
100 | if (this.options.priv_protocol) {
101 | user.privProtocol =
102 | snmp.PrivProtocols[this.options.priv_protocol];
103 | }
104 | if (this.options.priv_key) {
105 | user.privKey = this.options.priv_key;
106 | }
107 |
108 | this.session = snmp.createV3Session(
109 | this.options.host,
110 | user,
111 | options
112 | );
113 | } else {
114 | const community = this.options.community ?? "public";
115 | this.session = snmp.createSession(
116 | this.options.host,
117 | community,
118 | options
119 | );
120 | }
121 |
122 | this.session.on("close", () => {
123 | if (this.ending) {
124 | return;
125 | }
126 |
127 | this.log.warning(`Target ${this.options.host} disconnected`);
128 | this.pause();
129 |
130 | setTimeout(() => {
131 | this.connect();
132 | }, 2000);
133 | });
134 |
135 | this.resume();
136 | }
137 |
138 | public close() {
139 | if (this.interval) {
140 | clearInterval(this.interval);
141 | }
142 | }
143 |
144 | private fetch() {
145 | const oids = this.options.sensors.map((sensor) => sensor.oid);
146 |
147 | this.log.debug(
148 | `Fetching ${oids.length} sensors from ${this.options.host}...`
149 | );
150 |
151 | this.session.get(
152 | oids,
153 | (error: Error, varbinds: Array<{ value: string | number }>) => {
154 | if (error) {
155 | const errors = [];
156 |
157 | for (let i = 0; i < oids.length; i++) {
158 | errors.push(error);
159 | }
160 |
161 | this.emit("response", errors, this.options);
162 | } else {
163 | const values = [];
164 |
165 | for (const i in this.options.sensors) {
166 | const sensor = this.options.sensors[i];
167 | const result = varbinds[i];
168 |
169 | if (snmp.isVarbindError(result)) {
170 | values.push(new Error(snmp.varbindError(result)));
171 | } else {
172 | let { value, type } = result as {
173 | value: string | number | Buffer | bigint;
174 | type: any;
175 | };
176 |
177 | switch (type) {
178 | case snmp.ObjectType.Counter64:
179 | value = toBigIntBE(value as Buffer);
180 | break;
181 | case snmp.ObjectType.OctetString:
182 | value = value.toString();
183 | break;
184 | }
185 |
186 | if (sensor.transform) {
187 | value = eval(sensor.transform);
188 | }
189 |
190 | values.push(value);
191 | }
192 | }
193 |
194 | this.emit("response", values, this.options);
195 | }
196 | }
197 | );
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import { LogLevelStrings } from "./log";
2 |
3 | export interface MQTTConfig {
4 | host: string;
5 | port?: number;
6 | username?: string;
7 | password?: string;
8 | retain: boolean;
9 | qos: 0 | 1 | 2;
10 | client_id?: string;
11 | keepalive?: number;
12 | ca?: string;
13 | cert?: string;
14 | key?: string;
15 | clean: boolean;
16 | reject_unauthorized?: boolean;
17 | }
18 |
19 | export interface TargetConfig {
20 | host: string;
21 | sensors: SensorConfig[];
22 | name?: string;
23 | device_manufacturer?: string;
24 | device_model?: string;
25 | suggested_area?: string;
26 | community?: string;
27 | version?: VersionConfig;
28 | port?: number;
29 | scan_interval?: number;
30 | username?: string;
31 | auth_protocol?: "md5" | "sha";
32 | auth_key?: string;
33 | priv_protocol?: "des" | "aes" | "aes256b" | "aes256r";
34 | priv_key?: string;
35 | }
36 |
37 | export type VersionConfig = "1" | 1 | "2c" | 3 | "3";
38 |
39 | export interface SensorConfig {
40 | oid: string;
41 | name: string;
42 | transform?: string;
43 | unit_of_measurement?: string;
44 | device_class?: string;
45 | icon?: string;
46 | binary_sensor?: boolean;
47 | }
48 |
49 | export interface Config {
50 | log: LogLevelStrings;
51 | mqtt: MQTTConfig;
52 | homeassistant: HomeAssistantConfig;
53 | targets: Array;
54 | }
55 |
56 | export interface HomeAssistantConfig {
57 | discovery: boolean;
58 | prefix: string;
59 | }
60 |
--------------------------------------------------------------------------------
/src/util.ts:
--------------------------------------------------------------------------------
1 | import slugifyFn from "slugify";
2 | import { createHash } from "crypto";
3 |
4 | export function slugify(str: string) {
5 | return slugifyFn(
6 | str.toLowerCase().replaceAll("-", "_").replaceAll("~", "_"),
7 | {
8 | replacement: "_",
9 | strict: true,
10 | }
11 | ).replace(/^_+|_+$/g, "");
12 | }
13 |
14 | export const md5 = (str: string) => createHash("md5").update(str).digest("hex");
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/node16/tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/code-frame@^7.16.0":
6 | version "7.16.0"
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431"
8 | integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==
9 | dependencies:
10 | "@babel/highlight" "^7.16.0"
11 |
12 | "@babel/helper-validator-identifier@^7.15.7":
13 | version "7.15.7"
14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
15 | integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
16 |
17 | "@babel/highlight@^7.16.0":
18 | version "7.16.0"
19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a"
20 | integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==
21 | dependencies:
22 | "@babel/helper-validator-identifier" "^7.15.7"
23 | chalk "^2.0.0"
24 | js-tokens "^4.0.0"
25 |
26 | "@cspotcode/source-map-consumer@0.8.0":
27 | version "0.8.0"
28 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
29 | integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
30 |
31 | "@cspotcode/source-map-support@0.7.0":
32 | version "0.7.0"
33 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
34 | integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
35 | dependencies:
36 | "@cspotcode/source-map-consumer" "0.8.0"
37 |
38 | "@humanwhocodes/momoa@^2.0.2":
39 | version "2.0.2"
40 | resolved "https://registry.yarnpkg.com/@humanwhocodes/momoa/-/momoa-2.0.2.tgz#127d18c22abf4dd988797c898b4356db8d99b662"
41 | integrity sha512-mkMcsshJ7L17AyntqpyjLiGqhbG62w93B0StW+HSNVJ1WUeVFA2uPssV/GufEfDqN6lRKI1I+uDzBUw83C0VuA==
42 |
43 | "@tsconfig/node10@^1.0.7":
44 | version "1.0.7"
45 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.7.tgz#1eb1de36c73478a2479cc661ef5af1c16d86d606"
46 | integrity sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==
47 |
48 | "@tsconfig/node12@^1.0.7":
49 | version "1.0.7"
50 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.7.tgz#677bd9117e8164dc319987dd6ff5fc1ba6fbf18b"
51 | integrity sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==
52 |
53 | "@tsconfig/node14@^1.0.0":
54 | version "1.0.0"
55 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.0.tgz#5bd046e508b1ee90bc091766758838741fdefd6e"
56 | integrity sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==
57 |
58 | "@tsconfig/node16@^1.0.2":
59 | version "1.0.2"
60 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
61 | integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
62 |
63 | "@types/js-yaml@^4.0.5":
64 | version "4.0.5"
65 | resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138"
66 | integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==
67 |
68 | "@types/luxon@^2.0.8":
69 | version "2.0.8"
70 | resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.8.tgz#a0fdd7ab0b67e08bf1d301232a7fef79b74ded69"
71 | integrity sha512-lGmxL6hMEVqXr8w9bL52RUWXVu90o7vH8WQSutQssr2e+w0TNttXx2Zfw2V2lHHHWfW6OGqB8bXDvtKocv19qQ==
72 |
73 | "@types/node@^14.14.27":
74 | version "14.14.27"
75 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.27.tgz#c7127f8da0498993e13b1a42faf1303d3110d2f2"
76 | integrity sha512-Ecfmo4YDQPwuqTCl1yBxLV5ihKfRlkBmzUEDcfIRvDxOTGQEeikr317Ln7Gcv0tjA8dVgKI3rniqW2G1OyKDng==
77 |
78 | acorn-walk@^8.1.1:
79 | version "8.2.0"
80 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
81 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
82 |
83 | acorn@^8.4.1:
84 | version "8.5.0"
85 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
86 | integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
87 |
88 | ajv@^8.8.2:
89 | version "8.8.2"
90 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb"
91 | integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==
92 | dependencies:
93 | fast-deep-equal "^3.1.1"
94 | json-schema-traverse "^1.0.0"
95 | require-from-string "^2.0.2"
96 | uri-js "^4.2.2"
97 |
98 | ansi-styles@^3.2.1:
99 | version "3.2.1"
100 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
101 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
102 | dependencies:
103 | color-convert "^1.9.0"
104 |
105 | ansi-styles@^4.1.0:
106 | version "4.3.0"
107 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
108 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
109 | dependencies:
110 | color-convert "^2.0.1"
111 |
112 | arg@^4.1.0:
113 | version "4.1.3"
114 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
115 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
116 |
117 | argparse@^2.0.1:
118 | version "2.0.1"
119 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
120 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
121 |
122 | asn1-ber@*:
123 | version "1.1.0"
124 | resolved "https://registry.yarnpkg.com/asn1-ber/-/asn1-ber-1.1.0.tgz#b69f91578c08afa65511124908a7a82f62c6571c"
125 | integrity sha512-t/pm9zz3CC7jE2ItzMPi4rYUXp4d3JkLAUQY8E/5u5Lkaq7KMvMalRWrW9WWARm5gOB/HE/mkorImJwSL7fi9w==
126 |
127 | async-mqtt@^2.6.1:
128 | version "2.6.1"
129 | resolved "https://registry.yarnpkg.com/async-mqtt/-/async-mqtt-2.6.1.tgz#7cca37b0c766e00d7b0b33c9eb236e216ed06248"
130 | integrity sha512-EkXAwRzwMaPC6ji0EvNeM5OMe6VjMhEKVJJUN7gu/hGzkcDpZtaI34nUwdwCMbjQB3pnuSOHqQMFKsUpg+D8kA==
131 | dependencies:
132 | mqtt "^4.1.0"
133 |
134 | balanced-match@^1.0.0:
135 | version "1.0.0"
136 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
137 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
138 |
139 | base64-js@^1.3.1:
140 | version "1.5.1"
141 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
142 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
143 |
144 | better-ajv-errors@^1.1.2:
145 | version "1.1.2"
146 | resolved "https://registry.yarnpkg.com/better-ajv-errors/-/better-ajv-errors-1.1.2.tgz#6accafad01e1ae93121cf915c8c99377f609c010"
147 | integrity sha512-xpFTC7JqkSGkvchJlH4IFtmwZ5SXomh0FqbEVEHRcXl/aiHh9nM/dnNnGTlxjrFCjWOVLLWpcNW1Hcrzs55/lg==
148 | dependencies:
149 | "@babel/code-frame" "^7.16.0"
150 | "@humanwhocodes/momoa" "^2.0.2"
151 | chalk "^4.1.2"
152 | jsonpointer "^5.0.0"
153 | leven "^3.1.0 < 4"
154 |
155 | bigint-buffer@^1.1.5:
156 | version "1.1.5"
157 | resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442"
158 | integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==
159 | dependencies:
160 | bindings "^1.3.0"
161 |
162 | bindings@^1.3.0:
163 | version "1.5.0"
164 | resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
165 | integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
166 | dependencies:
167 | file-uri-to-path "1.0.0"
168 |
169 | bl@^4.0.2:
170 | version "4.1.0"
171 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
172 | integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
173 | dependencies:
174 | buffer "^5.5.0"
175 | inherits "^2.0.4"
176 | readable-stream "^3.4.0"
177 |
178 | brace-expansion@^1.1.7:
179 | version "1.1.11"
180 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
181 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
182 | dependencies:
183 | balanced-match "^1.0.0"
184 | concat-map "0.0.1"
185 |
186 | buffer-from@^1.0.0:
187 | version "1.1.1"
188 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
189 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
190 |
191 | buffer@^5.5.0:
192 | version "5.7.1"
193 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
194 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
195 | dependencies:
196 | base64-js "^1.3.1"
197 | ieee754 "^1.1.13"
198 |
199 | callback-stream@^1.0.2:
200 | version "1.1.0"
201 | resolved "https://registry.yarnpkg.com/callback-stream/-/callback-stream-1.1.0.tgz#4701a51266f06e06eaa71fc17233822d875f4908"
202 | integrity sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=
203 | dependencies:
204 | inherits "^2.0.1"
205 | readable-stream "> 1.0.0 < 3.0.0"
206 |
207 | chalk@^2.0.0:
208 | version "2.4.2"
209 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
210 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
211 | dependencies:
212 | ansi-styles "^3.2.1"
213 | escape-string-regexp "^1.0.5"
214 | supports-color "^5.3.0"
215 |
216 | chalk@^4.1.2:
217 | version "4.1.2"
218 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
219 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
220 | dependencies:
221 | ansi-styles "^4.1.0"
222 | supports-color "^7.1.0"
223 |
224 | color-convert@^1.9.0:
225 | version "1.9.3"
226 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
227 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
228 | dependencies:
229 | color-name "1.1.3"
230 |
231 | color-convert@^2.0.1:
232 | version "2.0.1"
233 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
234 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
235 | dependencies:
236 | color-name "~1.1.4"
237 |
238 | color-name@1.1.3:
239 | version "1.1.3"
240 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
241 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
242 |
243 | color-name@~1.1.4:
244 | version "1.1.4"
245 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
246 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
247 |
248 | commist@^1.0.0:
249 | version "1.1.0"
250 | resolved "https://registry.yarnpkg.com/commist/-/commist-1.1.0.tgz#17811ec6978f6c15ee4de80c45c9beb77cee35d5"
251 | integrity sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==
252 | dependencies:
253 | leven "^2.1.0"
254 | minimist "^1.1.0"
255 |
256 | concat-map@0.0.1:
257 | version "0.0.1"
258 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
259 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
260 |
261 | concat-stream@^2.0.0:
262 | version "2.0.0"
263 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
264 | integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
265 | dependencies:
266 | buffer-from "^1.0.0"
267 | inherits "^2.0.3"
268 | readable-stream "^3.0.2"
269 | typedarray "^0.0.6"
270 |
271 | core-util-is@~1.0.0:
272 | version "1.0.2"
273 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
274 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
275 |
276 | create-require@^1.1.0:
277 | version "1.1.1"
278 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
279 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
280 |
281 | debug@^4.1.1:
282 | version "4.3.1"
283 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
284 | integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
285 | dependencies:
286 | ms "2.1.2"
287 |
288 | diff@^4.0.1:
289 | version "4.0.2"
290 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
291 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
292 |
293 | duplexify@^3.6.0:
294 | version "3.7.1"
295 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
296 | integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
297 | dependencies:
298 | end-of-stream "^1.0.0"
299 | inherits "^2.0.1"
300 | readable-stream "^2.0.0"
301 | stream-shift "^1.0.0"
302 |
303 | end-of-stream@^1.0.0, end-of-stream@^1.1.0:
304 | version "1.4.4"
305 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
306 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
307 | dependencies:
308 | once "^1.4.0"
309 |
310 | escape-string-regexp@^1.0.5:
311 | version "1.0.5"
312 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
313 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
314 |
315 | extend@^3.0.0:
316 | version "3.0.2"
317 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
318 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
319 |
320 | fast-deep-equal@^3.1.1:
321 | version "3.1.3"
322 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
323 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
324 |
325 | file-uri-to-path@1.0.0:
326 | version "1.0.0"
327 | resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
328 | integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
329 |
330 | fs.realpath@^1.0.0:
331 | version "1.0.0"
332 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
333 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
334 |
335 | glob-parent@^3.1.0:
336 | version "3.1.0"
337 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
338 | integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
339 | dependencies:
340 | is-glob "^3.1.0"
341 | path-dirname "^1.0.0"
342 |
343 | glob-stream@^6.1.0:
344 | version "6.1.0"
345 | resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
346 | integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=
347 | dependencies:
348 | extend "^3.0.0"
349 | glob "^7.1.1"
350 | glob-parent "^3.1.0"
351 | is-negated-glob "^1.0.0"
352 | ordered-read-streams "^1.0.0"
353 | pumpify "^1.3.5"
354 | readable-stream "^2.1.5"
355 | remove-trailing-separator "^1.0.1"
356 | to-absolute-glob "^2.0.0"
357 | unique-stream "^2.0.2"
358 |
359 | glob@^7.1.1:
360 | version "7.1.6"
361 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
362 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
363 | dependencies:
364 | fs.realpath "^1.0.0"
365 | inflight "^1.0.4"
366 | inherits "2"
367 | minimatch "^3.0.4"
368 | once "^1.3.0"
369 | path-is-absolute "^1.0.0"
370 |
371 | has-flag@^3.0.0:
372 | version "3.0.0"
373 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
374 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
375 |
376 | has-flag@^4.0.0:
377 | version "4.0.0"
378 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
379 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
380 |
381 | help-me@^1.0.1:
382 | version "1.1.0"
383 | resolved "https://registry.yarnpkg.com/help-me/-/help-me-1.1.0.tgz#8f2d508d0600b4a456da2f086556e7e5c056a3c6"
384 | integrity sha1-jy1QjQYAtKRW2i8IZVbn5cBWo8Y=
385 | dependencies:
386 | callback-stream "^1.0.2"
387 | glob-stream "^6.1.0"
388 | through2 "^2.0.1"
389 | xtend "^4.0.0"
390 |
391 | ieee754@^1.1.13:
392 | version "1.2.1"
393 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
394 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
395 |
396 | inflight@^1.0.4:
397 | version "1.0.6"
398 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
399 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
400 | dependencies:
401 | once "^1.3.0"
402 | wrappy "1"
403 |
404 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
405 | version "2.0.4"
406 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
407 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
408 |
409 | is-absolute@^1.0.0:
410 | version "1.0.0"
411 | resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
412 | integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
413 | dependencies:
414 | is-relative "^1.0.0"
415 | is-windows "^1.0.1"
416 |
417 | is-extglob@^2.1.0:
418 | version "2.1.1"
419 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
420 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
421 |
422 | is-glob@^3.1.0:
423 | version "3.1.0"
424 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
425 | integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
426 | dependencies:
427 | is-extglob "^2.1.0"
428 |
429 | is-negated-glob@^1.0.0:
430 | version "1.0.0"
431 | resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
432 | integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=
433 |
434 | is-relative@^1.0.0:
435 | version "1.0.0"
436 | resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
437 | integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
438 | dependencies:
439 | is-unc-path "^1.0.0"
440 |
441 | is-unc-path@^1.0.0:
442 | version "1.0.0"
443 | resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
444 | integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
445 | dependencies:
446 | unc-path-regex "^0.1.2"
447 |
448 | is-windows@^1.0.1:
449 | version "1.0.2"
450 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
451 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
452 |
453 | isarray@~1.0.0:
454 | version "1.0.0"
455 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
456 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
457 |
458 | js-tokens@^4.0.0:
459 | version "4.0.0"
460 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
461 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
462 |
463 | js-yaml@^4.1.0:
464 | version "4.1.0"
465 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
466 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
467 | dependencies:
468 | argparse "^2.0.1"
469 |
470 | json-schema-traverse@^1.0.0:
471 | version "1.0.0"
472 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
473 | integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
474 |
475 | json-stable-stringify-without-jsonify@^1.0.1:
476 | version "1.0.1"
477 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
478 | integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
479 |
480 | jsonpointer@^5.0.0:
481 | version "5.0.0"
482 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.0.tgz#f802669a524ec4805fa7389eadbc9921d5dc8072"
483 | integrity sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==
484 |
485 | leven@^2.1.0:
486 | version "2.1.0"
487 | resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
488 | integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA=
489 |
490 | "leven@^3.1.0 < 4":
491 | version "3.1.0"
492 | resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
493 | integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
494 |
495 | luxon@^2.3.0:
496 | version "2.3.0"
497 | resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.3.0.tgz#bf16a7e642513c2a20a6230a6a41b0ab446d0045"
498 | integrity sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg==
499 |
500 | make-error@^1.1.1:
501 | version "1.3.6"
502 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
503 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
504 |
505 | minimatch@^3.0.4:
506 | version "3.0.4"
507 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
508 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
509 | dependencies:
510 | brace-expansion "^1.1.7"
511 |
512 | minimist@^1.1.0, minimist@^1.2.5:
513 | version "1.2.5"
514 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
515 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
516 |
517 | mqtt-packet@^6.6.0:
518 | version "6.7.0"
519 | resolved "https://registry.yarnpkg.com/mqtt-packet/-/mqtt-packet-6.7.0.tgz#0098f7f5d02f34b8dce35507befd6394e1109575"
520 | integrity sha512-GzgeeCirQpB59FyhHvf8BLiIYgxctPSxuSyaF2vWnkt7paX7jtuQ8Gpl+DkHCxZmYuv7GQE6zcUAegpafd0MqQ==
521 | dependencies:
522 | bl "^4.0.2"
523 | debug "^4.1.1"
524 | process-nextick-args "^2.0.1"
525 |
526 | mqtt@^4.1.0:
527 | version "4.2.6"
528 | resolved "https://registry.yarnpkg.com/mqtt/-/mqtt-4.2.6.tgz#b655547a9cfb3d86bfb398948b8dbb37e2e3bfd0"
529 | integrity sha512-GpxVObyOzL0CGPBqo6B04GinN8JLk12NRYAIkYvARd9ZCoJKevvOyCaWK6bdK/kFSDj3LPDnCsJbezzNlsi87Q==
530 | dependencies:
531 | commist "^1.0.0"
532 | concat-stream "^2.0.0"
533 | debug "^4.1.1"
534 | help-me "^1.0.1"
535 | inherits "^2.0.3"
536 | minimist "^1.2.5"
537 | mqtt-packet "^6.6.0"
538 | pump "^3.0.0"
539 | readable-stream "^3.6.0"
540 | reinterval "^1.1.0"
541 | split2 "^3.1.0"
542 | ws "^7.3.1"
543 | xtend "^4.0.2"
544 |
545 | ms@2.1.2:
546 | version "2.1.2"
547 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
548 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
549 |
550 | net-snmp@^3.5.8:
551 | version "3.5.8"
552 | resolved "https://registry.yarnpkg.com/net-snmp/-/net-snmp-3.5.8.tgz#90fd37b2ef28bf30a96fc176540bec0fe2172d5e"
553 | integrity sha512-SPMn8jE9QXD9QUMOzEeEEXAYZtRIX3zUyPDewZmRRZ0Qgx9t42H90VQG165tG32/MglU8gCoRWoBsGapyN75Jg==
554 | dependencies:
555 | asn1-ber "*"
556 | smart-buffer "^4.1.0"
557 |
558 | once@^1.3.0, once@^1.3.1, once@^1.4.0:
559 | version "1.4.0"
560 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
561 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
562 | dependencies:
563 | wrappy "1"
564 |
565 | ordered-read-streams@^1.0.0:
566 | version "1.0.1"
567 | resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
568 | integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=
569 | dependencies:
570 | readable-stream "^2.0.1"
571 |
572 | path-dirname@^1.0.0:
573 | version "1.0.2"
574 | resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
575 | integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
576 |
577 | path-is-absolute@^1.0.0:
578 | version "1.0.1"
579 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
580 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
581 |
582 | prettier@^2.5.1:
583 | version "2.5.1"
584 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
585 | integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
586 |
587 | process-nextick-args@^2.0.1, process-nextick-args@~2.0.0:
588 | version "2.0.1"
589 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
590 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
591 |
592 | pump@^2.0.0:
593 | version "2.0.1"
594 | resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
595 | integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
596 | dependencies:
597 | end-of-stream "^1.1.0"
598 | once "^1.3.1"
599 |
600 | pump@^3.0.0:
601 | version "3.0.0"
602 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
603 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
604 | dependencies:
605 | end-of-stream "^1.1.0"
606 | once "^1.3.1"
607 |
608 | pumpify@^1.3.5:
609 | version "1.5.1"
610 | resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
611 | integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
612 | dependencies:
613 | duplexify "^3.6.0"
614 | inherits "^2.0.3"
615 | pump "^2.0.0"
616 |
617 | punycode@^2.1.0:
618 | version "2.1.1"
619 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
620 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
621 |
622 | "readable-stream@> 1.0.0 < 3.0.0", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.1.5, readable-stream@~2.3.6:
623 | version "2.3.7"
624 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
625 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
626 | dependencies:
627 | core-util-is "~1.0.0"
628 | inherits "~2.0.3"
629 | isarray "~1.0.0"
630 | process-nextick-args "~2.0.0"
631 | safe-buffer "~5.1.1"
632 | string_decoder "~1.1.1"
633 | util-deprecate "~1.0.1"
634 |
635 | readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.4.0, readable-stream@^3.6.0:
636 | version "3.6.0"
637 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
638 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
639 | dependencies:
640 | inherits "^2.0.3"
641 | string_decoder "^1.1.1"
642 | util-deprecate "^1.0.1"
643 |
644 | reinterval@^1.1.0:
645 | version "1.1.0"
646 | resolved "https://registry.yarnpkg.com/reinterval/-/reinterval-1.1.0.tgz#3361ecfa3ca6c18283380dd0bb9546f390f5ece7"
647 | integrity sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=
648 |
649 | remove-trailing-separator@^1.0.1:
650 | version "1.1.0"
651 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
652 | integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
653 |
654 | require-from-string@^2.0.2:
655 | version "2.0.2"
656 | resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
657 | integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
658 |
659 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
660 | version "5.1.2"
661 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
662 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
663 |
664 | safe-buffer@~5.2.0:
665 | version "5.2.1"
666 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
667 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
668 |
669 | slugify@^1.6.5:
670 | version "1.6.5"
671 | resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.5.tgz#c8f5c072bf2135b80703589b39a3d41451fbe8c8"
672 | integrity sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==
673 |
674 | smart-buffer@^4.1.0:
675 | version "4.1.0"
676 | resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba"
677 | integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==
678 |
679 | split2@^3.1.0:
680 | version "3.2.2"
681 | resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f"
682 | integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
683 | dependencies:
684 | readable-stream "^3.0.0"
685 |
686 | stream-shift@^1.0.0:
687 | version "1.0.1"
688 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
689 | integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
690 |
691 | string_decoder@^1.1.1:
692 | version "1.3.0"
693 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
694 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
695 | dependencies:
696 | safe-buffer "~5.2.0"
697 |
698 | string_decoder@~1.1.1:
699 | version "1.1.1"
700 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
701 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
702 | dependencies:
703 | safe-buffer "~5.1.0"
704 |
705 | supports-color@^5.3.0:
706 | version "5.5.0"
707 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
708 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
709 | dependencies:
710 | has-flag "^3.0.0"
711 |
712 | supports-color@^7.1.0:
713 | version "7.2.0"
714 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
715 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
716 | dependencies:
717 | has-flag "^4.0.0"
718 |
719 | through2-filter@^3.0.0:
720 | version "3.0.0"
721 | resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
722 | integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
723 | dependencies:
724 | through2 "~2.0.0"
725 | xtend "~4.0.0"
726 |
727 | through2@^2.0.1, through2@~2.0.0:
728 | version "2.0.5"
729 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
730 | integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
731 | dependencies:
732 | readable-stream "~2.3.6"
733 | xtend "~4.0.1"
734 |
735 | to-absolute-glob@^2.0.0:
736 | version "2.0.2"
737 | resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
738 | integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=
739 | dependencies:
740 | is-absolute "^1.0.0"
741 | is-negated-glob "^1.0.0"
742 |
743 | ts-node@^10.4.0:
744 | version "10.4.0"
745 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7"
746 | integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==
747 | dependencies:
748 | "@cspotcode/source-map-support" "0.7.0"
749 | "@tsconfig/node10" "^1.0.7"
750 | "@tsconfig/node12" "^1.0.7"
751 | "@tsconfig/node14" "^1.0.0"
752 | "@tsconfig/node16" "^1.0.2"
753 | acorn "^8.4.1"
754 | acorn-walk "^8.1.1"
755 | arg "^4.1.0"
756 | create-require "^1.1.0"
757 | diff "^4.0.1"
758 | make-error "^1.1.1"
759 | yn "3.1.1"
760 |
761 | typedarray@^0.0.6:
762 | version "0.0.6"
763 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
764 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
765 |
766 | typescript@^4.5.4:
767 | version "4.5.4"
768 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
769 | integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
770 |
771 | unc-path-regex@^0.1.2:
772 | version "0.1.2"
773 | resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
774 | integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
775 |
776 | unique-stream@^2.0.2:
777 | version "2.3.1"
778 | resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
779 | integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
780 | dependencies:
781 | json-stable-stringify-without-jsonify "^1.0.1"
782 | through2-filter "^3.0.0"
783 |
784 | uri-js@^4.2.2:
785 | version "4.4.1"
786 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
787 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
788 | dependencies:
789 | punycode "^2.1.0"
790 |
791 | util-deprecate@^1.0.1, util-deprecate@~1.0.1:
792 | version "1.0.2"
793 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
794 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
795 |
796 | wrappy@1:
797 | version "1.0.2"
798 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
799 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
800 |
801 | ws@^7.3.1:
802 | version "7.4.3"
803 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.3.tgz#1f9643de34a543b8edb124bdcbc457ae55a6e5cd"
804 | integrity sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==
805 |
806 | xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
807 | version "4.0.2"
808 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
809 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
810 |
811 | yn@3.1.1:
812 | version "3.1.1"
813 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
814 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
815 |
--------------------------------------------------------------------------------