diff --git a/.github/workflows/docker-nightly.yml b/.github/workflows/docker-nightly.yml new file mode 100644 index 0000000..a4be7b7 --- /dev/null +++ b/.github/workflows/docker-nightly.yml @@ -0,0 +1,45 @@ +name: Publish Docker nightly image + +on: + pull_request: + types: + - closed + branches: + - dev + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + if: github.repository == 'OpenHausIO/backend' && github.event.pull_request.merged == true + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Use Node.js 18.x + uses: actions/setup-node@v4 + with: + node-version: 18.x + - run: npm ci + - run: npm run build + + - name: Log in to Docker Hub + uses: docker/login-action@v3.0.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5.5.0 + with: + images: openhaus/backend + + - name: Build and push Docker image + uses: docker/build-push-action@v5.1.0 + with: + context: . + file: ./Dockerfile + push: true + tags: openhaus/backend:nightly + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/node-js.yml b/.github/workflows/node-js.yml index 75a0112..73183a7 100644 --- a/.github/workflows/node-js.yml +++ b/.github/workflows/node-js.yml @@ -27,11 +27,11 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node-version: [16.x, 17.x, 18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + node-version: [16.x, 18.x, 20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ mongodb-version: ["4.2", "4.4", "5.0"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # mongodb setup - name: Start MongoDB @@ -41,7 +41,7 @@ jobs: # node.js setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..251a23e --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npm run lint \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2143f07..b360ac9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # https://medium.com/@kahana.hagai/docker-compose-with-node-js-and-mongodb-dbdadab5ce0a # The instructions for the first stage -FROM node:16-alpine as builder +FROM node:20-alpine as builder ARG NODE_ENV=production ENV NODE_ENV=${NODE_ENV} @@ -22,7 +22,7 @@ RUN npm install # The instructions for second stage -FROM node:16-alpine +FROM node:20-alpine WORKDIR /opt/OpenHaus/backend COPY --from=builder node_modules node_modules diff --git a/Gruntfile.js b/Gruntfile.js index 734f958..ee0c707 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,7 +24,8 @@ module.exports = function (grunt) { options: { mangle: { toplevel: true - } + }, + //banner: fs.readFileSync(path.join(process.cwd(), "docs/banner.txt"), "utf8") }, build: { files: [{ @@ -99,10 +100,18 @@ module.exports = function (grunt) { stdio: "inherit" }); + // remove build, use taggin. see: #451 + /* cp.execSync(`docker build . -t openhaus/${pkg.name}:latest ${buildArgs}`, { env: process.env, stdio: "inherit" }); + */ + + cp.execSync(`docker image tag openhaus/${pkg.name}:${pkg.version} openhaus/${pkg.name}:latest`, { + env: process.env, + stdio: "inherit" + }); }); diff --git a/ISSUES.md b/ISSUES.md new file mode 100644 index 0000000..c701352 --- /dev/null +++ b/ISSUES.md @@ -0,0 +1,38 @@ +```systemd +[Unit] +Description=firewalld - dynamic firewall daemon +Before=network-pre.target +Wants=network-pre.target +After=dbus.service +After=polkit.service +Conflicts=iptables.service ip6tables.service ebtables.service ipset.service nftables.service +Documentation=man:firewalld(1) + +[Service] +EnvironmentFile=-/etc/sysconfig/firewalld +ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS +ExecReload=/bin/kill -HUP $MAINPID +# supress to log debug and error output also to /var/log/messages +StandardOutput=null +StandardError=null +Type=dbus +BusName=org.fedoraproject.FirewallD1 +KillMode=mixed + +[Install] +WantedBy=multi-user.target +Alias=dbus-org.fedoraproject.FirewallD1.service +``` + +https://systemd-devel.freedesktop.narkive.com/dpY7US7K/a-little-help-with-mainpid-please + + +OpenHaus relevant/verbesserung?! + + +---------------- + +Use husky for git hooks? + +https://www.npmjs.com/package/husky +https://typicode.github.io/husky/ \ No newline at end of file diff --git a/adapter/eol.js b/adapter/eol.js index e30cc5b..28c7d4f 100644 --- a/adapter/eol.js +++ b/adapter/eol.js @@ -8,7 +8,7 @@ module.exports = (options = {}) => { // https://github.com/OpenHausIO/backend/issues/315 let cr = Buffer.from("\r"); let lf = Buffer.from("\n"); - //let eol = Buffer.from("\x1A"); + //let eof = Buffer.from("\x1A"); let nl = Buffer.concat([ cr, lf @@ -25,6 +25,7 @@ module.exports = (options = {}) => { let decode = new Transform({ transform(chunk, encoding, cb) { log.trace("[encode] (%s) %j", encoding, chunk); + // NOTE (mstirner) is this right? cb(null, chunk.subarray(0, nl.length)); }, ...options diff --git a/backend.service b/backend.service index 6d163d2..4024039 100644 --- a/backend.service +++ b/backend.service @@ -1,17 +1,20 @@ [Unit] Description=OpenHaus Backend +Documentation=https://docs.open-haus.io Wants=network-online.target After=network-online.target [Service] ExecStart=/usr/bin/node /opt/OpenHaus/backend/index.js WorkingDirectory=/opt/OpenHaus/backend -Restart=always +EnvironmentFile=/opt/OpenHaus/backend/.env +Restart=on-failure RestartSec=10 -Environment=NODE_ENV=production -Environment=VAULT_MASTER_PASSWORD=Pa$$w0rd -Environment=USERS_JWT_SECRET=Pa$$w0rd -Environment=UUID=00000000-0000-0000-0000-000000000000 +Type=simple +#Environment=NODE_ENV=production +#Environment=VAULT_MASTER_PASSWORD=Pa$$w0rd +#Environment=USERS_JWT_SECRET=Pa$$w0rd +#Environment=UUID=00000000-0000-0000-0000-000000000000 [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/components/devices/class.device.js b/components/devices/class.device.js index 6225fac..3cf52d1 100644 --- a/components/devices/class.device.js +++ b/components/devices/class.device.js @@ -1,7 +1,14 @@ +const Joi = require("joi"); +const mongodb = require("mongodb"); + const InterfaceStream = require("./class.interfaceStream.js"); const Interface = require("./class.interface.js"); +const Item = require("../../system/component/class.item.js"); const mixins = require("../../helper/mixins.js"); +const injectMethod = require("../../helper/injectMethod.js"); + +//const { parse, calculateChecksum } = require("./net-helper.js"); /** * @description @@ -20,17 +27,25 @@ const mixins = require("../../helper/mixins.js"); * @see interface components/devices/class.interface.js * @see interfaceStream components/devices/class.interfaceStream.js */ -module.exports = class Device { - constructor(props) { +module.exports = class Device extends Item { + constructor(props, scope) { + super(props); + + // removed for #356 // set properties from db - Object.assign(this, props); - this._id = String(props._id); + //Object.assign(this, props); + //this._id = String(props._id); // create for each interface a interface class instance // for each interface class, create a interface stream this.interfaces = props.interfaces.map((obj) => { + + // NOTE: refactor interfaceStream in v4 + // move .bridge method there and pass device instance? + // > Would this also create a ciruclar reference in Interface class + // > since its stored via `Object.defineProperty(this, "stream",...);` let stream = new InterfaceStream({ // duplex stream options emitClose: false @@ -43,6 +58,21 @@ module.exports = class Device { let iface = new Interface(obj, stream); + // inject bridge method into interface instance + // passing deivce instance into Interface class, creates a ciruclar reference + // TODO: Move this into "interfaceStream" (needs to be refactored) + // NOTE: remove "device" for bridging requests (only needed in connector)? + // > See: https://github.com/OpenHausIO/connector/issues/54 + // > When done, "device" property can be removed, and the `.bridge()` method can be moved into Interface class + injectMethod(iface, "bridge", (cb) => { + return Interface._bridge({ + events: scope.events, + interface: iface, + device: this._id + }, cb); + }); + + // "hide" stream behind iface object // so we can use the interface object // as duplex stream @@ -61,4 +91,29 @@ module.exports = class Device { }); } + + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + room: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).allow(null).default(null), + enabled: Joi.boolean().default(true), + //interfaces: Joi.array().items(Interface.schema()).min(1).required() + interfaces: Joi.array().items(Interface.schema()).default([]), + meta: { + manufacturer: Joi.string().allow(null).default(null), + model: Joi.string().allow(null).default(null), + revision: Joi.number().allow(null).default(null), + serial: Joi.string().allow(null).default(null) + }, + icon: Joi.string().allow(null).default(null) + }); + } + + static validate(data) { + return Device.schema().validate(data); + } + }; \ No newline at end of file diff --git a/components/devices/class.interface.js b/components/devices/class.interface.js index bc5dbb3..f95a6a8 100644 --- a/components/devices/class.interface.js +++ b/components/devices/class.interface.js @@ -1,7 +1,16 @@ const Joi = require("joi"); const { Agent } = require("http"); const mongodb = require("mongodb"); -const { PassThrough, Duplex } = require("stream"); +const { Transform, Duplex } = require("stream"); +const { randomUUID } = require("crypto"); +//const path = require("path"); + +//const Adapter = require("./class.adapter.js"); + + +const timeout = require("../../helper/timeout.js"); +const promisfy = require("../../helper/promisify.js"); + /** * @description @@ -39,6 +48,14 @@ module.exports = class Interface { let { interfaceStreams } = require("../../system/shared.js"); interfaceStreams.set(this._id, stream); + // hot fix for #350 + Object.defineProperty(this, "cachedAgent", { + value: null, + enumerable: false, + configurable: false, + writable: true + }); + } /** @@ -104,6 +121,8 @@ module.exports = class Interface { * * @link https://nodejs.org/dist/latest-v16.x/docs/api/http.html#new-agentoptions */ + /* + // *OLD* function, see #329 httpAgent(options) { options = Object.assign({ @@ -134,6 +153,15 @@ module.exports = class Interface { writable: output }); + // when multiple reuqests are done parallal, sometimes a AbortedErr is thrown + // see #329 for details + // TODO: Check if the upstream is drained, and perform requests in series + // As "quick fix" till a solution is found for #312 catch the trown error + socket.on("error", (err) => { + console.log("Catched error on http.agent.createConnection", err); + this.stream.destroy(); + }); + /* [socket, this.stream, input, output].forEach((stream) => { let cleanup = finished(stream, (err) => { @@ -160,7 +188,7 @@ module.exports = class Interface { }); }); - */ + * // TODO implement other socket functions?! @@ -182,6 +210,246 @@ module.exports = class Interface { return agent; } + */ + + + // NEW VERSION, fix for #329 + httpAgent(options = {}) { + + if (this.cachedAgent) { + return this.cachedAgent; + } + + let agent = new Agent({ + keepAlive: true, + maxSockets: 1, + ...options + }); + + //let settings = this.settings; + + /* + // added for testing a solution for #411 + // does nothing/not work, but feels like can be useful in the future + // see: + // - https://nodejs.org/docs/latest/api/http.html#agentkeepsocketalivesocket + // - https://nodejs.org/docs/latest/api/http.html#agentkeepsocketalivesocket + agent.keepSocketAlive = (socket) => { + console.log("agent.keepSocketAlive called"); + return true; + }; + + agent.reuseSocket = (socket, request) => { + console.log("agent.reuseSocket called"); + }; + */ + + agent.createConnection = ({ headers = {} }) => { + + //console.log(`############## Create connection to tcp://${host}:${port}`); + + // cleanup, could be possible be piped from previous "connections" + this.stream.unpipe(); + + /* + // check if passed host/port matches interface settings? + if (host != settings.host || port != settings.port) { + + let msg = "host/port for interface missmatch, expected:\r\n"; + msg += `\thost = ${host}; got = ${settings.host}\r\n`; + msg += `\tport = ${settings.port}; got = ${settings.port}`; + + throw new Error(msg); + + } + */ + + //let readable = new PassThrough(); + //let writable = new PassThrough(); + + // convert headers key/values to lowercase + // the string conversion prevents a error thrown for numbers + // this happens for websocket requests, where e.g. "sec-websocket-version=13" + // see snipp below "detect websocket connection with set headers" + headers = Object.keys(headers).reduce((obj, key) => { + obj[key.toLowerCase()] = `${headers[key]}`.toLowerCase(); + return obj; + }, {}); + + + let readable = new Transform({ + transform(chunk, enc, cb) { + + //console.log("[incoming]", chunk); + + // temp fix for #343 + // this is not the prefered fix for this issue + // it should be handled on "stream/socket" level instead + // the issue above occoured with a "shelly 1pm" and parallel requests to /status /ota /settings + // NOTE: what if the body contains json that has a `connection: close` property/key/value? + + // detect websocket connection with set headers, fix #411 + // agent.protocol is never "ws" regardless of the url used in requests + // temp solution, more like a hotfix than a final solution + if (agent.protocol === "http:" && !(headers?.upgrade === "websocket" && headers?.connection === "upgrade")) { + chunk = chunk.toString().replace(/connection:\s?close\r\n/i, "connection: keep-alive\r\n"); + } + + this.push(chunk); + cb(); + + } + }); + + let writable = new Transform({ + transform(chunk, enc, cb) { + + //console.log("[outgoing]", chunk); + + this.push(chunk); + cb(); + + } + }); + + + // TODO Implement "auto-drain" when no upstream is attached -> Move this "lower", e.g. before ws upstream? + /* + let writable = new Transform({ + transform(chunk, enc, cb) { + + debugger; + + //console.log("this.stream",); + console.error(">>>> Write data, flowing?", str.upstream ? true : false, settings.host); + + if (str.upstream) { + this.push(chunk); + } else { + while (this.read() !== null) { + // do nothing with writen input data + // empty readable queue + } + } + + cb(); + + } + }); + */ + + + let stream = new Duplex.from({ + readable, + writable + }); + + stream.destroy = () => { + //console.log("socket.destroy();", args); + }; + + stream.ref = () => { + //console.log("socket.unref();", args); + }; + + stream.unref = () => { + //console.log("socket.unref();", args); + }; + + stream.setKeepAlive = () => { + //console.log("socket.setKeepAlive()", args); + }; + + stream.setTimeout = () => { + //console.log("socket.setTimeout();", args); + }; + + stream.setNoDelay = () => { + //console.log("socket.setNotDelay();", args); + }; + + this.stream.pipe(readable, { end: false }); + writable.pipe(this.stream, { end: false }); + + return stream; + + }; + + this.cachedAgent = agent; + return agent; + + } + + + // bridge methods connects adapter with the underlaying network socket + // create a `.socket()` method that returns the palin websocket stream + static _bridge({ device, interface: iface, events }, cb) { + return promisfy((done) => { + + console.log("Bridge request, iface", iface, device); + + // create a random uuid + // used as identifier for responses + let uuid = randomUUID(); + //let uuid = "4c6de542-f89f-42ac-a2b5-1c26f9e68d73"; + + + // timeout after certain time + // no connector available, not mocks or whatever reaseon + let caller = timeout(5000, (timedout, duration, args) => { + if (timedout) { + done(new Error("TIMEDOUT")); + } else { + done(null, args[0]); + } + }); + + + // socket response handler + // listen for uuid and compare it with generated + let handler = ({ stream, type, uuid: id, socket }) => { + if (uuid === id && type === "response" && socket) { + + console.log("adapter", iface.adapter); + + /* + // create adapter stack here + // pass adapter stack as caller argument + //caller(stack); + let stack = iface.adapter.map((name) => { + try { + return require(path.join(process.cwd(), "adapter", `${name}.js`))(); + } catch (err) { + console.error(`Error in adapter "${name}" `, err); + } + }); + + console.log("stack", stack); + + stream = new Adapter(stack, stream, { + emitClose: false, + end: false + }); + + console.log("stream", stream) + */ + + caller(stream); + + } + }; + + events.on("socket", handler); + + events.emit("socket", { + uuid, + device, + interface: iface._id, + type: "request" + }); + + }, cb); + } }; \ No newline at end of file diff --git a/components/devices/index.js b/components/devices/index.js index f6da0b8..0bae134 100644 --- a/components/devices/index.js +++ b/components/devices/index.js @@ -1,5 +1,4 @@ const mongodb = require("mongodb"); -const Joi = require("joi"); // for development its usefull if we detect @@ -17,7 +16,6 @@ const COMPONENT = require("../../system/component/class.component.js"); //require("./class.interface.js"); //require("./class.interfaceStream"); -const Interface = require("./class.interface.js"); const Device = require("./class.device.js"); /** @@ -144,23 +142,7 @@ class C_DEVICES extends COMPONENT { // inject logger, collection and schema object // https://stackoverflow.com/a/37746388/5781499 - super("devices", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - room: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).allow(null).default(null), - enabled: Joi.boolean().default(true), - //interfaces: Joi.array().items(Interface.schema()).min(1).required() - interfaces: Joi.array().min(1).items(Interface.schema()).required(), - meta: { - manufacturer: Joi.string().allow(null).default(null), - model: Joi.string().allow(null).default(null), - revision: Joi.number().allow(null).default(null), - serial: Joi.string().allow(null).default(null) - }, - icon: Joi.string().allow(null).default(null) - }, module); + super("devices", Device.schema(), module); // create for new added device interfaces diff --git a/components/endpoints/class.command.js b/components/endpoints/class.command.js index 3dfa1de..d68010f 100644 --- a/components/endpoints/class.command.js +++ b/components/endpoints/class.command.js @@ -4,6 +4,8 @@ const mongodb = require("mongodb"); const _timeout = require("../../helper/timeout.js"); const { interfaces } = require("../../system/shared.js"); +const Param = require("./class.param.js"); +const Params = require("./class.params.js"); /** * @description @@ -84,6 +86,13 @@ module.exports = class Command { this.payload = obj.payload.read(0); } + // fix #383 + obj.params?.forEach((param, i, arr) => { + if (!(param instanceof Param)) { + arr[i] = new Param(param); + } + }); + // command duration timeout this.#privates.set("timeout", Number(process.env.COMMAND_RESPONSE_TIMEOUT)); @@ -180,16 +189,55 @@ module.exports = class Command { * @param {Array} [params] Parameter array * @param {Function} [cb] Callback */ - trigger(params, cb = () => { }) { + trigger(params, cb) { if (!cb && params instanceof Function) { cb = params; params = []; } + if (!params && !cb) { + params = []; + cb = () => { }; + } + let worker = this.#privates.get("handler"); let iface = interfaces.get(this.interface); + //console.log("params array:", this.params, params) + + let valid = params.every(({ key, value }) => { + + let param = this.params.find((param) => { + return param.key === key; + }); + + if (!param) { + return false; + } + + // auto convert "123" to 123 + if (param.type === "number") { + value = Number(value); + } + + return typeof (value) === param.type; + + }); + + if (!iface) { + let err = new Error(`Interface "${this.interface}" not found, cant write to it.`); + err.code = "NO_INTERFACE"; + return cb(err, false); + } + + if (!valid) { + let err = new Error(`Invalid parameter`); + err.code = "INVALID_PARAMETER"; + // TODO: Should not be as second argument passed "false"?! + return cb(err); + } + let timer = _timeout(this.#privates.get("timeout"), (timedout, duration, args) => { if (timedout) { @@ -206,7 +254,7 @@ module.exports = class Command { // handle timeout stuff here? // when so, timeout applys to custom functions too! - worker.call(this, this, iface, params, timer); + worker.call(this, this, iface, new Params(...params), timer); } @@ -231,29 +279,7 @@ module.exports = class Command { //payload: Joi.string().allow(null).default(null), payload: Joi.alternatives().try(Joi.string(), Joi.binary()).allow(null).default(null), description: Joi.string().allow(null).default(null), - params: Joi.array().items(Joi.object({ - type: Joi.string().valid("number", "string", "boolean").required(), - key: Joi.string().required() - }).when(".type", { - switch: [{ - is: "number", - then: Joi.object({ - value: Joi.number().default(null).allow(null), - min: Joi.number().default(0), - max: Joi.number().default(100) - }) - }, { - is: "string", - then: Joi.object({ - value: Joi.string().default(null).allow(null) - }) - }, { - is: "boolean", - then: Joi.object({ - value: Joi.boolean().default(null).allow(null) - }) - }] - })) + params: Joi.array().items(Param.schema()).default([]) }); } diff --git a/components/endpoints/class.endpoint.js b/components/endpoints/class.endpoint.js index 0240e6a..0e32e65 100644 --- a/components/endpoints/class.endpoint.js +++ b/components/endpoints/class.endpoint.js @@ -1,9 +1,14 @@ +const Joi = require("joi"); +const mongodb = require("mongodb"); + const Command = require("./class.command.js"); const State = require("./class.state.js"); //const Commands = require("./class.commands.js"); //const States = require("./!class.states.js"); +const Item = require("../../system/component/class.item.js"); const _expose = require("../../helper/expose.js"); +const _debounce = require("../../helper/debounce.js"); /** * @description @@ -27,17 +32,54 @@ const _expose = require("../../helper/expose.js"); * @see Devices components/devices/ * @see InterfaceStream components/devices/class.interfaceStream.js */ -module.exports = class Endpoint { - constructor(obj) { +module.exports = class Endpoint extends Item { + constructor(obj, scope) { + + super(obj); - Object.assign(this, obj); - this._id = String(obj._id); + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); //this.commands = new Commands(obj.commands); //this.states = new States(obj.states); + // see 407 & 420 + let updater = _debounce(async () => { + try { + + // trigger update on endpoint item + // otherwise ui is not rendered/refreshed on state changed + await scope.update(this._id, this); + + // feedback + scope.logger.verbose("Endpoint states updated", this.states); + + } catch (err) { + + scope.logger.warn(err, "Could not update item states after debouncing"); + + } + }, 100); + + // see 407 & 420 this.states = obj.states.map((item) => { - return new State(item); + return new State(item, () => { + try { + + // feedback + scope.logger.verbose(`Value in endpoint ("${obj._id}") state ("${item._id}") changed: ${item.alias}=${item.value}`); + + // update item in database + //await scope.update(this._id, this); + updater(); + + } catch (err) { + + scope.logger.warn(err, `Could not update item (${obj._id}) state ("${item._id}") in database: ${item.alias}=${item.value}`); + + } + }); }); this.commands = obj.commands.map((item) => { @@ -59,4 +101,25 @@ module.exports = class Endpoint { }); } + + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + enabled: Joi.boolean().default(true), + room: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).allow(null).default(null), + device: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).required(), + commands: Joi.array().items(Command.schema()).default([]), + states: Joi.array().items(State.schema()).default([]), + identifier: Joi.any().allow(null).default(null), // usefull for ssdp, etc. + icon: Joi.string().allow(null).default(null) + }); + } + + static validate(data) { + return Endpoint.schema().validate(data); + } + }; \ No newline at end of file diff --git a/components/endpoints/class.param.js b/components/endpoints/class.param.js new file mode 100644 index 0000000..0f53c6b --- /dev/null +++ b/components/endpoints/class.param.js @@ -0,0 +1,70 @@ +const Joi = require("joi"); + +module.exports = class Param { + + constructor(obj) { + + Object.assign(this, obj); + + Object.defineProperty(this, "value", { + get() { + return obj.value; + }, + set(val) { + + if (val === null) { + obj.value = null; + return; + } + + if (typeof (val) !== obj.type) { + throw new Error(`Parameter "${obj.key}" invalid type ${typeof (val)}. Expected ${obj.type}`); + } + + if (obj.type === "number" && !(val >= obj.min && obj.max >= val)) { + throw new Error(`Invalid value: ${val}. Expected value >= ${obj.min} or ${obj.max} >= value`); + } + + obj.value = val; + + }, + enumerable: true, + configurable: true + }); + + } + + static schema() { + return Joi.object({ + type: Joi.string().valid("number", "string", "boolean").required(), + key: Joi.string().required() + }).when(".type", { + switch: [{ + is: "number", + then: Joi.object({ + value: Joi.number().default(null).allow(null), + min: Joi.number().default(0), + max: Joi.number().default(100), + //default: Joi.number().allow(null).default(null) + }) + }, { + is: "string", + then: Joi.object({ + value: Joi.string().default(null).allow(null), + //default: Joi.string().allow(null).default(null) + }) + }, { + is: "boolean", + then: Joi.object({ + value: Joi.boolean().default(null).allow(null), + //default: Joi.boolean().allow(null).default(null) + }) + }] + }); + } + + static validate(data) { + return Param.schema().validate(data); + } + +}; \ No newline at end of file diff --git a/components/endpoints/class.params.js b/components/endpoints/class.params.js new file mode 100644 index 0000000..489cbe6 --- /dev/null +++ b/components/endpoints/class.params.js @@ -0,0 +1,14 @@ +module.exports = class Params extends Array { + + constructor(...args) { + super(...args); + } + + lean() { + return this.reduce((obj, { key, value }) => { + obj[key] = value; + return obj; + }, {}); + } + +}; \ No newline at end of file diff --git a/components/endpoints/class.state.js b/components/endpoints/class.state.js index 59b84a9..8fe1970 100644 --- a/components/endpoints/class.state.js +++ b/components/endpoints/class.state.js @@ -22,8 +22,7 @@ const mongodb = require("mongodb"); */ module.exports = class State { - - constructor(obj) { + constructor(obj, changed = () => { }) { Object.assign(this, obj); this._id = String(obj._id); @@ -44,13 +43,26 @@ module.exports = class State { }, set: (value) => { + if (this.type === "number" && this.invert && value < 0) { + value = value * -1; + } + // check for value type, but allow null value if (((typeof value) !== this.type) && (value !== null)) { + // TODO: uncomment & make active + //throw new TypeError(`Invalid type "${typeof (value)}"`); return; } // fix #251 if (this.type === "number" && !(value >= this.min && value <= this.max)) { + // TODO: uncomment & make active + //throw new RangeError(`Invalid value "${value}"`); + return; + } + + // prevent useles set/update + if (value === obj.value) { return; } @@ -58,6 +70,8 @@ module.exports = class State { this.timestamps.updated = Date.now(); + process.nextTick(changed, this); + }, configurable: false, enumerable: true @@ -96,7 +110,8 @@ module.exports = class State { then: Joi.object({ value: Joi.number().default(null).allow(null), min: Joi.number().default(0), - max: Joi.number().default(100) + max: Joi.number().default(100), + invert: Joi.boolean().default(false) }) }, { is: "string", diff --git a/components/endpoints/index.js b/components/endpoints/index.js index 4c58d11..a810c2a 100644 --- a/components/endpoints/index.js +++ b/components/endpoints/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const util = require("util"); //const logger = require("../../system/logger").create("endpoints"); @@ -44,23 +41,38 @@ class C_ENDPOINTS extends COMPONENT { constructor() { // inject logger, collection and schema object - super("endpoints", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - enabled: Joi.boolean().default(true), - room: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).allow(null).default(null), - device: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).required(), - commands: Joi.array().items(Command.schema()).default([]), - states: Joi.array().items(State.schema()).default([]), - identifier: Joi.any().allow(null).default(null), // usefull for ssdp, etc. - icon: Joi.string().allow(null).default(null) - }, module); + super("endpoints", Endpoint.schema(), module); this.hooks.post("add", (data, next) => { - next(null, new Endpoint(data)); + next(null, new Endpoint(data, this)); + }); + + + this.hooks.post("update", (data, next) => { + + // fix for #368 + data.states.forEach((state, i, arr) => { + if (!(state instanceof State)) { + arr[i] = new State(state, async () => { + + // trigger update on endpoint item + // otherwise ui is not rendered/refreshed on state changed + await this.update(this._id, this); + + }); + } + }); + + // fix for #287 + data.commands.forEach((command, i, arr) => { + if (!(command instanceof Command)) { + arr[i] = new Command(command); + } + }); + + next(); + }); @@ -120,7 +132,7 @@ instance.init((scope, ready) => { } else { data = data.map((item) => { - return new Endpoint(item); + return new Endpoint(item, scope); }); scope.items.push(...data); diff --git a/components/mdns/class.mdns.js b/components/mdns/class.mdns.js index 19efe27..09ad8ba 100644 --- a/components/mdns/class.mdns.js +++ b/components/mdns/class.mdns.js @@ -1,9 +1,17 @@ -class MDNS { +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const Item = require("../../system/component/class.item.js"); + +module.exports = class MDNS extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); Object.defineProperty(this, "_matches", { value: [], @@ -14,10 +22,25 @@ class MDNS { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + type: Joi.string().valid("SRV", "PTR", "A", "AAAA").default("A"), + timestamps: { + announced: Joi.number().allow(null).default(null) + } + }); + } + + static validate(data) { + return MDNS.schema().validate(data); + } + match(cb) { this._matches.push(cb); } -} - -module.exports = MDNS; \ No newline at end of file +}; \ No newline at end of file diff --git a/components/mdns/index.js b/components/mdns/index.js index 5435dd4..787bffc 100644 --- a/components/mdns/index.js +++ b/components/mdns/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); @@ -30,16 +27,7 @@ class C_MDNS extends COMPONENT { constructor() { // inject logger, collection and schema object - super("mdns", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - type: Joi.string().valid("SRV", "PTR", "A", "AAAA").default("A"), - timestamps: { - announced: Joi.number().allow(null).default(null) - } - }, module); + super("mdns", MDNS.schema(), module); this.hooks.post("add", (data, next) => { next(null, new MDNS(data)); diff --git a/components/mqtt/!message-handler.js b/components/mqtt/!message-handler.js new file mode 100644 index 0000000..7800041 --- /dev/null +++ b/components/mqtt/!message-handler.js @@ -0,0 +1,151 @@ +const crypto = require("crypto"); +const mqtt = require("mqtt-packet"); + +const VERSION = Number(process.env.MQTT_BROKER_VERSION); + +const parser = mqtt.parser({ + protocolVersion: VERSION +}); + +const exitCodes = require("./exit-codes.js")(VERSION); + +module.exports = (scope) => { + scope._ready(({ logger, events }) => { + + // ping timer + let interval = null; + + events.on("publish", (packet) => { + scope.items.forEach(({ topic, _subscriber }) => { + + if (String(packet.topic).startsWith(topic) || packet.topic === topic) { + _subscriber.forEach((cb) => { + cb(packet.payload, packet); + }); + } + + }); + }); + + + events.on("connected", (ws) => { + + logger.debug("TCP socket connected to broker"); + + events.once("disconnected", () => { + clearInterval(interval); + logger.trace("Ping interval cleared"); + }); + + // TODO make this object configurable + let data = mqtt.generate({ + cmd: "connect", + protocolId: "MQTT", // Or "MQIsdp" in MQTT 3.1 and 5.0 + protocolVersion: VERSION, // Or 3 in MQTT 3.1, or 5 in MQTT 5.0 + clean: true, // Can also be false + clientId: process.env.MQTT_CLIENT_ID, + keepalive: 10, // Seconds which can be any positive number, with 0 as the default setting + /* + will: { + topic: "mydevice/test", + payload: Buffer.from("2134f"), // Payloads are buffers + + } + */ + }); + + ws.send(data); + + events.once("connack", (packet) => { + if (packet.returnCode === 0) { + + events.once("suback", () => { + + logger.debug("Subscribed to topic #"); + + let ping = mqtt.generate({ + cmd: "pingreq" + }); + + interval = setInterval(() => { + ws.send(ping); + }, Number(process.env.MQTT_PING_INTERVAL)); + + // monkey patch publisher function + scope.items.forEach((item) => { + item._publisher = (payload) => { + + scope.logger.verbose(`Publish on topic ${item.topic}`, payload); + + let pub = mqtt.generate({ + cmd: "publish", + messageId: crypto.randomInt(0, 65535), + qos: 0, + dup: false, + topic: item.topic, + payload: Buffer.from(`${payload}`), + retain: false + }); + + ws.send(pub); + + }; + }); + + }); + + let sub = mqtt.generate({ + cmd: "subscribe", + messageId: crypto.randomInt(0, 65535), + /* + properties: { // MQTT 5.0 properties + subscriptionIdentifier: 145, + userProperties: { + test: "shellies" + } + }, + */ + subscriptions: [{ + topic: "#", + qos: 0, + nl: false, // no Local MQTT 5.0 flag + rap: true, // Retain as Published MQTT 5.0 flag + rh: 1 // Retain Handling MQTT 5.0 + }] + }); + + ws.send(sub); + + } + }); + + }); + + + parser.on("packet", (packet) => { + + logger.verbose("Packet received", packet); + + if (packet.cmd === "connack") { + if (packet.returnCode == 0) { + + logger.debug("Connected to broker"); + + } else { + + logger.warn(`Could not connecto to broker: "${exitCodes[packet.returnCode]}"`); + + } + } + + events.emit(packet.cmd, packet); + + }); + + + events.on("message", (message) => { + parser.parse(message); + }); + + }); +}; \ No newline at end of file diff --git a/components/mqtt/class.mqtt.js b/components/mqtt/class.mqtt.js index ecafe25..3d2aa81 100644 --- a/components/mqtt/class.mqtt.js +++ b/components/mqtt/class.mqtt.js @@ -1,3 +1,7 @@ +const Item = require("../../system/component/class.item.js"); +const Joi = require("joi"); +const mongodb = require("mongodb"); + /** * @description * Represents a mqtt topic item @@ -10,12 +14,15 @@ * @property {String} topic MQTT topic e.g. `air-sensor/sensor/particulate_matter_25m_concentration/state` * @property {String} description Description for Admins/Topic */ -class MQTT { +class MQTT extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); Object.defineProperty(this, "_subscriber", { value: [], @@ -33,6 +40,20 @@ class MQTT { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + topic: Joi.string().required(), + description: Joi.string().allow(null).default(null) + }); + } + + static validate(data) { + return MQTT.schema().validate(data); + } + /** * Subscribe to this topic * @param {Function} cb Callback diff --git a/components/mqtt/index.js b/components/mqtt/index.js index 10deecd..e11b917 100644 --- a/components/mqtt/index.js +++ b/components/mqtt/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); @@ -49,13 +46,7 @@ class C_MQTT extends COMPONENT { constructor() { // inject logger, collection and schema object - super("mqtt", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - topic: Joi.string().required(), - description: Joi.string().allow(null).default(null) - }, module); + super("mqtt", MQTT.schema(), module); this.hooks.post("add", (data, next) => { next(null, new MQTT(data)); diff --git a/components/mqtt/message-handler.js b/components/mqtt/message-handler.js index 7800041..53de2d8 100644 --- a/components/mqtt/message-handler.js +++ b/components/mqtt/message-handler.js @@ -2,111 +2,90 @@ const crypto = require("crypto"); const mqtt = require("mqtt-packet"); const VERSION = Number(process.env.MQTT_BROKER_VERSION); +const exitCodes = require("./exit-codes.js")(VERSION); const parser = mqtt.parser({ protocolVersion: VERSION }); -const exitCodes = require("./exit-codes.js")(VERSION); - module.exports = (scope) => { - scope._ready(({ logger, events }) => { + scope._ready(({ logger, events, items }) => { - // ping timer + // ping setTimeout timer let interval = null; + + // listen for published topics + // call publish handler on each mqtt item events.on("publish", (packet) => { - scope.items.forEach(({ topic, _subscriber }) => { + // feedback + logger.trace(`Published: ${packet.topic}=${packet.payload}`); + + items.forEach(({ topic, _subscriber }) => { if (String(packet.topic).startsWith(topic) || packet.topic === topic) { + _subscriber.forEach((cb) => { cb(packet.payload, packet); }); - } + } }); - }); + }); - events.on("connected", (ws) => { - logger.debug("TCP socket connected to broker"); + // "connected" fires every time a websocket connection is made, e.g. from a connector. + // So we need to react and create a new connection to the browker + events.on("connected", async (ws) => { + try { - events.once("disconnected", () => { - clearInterval(interval); - logger.trace("Ping interval cleared"); - }); + // connecto to broker + // TODO: Add here credentials for authentication + await new Promise((resolve, reject) => { - // TODO make this object configurable - let data = mqtt.generate({ - cmd: "connect", - protocolId: "MQTT", // Or "MQIsdp" in MQTT 3.1 and 5.0 - protocolVersion: VERSION, // Or 3 in MQTT 3.1, or 5 in MQTT 5.0 - clean: true, // Can also be false - clientId: process.env.MQTT_CLIENT_ID, - keepalive: 10, // Seconds which can be any positive number, with 0 as the default setting - /* - will: { - topic: "mydevice/test", - payload: Buffer.from("2134f"), // Payloads are buffers - - } - */ - }); + logger.verbose("Connect to broker..."); - ws.send(data); + let data = mqtt.generate({ + cmd: "connect", + protocolId: "MQTT", + protocolVersion: VERSION, + clean: true, + clientId: process.env.MQTT_CLIENT_ID, + keepalive: 10, + }); - events.once("connack", (packet) => { - if (packet.returnCode === 0) { + ws.send(data, () => { + parser.once("packet", ({ cmd, returnCode }) => { + if (cmd === "connack" && returnCode === 0) { - events.once("suback", () => { + // feedback + logger.debug("Connected to broker"); - logger.debug("Subscribed to topic #"); + resolve(); - let ping = mqtt.generate({ - cmd: "pingreq" + } else { + reject(new Error(exitCodes[returnCode])); + } }); + }); - interval = setInterval(() => { - ws.send(ping); - }, Number(process.env.MQTT_PING_INTERVAL)); - - // monkey patch publisher function - scope.items.forEach((item) => { - item._publisher = (payload) => { - - scope.logger.verbose(`Publish on topic ${item.topic}`, payload); + }); - let pub = mqtt.generate({ - cmd: "publish", - messageId: crypto.randomInt(0, 65535), - qos: 0, - dup: false, - topic: item.topic, - payload: Buffer.from(`${payload}`), - retain: false - }); - ws.send(pub); + // subscribe to # topic + // so we can handle all topics + await new Promise((resolve, reject) => { - }; - }); + // feedback + logger.verbose("[MQTT] Subscribe to # topic..."); - }); - - let sub = mqtt.generate({ + let data = mqtt.generate({ cmd: "subscribe", messageId: crypto.randomInt(0, 65535), - /* - properties: { // MQTT 5.0 properties - subscriptionIdentifier: 145, - userProperties: { - test: "shellies" - } - }, - */ subscriptions: [{ topic: "#", + //topic: "#", qos: 0, nl: false, // no Local MQTT 5.0 flag rap: true, // Retain as Published MQTT 5.0 flag @@ -114,37 +93,102 @@ module.exports = (scope) => { }] }); - ws.send(sub); + ws.send(data, () => { + parser.once("packet", ({ cmd, granted }) => { + if (cmd === "suback" && granted[0] === 0) { - } - }); + // feedback + logger.debug("Subscribed to # topic"); - }); + resolve(); + } else { + reject(new Error("Subscription not granted")); + } + }); + }); - parser.on("packet", (packet) => { + }); - logger.verbose("Packet received", packet); - if (packet.cmd === "connack") { - if (packet.returnCode == 0) { + // monkey patch/override publisher function + // on mqtt item topics with current connection + await new Promise((resolve) => { - logger.debug("Connected to broker"); + items.forEach((item) => { + item._publisher = (payload, options = {}) => { - } else { + // feedback + logger.verbose(`Publish on topic ${item.topic}`, payload); - logger.warn(`Could not connecto to broker: "${exitCodes[packet.returnCode]}"`); + let pub = mqtt.generate({ + cmd: "publish", + messageId: crypto.randomInt(0, 65535), + qos: 0, + dup: false, + topic: item.topic, + payload: Buffer.from(payload), + retain: false, + ...options + }); + + ws.send(pub, () => { + + // feedback + // log self send published messages for debugging + logger.trace(`Send publish: ${item.topic}=${payload}`); + + }); + + }; + }); + + resolve(); + + }); + + + // listen for publishes and other packates + // send ping requests regulary to broker + await new Promise((resolve) => { + + let ping = mqtt.generate({ + cmd: "pingreq" + }); + + interval = setInterval(() => { + ws.send(ping); + }, Number(process.env.MQTT_PING_INTERVAL)); + + resolve(); + + }); + + } catch (err) { + + // feedback + logger.error(err, "Could not setup MQTT broker handling"); - } } + }); + + + // listen for disconnects from the connector + // clear the ping requests intveral, cant reach broker + events.once("disconnected", () => { + clearInterval(interval); + }); - events.emit(packet.cmd, packet); + // re-emit events on component scope/events + parser.on("packet", (packet) => { + scope.events.emit(packet.cmd, packet); }); - events.on("message", (message) => { - parser.parse(message); + // handle messages from the websockt as mqtt packets + events.on("message", (msg) => { + parser.parse(msg); }); }); diff --git a/components/plugins/class.plugin.js b/components/plugins/class.plugin.js index 1b2129e..26ba9ca 100644 --- a/components/plugins/class.plugin.js +++ b/components/plugins/class.plugin.js @@ -1,6 +1,13 @@ const fs = require("fs"); const path = require("path"); +const Joi = require("joi"); +const mongodb = require("mongodb"); const logger = require("../../system/logger/index.js"); +const semver = require("semver"); +const pkg = require("../../package.json"); +const uuid = require("uuid"); + +const Item = require("../../system/component/class.item.js"); //const Bootstrap = require("./class.bootstrap.js"); @@ -19,100 +26,191 @@ const logger = require("../../system/logger/index.js"); * @property {Boolean} autostart Start the plugin after the backend has initzialized successful? * @property {Boolean} enabled Indicates if this thing can do anything */ -class Plugin { +module.exports = class Plugin extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); + + Object.defineProperty(this, "logger", { + value: logger.create(`plugins/${this.uuid}`), + configurable: false, + enumerable: false, + writable: false + }); + + Object.defineProperty(this, "started", { + value: false, + configurable: false, + enumerable: false, + writable: true + }); } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + uuid: Joi.string().default(() => { + return uuid.v4(); + }), + version: Joi.string().required().messages({ + "any.invalid": `{{#label}} needs to be a valid semver version` + }).custom((value, helpers) => { + + if (semver.valid(value) === null) { + return helpers.error("any.invalid"); + } + + return semver.clean(value); + + }), + //runlevel: Joi.number().min(0).max(2).default(0), + autostart: Joi.boolean().default(true), + enabled: Joi.boolean().default(true), + intents: Joi.array().items("devices", "endpoints", "plugins", "rooms", "ssdp", "store", "users", "vault", "mqtt", "mdns", "webhooks").required() + }); + } + + static validate(data) { + return Plugin.schema().validate(data); + } + /** * @function start * Start installed plugin */ start() { - if (this.enabled) { + if (!this.started) { + if (this.enabled) { - let plugin = path.resolve(process.cwd(), "plugins", this.uuid); + // feedback + logger.debug(`Start plugin "${this.name}"...`); - if (fs.existsSync(plugin)) { + let json = {}; + let plugin = path.resolve(process.cwd(), "plugins", this.uuid); + let file = path.resolve(plugin, "package.json"); - let init = (dependencies, cb) => { - try { + // 1) check if plugin is compatible + try { - const granted = dependencies.every((c) => { - if (this.intents.includes(c)) { + let content = fs.readFileSync(file); + json = JSON.parse(content); - return true; + // check in further version: + // json?.openhaus?.backend || json?.openhaus?.versions?.backend + // when a plugin provides frontend stuff or store data about itself in openhaus.plugin/openhaus.intents + if (!semver.satisfies(pkg.version, json?.backend)) { + this.logger.warn(`Plugin "${this.name}" is incompatible. It may work not properly or break something!`); + } - } else { + } catch (err) { - logger.warn(`Plugin ${this.uuid} (${this.name}) wants to access not registerd intens "${c}"`); - return false; + this.logger.warn(err, `Could not check plugin compatibility for plugin "${this.name}"`); - } - }); + if (err.code === "ENOENT") { + this.logger.warn(`package.json for plugin "${this.name}" not found, try to start it anyway...`); + } else { + this.logger.error(err); + } + + } + + // 2) start plugin + if (fs.existsSync(plugin)) { + + let init = (dependencies, cb) => { + try { + + // NOTE: Monkey patch ready/abort method to init? + // A plugin could siganlize if its ready or needs to be restarted + /* + let init = new Promise((resolve, reject) => { + init.ready = resolve; + init.abort = reject; + }); + */ + + const granted = dependencies.every((c) => { + if (this.intents.includes(c)) { + + return true; - if (granted) { + } else { - let components = dependencies.map((name) => { - return require(path.resolve(process.cwd(), `components/${name}`)); + logger.warn(`Plugin ${this.uuid} (${this.name}) wants to access not registerd intens "${c}"`); + return false; + + } }); - cb(this, components); - return init; + if (granted) { + + let components = dependencies.map((name) => { + return require(path.resolve(process.cwd(), `components/${name}`)); + }); - } else { + cb(this, components); + return init; + + } else { + + throw new Error(`Unregisterd intents access approach`); + + } - throw new Error(`Unregisterd intents access approach`); + } catch (err) { + + logger.error(err, `Plugin could not initalize!`, err.message); + throw err; } + }; - } catch (err) { + init[Symbol.for("uuid")] = this.uuid; - logger.error(err, `Plugin could not initalize!`, err.message); - throw err; + try { - } - }; + let returns = require(path.resolve(plugin, "index.js"))(this, this.logger, init); - init[Symbol.for("uuid")] = this.uuid; + if (!returns) { + return; + } - try { + if (returns[Symbol.for("uuid")] !== this.uuid) { + logger.warn(`Plugin "${this.uuid}" (${this.name}) does not return the init function!`); + throw new Error("Invalid init function returnd!"); + } - let log = logger.create(`plugins/${this.uuid}`); - let returns = require(path.resolve(plugin, "index.js"))(this, log, init); + this.started = true; - if (!returns) { - return; + } catch (err) { + logger.error(`Error in plugin "${this.name}": `, err); + throw err; } - if (returns[Symbol.for("uuid")] !== this.uuid) { - logger.warn(`Plugin "${this.uuid}" (${this.name}) does not return the init function!`); - throw new Error("Invalid init function returnd!"); - } + } else { + + logger.error(`Could not found plugin file/folder "${this.uuid}"`); + throw new Error("Plugin not found"); - } catch (err) { - logger.error(`Error in plugin "${this.name}": `, err); - throw err; } } else { - logger.error(`Could not found plugin file/folder "${this.uuid}"`); - throw new Error("Plugin not found"); + let err = Error("Plugin is not enabled!"); + err.code = "PLUGIN_NOT_ENABLED"; - } - - } else { - - let err = Error("Plugin is not enabled!"); - err.code = "PLUGIN_NOT_ENABLED"; - - throw err; + throw err; + } } } @@ -123,6 +221,4 @@ class Plugin { } */ -} - -module.exports = Plugin; \ No newline at end of file +}; \ No newline at end of file diff --git a/components/plugins/index.js b/components/plugins/index.js index 77153bf..a1c0192 100644 --- a/components/plugins/index.js +++ b/components/plugins/index.js @@ -1,10 +1,6 @@ const fs = require("fs"); const path = require("path"); -const Joi = require("joi"); -const mongodb = require("mongodb"); -const uuid = require("uuid"); - //const logger = require("../../system/logger").create("plugins"); @@ -35,22 +31,10 @@ class C_PLUGINS extends COMPONENT { // inject logger, collection and schema object // super(logger, mongodb.client.collection("plugins"), { - super("plugins", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - uuid: Joi.string().default(() => { - return uuid.v4(); - }), - version: Joi.number().required(), - //runlevel: Joi.number().min(0).max(2).default(0), - autostart: Joi.boolean().default(true), - enabled: Joi.boolean().default(true), - intents: Joi.array().items("devices", "endpoints", "plugins", "rooms", "ssdp", "store", "users", "vault", "mqtt", "mdns", "webhooks").required() - }, module); + super("plugins", Plugin.schema(), module); this.hooks.post("add", (data, next) => { + // NOTE: use path to plugins set via env, see #432 fs.mkdir(path.resolve(process.cwd(), "plugins", data.uuid), (err) => { // ignore when folder exists @@ -70,6 +54,7 @@ class C_PLUGINS extends COMPONENT { }); this.hooks.post("remove", (item, result, _id, next) => { + // NOTE: use path to plugins set via env, see #432 fs.rm(path.resolve(process.cwd(), "plugins", item.uuid), { recursive: true }, (err) => { diff --git a/components/rooms/class.room.js b/components/rooms/class.room.js index b2ee6fb..df6e95f 100644 --- a/components/rooms/class.room.js +++ b/components/rooms/class.room.js @@ -1,3 +1,8 @@ +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const Item = require("../../system/component/class.item.js"); + /** * @description * Represents a room item @@ -11,9 +16,32 @@ * @property {Number} [floor=null] Floor on which the room is located * @property {String} [icon=null] fontawesome class string for the frontend */ -module.exports = class Room { +module.exports = class Room extends Item { + constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); + } + + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + number: Joi.number().allow(null).default(null), + floor: Joi.number().allow(null).default(null), + icon: Joi.string().allow(null).default(null) + }); + } + + static validate(data) { + return Room.schema().validate(data); + } + }; \ No newline at end of file diff --git a/components/rooms/index.js b/components/rooms/index.js index 5704fd5..9aff9e1 100644 --- a/components/rooms/index.js +++ b/components/rooms/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); @@ -51,15 +48,7 @@ class C_ROOMS extends COMPONENT { constructor() { // inject logger, collection and schema object - super("rooms", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - number: Joi.number().allow(null).default(null), - floor: Joi.number().allow(null).default(null), - icon: Joi.string().allow(null).default(null) - }, module); + super("rooms", Room.schema(), module); this.hooks.post("add", (data, next) => { next(null, new Room(data)); diff --git a/components/scenes/class.makro.js b/components/scenes/class.makro.js index b1d9b29..b0b8689 100644 --- a/components/scenes/class.makro.js +++ b/components/scenes/class.makro.js @@ -1,8 +1,9 @@ const Joi = require("joi"); const mongodb = require("mongodb"); -const dispatcher = require("../../system/dispatcher"); +//const dispatcher = require("../../system/dispatcher"); //const C_ENDPOINTS = require("../endpoints"); +const types = require("./makro-types.js"); /** * @description @@ -44,6 +45,14 @@ module.exports = class Makro { * @returns */ execute(result, signal) { + + if (types[this.type]) { + return types[this.type](this, result, signal); + } else { + throw new Error(`Type ${this.type} handler not found`); + } + + /* return new Promise((resolve, reject) => { try { if (this.type === "timer") { @@ -89,6 +98,8 @@ module.exports = class Makro { } }); + */ + } @@ -108,6 +119,7 @@ module.exports = class Makro { return String(new mongodb.ObjectId()); }), type: Joi.string().valid("command", "timer", "scene"/*, "state"*/).required(), + enabled: Joi.boolean().default(true), timestamps: Joi.object({ created: Joi.number().allow(null), updated: Joi.number().allow(null) diff --git a/components/scenes/class.scene.js b/components/scenes/class.scene.js index 2139c8c..626a66c 100644 --- a/components/scenes/class.scene.js +++ b/components/scenes/class.scene.js @@ -1,17 +1,40 @@ +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const { setTimeout } = require("timers/promises"); + const Makro = require("./class.makro.js"); +const Trigger = require("./class.trigger.js"); + +const Item = require("../../system/component/class.item.js"); -module.exports = class Scene { +module.exports = class Scene extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); this.makros = obj.makros.map((makro) => { return new Makro(makro); }); + this.triggers = obj.triggers.map((data) => { + + let trigger = new Trigger(data); + + trigger.signal.on("fire", () => { + this.trigger(); + }); + + return trigger; + + }); + Object.defineProperty(this, "running", { value: false, enumerable: false, @@ -49,26 +72,60 @@ module.exports = class Scene { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + makros: Joi.array().items(Makro.schema()).default([]), + triggers: Joi.array().items(Trigger.schema()).default([]), + visible: Joi.boolean().default(true), + icon: Joi.string().allow(null).default(null) + }); + } + + static validate(data) { + return Scene.schema().validate(data); + } + trigger() { let ac = new AbortController(); this._ac = ac; - let init = this.makros.map((makro) => { + let init = this.makros.filter(({ + + // enabled is per default "true" + // when a marko should be disabled + // this has explicit to be set to false + enabled = true + + }) => { + + // execute only enabled makros + return enabled; + + }).map((makro) => { // bind scope to method return makro.execute.bind(makro); }).reduce((acc, cur, i) => { return (result) => { - return acc(result, this._ac.signal).then((r) => { + return acc(result, this._ac.signal).then(async (r) => { if (this.aborted) { return Promise.reject("Aborted!"); } else { + // NOTE: Intended to be a workaround for #329 & #312 + // But the general idea of this is not bad + await setTimeout(Number(process.env.SCENES_MAKRO_DELAY)); + this.index = i; + return cur(r, this._ac.signal); } diff --git a/components/scenes/class.trigger.js b/components/scenes/class.trigger.js new file mode 100644 index 0000000..3f57e54 --- /dev/null +++ b/components/scenes/class.trigger.js @@ -0,0 +1,126 @@ +const { EventEmitter } = require("events"); + +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const types = require("./trigger-types.js"); + +module.exports = class Trigger { + + /** + * @class Trigger + * + * @param {Object} obj Parameter object + * + * @property {EventEmitter} signal Event Emitter signal + * @property {Number|null} fired Last fired timestamp + * @property {Object} prams Parameter object + */ + constructor(obj) { + + //this.signal = new TriggerSignal(); + //this.signal = new EventEmitter(); + //this.fired = null; + + Object.defineProperty(this, "signal", { + value: new EventEmitter(), + writable: false, + enumerable: false + }); + + Object.defineProperty(this, "fired", { + value: null, + writable: true, + enumerable: false + }); + + Object.assign(this, obj); + + if (types[obj.type]) { + types[obj.type](this, this.params); + } + + } + + + /** + * @function schema + * State schema, see properties above. + * + * @static + * + * @returns {Object} Joi Object + * + * @link https://joi.dev/api/?v=17.6.0#anyvalidatevalue-options + */ + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + type: Joi.string().valid("cronjob", "webhook"/*, "state", "scene"*/).required(), + enabled: Joi.boolean().default(true), + //params: Joi.object().... + timestamps: Joi.object({ + created: Joi.number().allow(null), + updated: Joi.number().allow(null) + }) + }).when(".type", { + switch: [{ + is: "cronjob", + then: Joi.object({ + params: Joi.object({ + cron: Joi.string().pattern(/^((((\d+,)+\d+|(\d+(\/|-|#)\d+)|\d+L?|\*(\/\d+)?|L(-\d+)?|\?|[A-Z]{3}(-[A-Z]{3})?) ?){5,7})$/), + }) + }) + }, { + is: "webhook", + then: Joi.object({ + params: Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).required() + }) + }) + }/*,{ + is: "state", + then: Joi.object({ + params: Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).required(), + threshold: Joi.alternatives(Joi.number(), Joi.string(), Joi.boolean()).required(), + }) + }) + },{ + is: "scene", + then: Joi.object({ + params: Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).required() + }) + }) + }**/] + }); + } + + + /** + * @function validate + * Validate schema object + * + * @static + * + * @param {Object} obj Input data that matches the schema + * + * @returns {Object} Joi validation object + * + * @link https://joi.dev/api/?v=17.6.0#anyvalidatevalue-options + */ + static validate(obj) { + return Trigger.schema().validate(obj); + } + + fire() { + if (this.enabled) { + this.fired = Date.now(); + this.signal.emit("fire"); + } + } + +}; \ No newline at end of file diff --git a/components/scenes/index.js b/components/scenes/index.js index 4331014..77ce557 100644 --- a/components/scenes/index.js +++ b/components/scenes/index.js @@ -1,12 +1,10 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); const Scene = require("./class.scene.js"); const Makro = require("./class.makro.js"); +const Trigger = require("./class.trigger.js"); /** * @description @@ -20,18 +18,33 @@ class C_SCENES extends COMPONENT { constructor() { // inject logger, collection and schema object - super("scenes", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - makros: Joi.array().items(Makro.schema()).default([]) - }, module); + super("scenes", Scene.schema(), module); this.hooks.post("add", (data, next) => { next(null, new Scene(data)); }); + // handle change makro array + // see #364 + this.hooks.post("update", (data, next) => { + + data.makros.forEach((makro, i, arr) => { + if (!(makro instanceof Makro)) { + arr[i] = new Makro(makro); + } + }); + + // fix #390 + data.triggers.forEach((trigger, i, arr) => { + if (!(trigger instanceof Trigger)) { + arr[i] = new Trigger(trigger); + } + }); + + next(); + + }); + } } diff --git a/components/scenes/makro-types.js b/components/scenes/makro-types.js new file mode 100644 index 0000000..6db6c82 --- /dev/null +++ b/components/scenes/makro-types.js @@ -0,0 +1,60 @@ +const dispatcher = require("../../system/dispatcher"); + +module.exports = { + + // TODO (mstirner) change to "sleep" instead! + "timer": ({ _id, value }, result, signal) => { + return new Promise((resolve) => { + + let timeout = setTimeout(() => { + resolve(_id, signal); + }, value); + + signal.addEventListener("abort", () => { + clearTimeout(timeout); + }, { + once: true + }); + + }); + }, + + "command": ({ endpoint, _id, command }) => { + return new Promise((resolve) => { + + // TODO (mstirner) replace dispatcher with eventbus + dispatcher({ + "component": "endpoints", + "item": endpoint, + "method": "trigger", + "args": [command, () => { + + //console.log("Command executed adasdasdfasdfasdfasfdadsfasdf", err || success) + // how should this be catched? + // reject the makro execution if one command fails? + // or ignore it simple, and continue? + + }] + }); + + resolve(_id); + + }); + }, + + "scene": ({ scene }) => { + return new Promise((resolve) => { + + dispatcher({ + "component": "scenes", + "item": scene, + "method": "trigger", + "args": [] + }); + + resolve(); + + }); + } + +}; \ No newline at end of file diff --git a/components/scenes/trigger-types.js b/components/scenes/trigger-types.js new file mode 100644 index 0000000..335f1fc --- /dev/null +++ b/components/scenes/trigger-types.js @@ -0,0 +1,46 @@ +const { Cron } = require("../../system/cronjob"); +const cron = new Cron(); + +module.exports = { + + "cronjob": (trigger, params) => { + cron.add(params.cron, () => { + trigger.fire(); + }); + }, + + /* + "state": (trigger, { params }) => { + // this should check for state changes of endpoints + // requires a "eventbus" and some additionl code in endpoints + // params.endpoint = endpoint object id + // params.state = endpoint state object id + // check if greater/lower than threshold or how to react? + } + */ + + /* + "webhook": (trigger, { param }) => { + // this waits for a http client to hit a webhook route + // the webhook itself should be "fire" some event + // we can listen to from the eventbus + // param.webhhok = mongodb _id + } + */ + + /* + "scene": (trigger, { param }) => { + // this waits for another scene to get executed + // check for dispatcher events? + // but this would only be executed when dispatcher is used + // how to check for all scenes? + // would be much easier with eventbus + dispatcher.on("scene", ({scene}) => { + if(scene === param._id){ + trigger.fire(); + } + }); + } + */ + +}; \ No newline at end of file diff --git a/components/ssdp/class.ssdp.js b/components/ssdp/class.ssdp.js index 91971df..2ebc564 100644 --- a/components/ssdp/class.ssdp.js +++ b/components/ssdp/class.ssdp.js @@ -1,9 +1,20 @@ -class SSDP { +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const Item = require("../../system/component/class.item.js"); + +// simple ssdp monitor: +// nc -ulvv 239.255.255.250 1900 +// TODO: Add documentation for class +module.exports = class SSDP extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); Object.defineProperty(this, "_matches", { value: [], @@ -14,10 +25,28 @@ class SSDP { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + description: Joi.string().allow(null).default(null), + nt: Joi.string().allow(null).default(null), + usn: Joi.string().allow(null).default(null), + // NOTE: Removed head field since currently no unique index can be build with it + //headers: Joi.array().items(Joi.string()).allow(null).default([]), + timestamps: { + announced: Joi.number().allow(null).default(null) + } + }); + } + + static validate(data) { + return SSDP.schema().validate(data); + } + match(cb) { this._matches.push(cb); } -} - -module.exports = SSDP; \ No newline at end of file +}; \ No newline at end of file diff --git a/components/ssdp/index.js b/components/ssdp/index.js index c0a770e..b722d0d 100644 --- a/components/ssdp/index.js +++ b/components/ssdp/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); @@ -48,19 +45,7 @@ class C_SSDP extends COMPONENT { constructor() { // inject logger, collection and schema object - super("ssdp", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - description: Joi.string().allow(null).default(null), - nt: Joi.string().allow(null).default(null), - usn: Joi.string().allow(null).default(null), - // NOTE: Removed head field since currently no unique index can be build with it - //headers: Joi.array().items(Joi.string()).allow(null).default([]), - timestamps: { - announced: Joi.number().allow(null).default(null) - } - }, module); + super("ssdp", SSDP.schema(), module); this.hooks.post("add", (data, next) => { next(null, new SSDP(data)); diff --git a/components/store/class.store.js b/components/store/class.store.js index abbdb01..25848cf 100644 --- a/components/store/class.store.js +++ b/components/store/class.store.js @@ -1,6 +1,10 @@ const { EventEmitter } = require("events"); +const Joi = require("joi"); +const mongodb = require("mongodb"); const Value = require("./class.value.js"); +const uuid = require("uuid"); +const Item = require("../../system/component/class.item.js"); /** * @description @@ -17,19 +21,22 @@ const Value = require("./class.value.js"); * * @see value components/store/class.value.js */ -class Store { +module.exports = class Store extends Item { #privates = new Map(); constructor(obj, scope) { + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); + // create event emitter for lean object let events = new EventEmitter(); this.#privates.set("events", events); - Object.assign(this, obj); - this._id = String(obj._id); - this.config = obj.config.map((data) => { return new Value(data, async () => { try { @@ -55,6 +62,24 @@ class Store { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + description: Joi.string().allow(null).default(null), + config: Joi.array().min(1).items(Value.schema()).required(), + //item: Joi.string().allow(null).default(null), + uuid: Joi.string().default(() => { + return uuid.v4(); + }) + }); + } + + static validate(data) { + return Store.schema().validate(data); + } /** * @function changes @@ -112,6 +137,4 @@ class Store { }, {}); } -} - -module.exports = Store; \ No newline at end of file +}; \ No newline at end of file diff --git a/components/store/class.value.js b/components/store/class.value.js index 9a20df1..3daa0ff 100644 --- a/components/store/class.value.js +++ b/components/store/class.value.js @@ -60,6 +60,7 @@ class Value { _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { return String(new mongodb.ObjectId()); }), + name: Joi.string().required(), key: Joi.string().required(), value: Joi.when("type", { is: "number", diff --git a/components/store/index.js b/components/store/index.js index e30351f..393ca9b 100644 --- a/components/store/index.js +++ b/components/store/index.js @@ -1,7 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); -const uuid = require("uuid"); - const COMPONENT = require("../../system/component/class.component.js"); //const Value = require("./class.value.js"); @@ -38,21 +34,29 @@ class C_STORE extends COMPONENT { constructor() { // inject logger, collection and schema object - super("store", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - config: Joi.array().min(1).items(Value.schema()).required(), - item: Joi.string().allow(null).default(null), - namespace: Joi.string().default(() => { - return uuid.v4(); - }), - }, module); + super("store", Store.schema(), module); this.hooks.post("add", (data, next) => { next(null, new Store(data, this)); }); + // fix #406 + this.hooks.post("update", (data, next) => { + + data.config.forEach((value, i, arr) => { + if (!(value instanceof Value)) { + arr[i] = new Value(value); + } + }); + + next(); + + }); + + this.collection.createIndex("uuid", { + unique: true + }); + } } diff --git a/components/users/class.user.js b/components/users/class.user.js index 8dcaa26..e6d5c5c 100644 --- a/components/users/class.user.js +++ b/components/users/class.user.js @@ -1,7 +1,11 @@ const jwt = require("jsonwebtoken"); +const Joi = require("joi"); +const mongodb = require("mongodb"); const _promisify = require("../../helper/promisify"); +const Item = require("../../system/component/class.item.js"); + /** * @description * Represents a user item @@ -18,12 +22,15 @@ const _promisify = require("../../helper/promisify"); * @property {Boolean} [enabled=false] Is user enabled/can login? * @property {Array} tokens Internal used to store JWTs (Active tokens/sessions) */ -module.exports = class User { +module.exports = class User extends Item { constructor(scope, obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); Object.defineProperty(this, "_scope", { value: scope, @@ -34,6 +41,30 @@ module.exports = class User { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required(), + email: Joi.string().required(), + password: Joi.string().required(), + enabled: Joi.boolean().default(false), + tokens: Joi.array().items(Joi.string()).default([]), + admin: Joi.boolean().default(false), + timestamps: { + // NOTE: would be greate to have a expiration date for users + // expires: Joi.number().allow(null).default(null) + login: Joi.number().allow(null).default(null), + logout: Joi.number().allow(null).default(null) + } + }); + } + + static validate(data) { + return User.schema().validate(data); + } + /** * @function addToken * Adds a new JWT token for the user. diff --git a/components/users/index.js b/components/users/index.js index 5b2b2fb..d1b5654 100644 --- a/components/users/index.js +++ b/components/users/index.js @@ -1,6 +1,4 @@ // external modules -const mongodb = require("mongodb"); -const Joi = require("joi"); const bcrypt = require("bcrypt"); // system stuff @@ -25,23 +23,7 @@ class C_USERS extends COMPONENT { constructor() { // inject logger, collection and schema object - super("users", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - email: Joi.string().required(), - password: Joi.string().required(), - enabled: Joi.boolean().default(false), - tokens: Joi.array().items(Joi.string()).default([]), - admin: Joi.boolean().default(false), - timestamps: { - //would be greate to have a expiration date for users - //expires: Joi.number().allow(null).default(null) - login: Joi.number().allow(null).default(null), - logout: Joi.number().allow(null).default(null) - } - }, module); + super("users", User.schema(), module); this.hooks.post("add", (data, next) => { next(null, new User(this, data)); diff --git a/components/vault/class.vault.js b/components/vault/class.vault.js index aa33456..38443aa 100644 --- a/components/vault/class.vault.js +++ b/components/vault/class.vault.js @@ -7,6 +7,8 @@ const _debounce = require("../../helper/debounce.js"); const Secret = require("./class.secret.js"); +const Item = require("../../system/component/class.item.js"); + /** * @description * Contains a collection of secrets @@ -22,12 +24,14 @@ const Secret = require("./class.secret.js"); * * @see secret components/vault/class.secret.js */ -class Vault { +module.exports = class Vault extends Item { #privates = new Map(); constructor(obj, scope) { + super(obj); + // create event emitter for lean object let events = new EventEmitter(); this.#privates.set("events", events); @@ -53,8 +57,9 @@ class Vault { } }, Number(process.env.DATABASE_UPDATE_DEBOUNCE_TIMER)); - Object.assign(this, obj); - this._id = String(obj._id); + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); this.secrets = obj.secrets.map((secret) => { return new Secret(secret, () => { @@ -78,12 +83,17 @@ class Vault { _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { return String(new mongodb.ObjectId()); }), - key: Joi.string().required(), - value: Joi.any().required(), - description: Joi.string().required() + name: Joi.string().required(), + identifier: Joi.string().required(), + description: Joi.string().allow(null).default(null), + secrets: Joi.array().items(Secret.schema()).default([]) }); } + static validate(data) { + return Vault.schema().validate(data); + } + /** * @function changes @@ -132,6 +142,4 @@ class Vault { }, {}); } -} - -module.exports = Vault; \ No newline at end of file +}; \ No newline at end of file diff --git a/components/vault/index.js b/components/vault/index.js index 820efdd..485b193 100644 --- a/components/vault/index.js +++ b/components/vault/index.js @@ -1,12 +1,8 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("vault"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); const Vault = require("./class.vault.js"); -const Secret = require("./class.secret.js"); const encrypt = require("./encrypt.js"); @@ -35,14 +31,7 @@ class C_VAULT extends COMPONENT { constructor() { // inject logger, collection and schema object - super("vault", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required(), - identifier: Joi.string().required(), - secrets: Joi.array().items(Secret.schema()).default([]) - }, module); + super("vault", Vault.schema(), module); this.hooks.pre("add", (data, next) => { try { diff --git a/components/webhooks/class.webhook.js b/components/webhooks/class.webhook.js index 331c156..b209803 100644 --- a/components/webhooks/class.webhook.js +++ b/components/webhooks/class.webhook.js @@ -1,3 +1,8 @@ +const Joi = require("joi"); +const mongodb = require("mongodb"); + +const Item = require("../../system/component/class.item.js"); + /** * @description * Represents a webhook item @@ -9,12 +14,15 @@ * @property {String} _id MongoDB Object is as string * @property {String} name Webhook name */ -module.exports = class Webhook { +module.exports = class Webhook extends Item { constructor(obj) { - Object.assign(this, obj); - this._id = String(obj._id); + super(obj); + + // removed for #356 + //Object.assign(this, obj); + //this._id = String(obj._id); Object.defineProperty(this, "_handler", { value: [], @@ -38,6 +46,19 @@ module.exports = class Webhook { } + static schema() { + return Joi.object({ + _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { + return String(new mongodb.ObjectId()); + }), + name: Joi.string().required() + }); + } + + static validate(data) { + return Webhook.schema().validate(data); + } + handle(cb) { this._handler.push(cb); } diff --git a/components/webhooks/index.js b/components/webhooks/index.js index b5f6b10..67afc8d 100644 --- a/components/webhooks/index.js +++ b/components/webhooks/index.js @@ -1,6 +1,3 @@ -const mongodb = require("mongodb"); -const Joi = require("joi"); - //const logger = require("../../system/logger").create("rooms"); //const COMMON_COMPONENT = require("../../system/component/common.js"); const COMPONENT = require("../../system/component/class.component.js"); @@ -18,12 +15,7 @@ class C_WEBHOOKS extends COMPONENT { constructor() { // inject logger, collection and schema object - super("webhooks", { - _id: Joi.string().pattern(/^[0-9a-fA-F]{24}$/).default(() => { - return String(new mongodb.ObjectId()); - }), - name: Joi.string().required() - }, module); + super("webhooks", Webhook.schema(), module); this.hooks.post("add", (data, next) => { next(null, new Webhook(data)); diff --git a/helper/injectMethod.js b/helper/injectMethod.js new file mode 100644 index 0000000..03250d0 --- /dev/null +++ b/helper/injectMethod.js @@ -0,0 +1,35 @@ +/** + * @function injectMethod + * Add a method to a given object into the prototype + * Default values are set to the exact same values when the method would be defined in the object/class body + * + * @param {Object} obj Object to add property to + * @param {String} prop The property name + * @param {*} value Value of the property + * @param {Object} [options={}] Property descriptor options + * @param {Boolean} [options.writable=true] + * @param {Boolean} [options.enumerable=false] + * @param {Boolean} [options.configurable=true] + * + * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#description + */ + +function injectMethod(obj, prop, value, options = {}) { + + if (!(value instanceof Function)) { + throw new TypeError(`Value must be a function, received ${typeof value}`); + } + + // NOTE: Setting on prototype of given object, breaks iface.bridge()... + // Object.defineProperty(Object.getPrototypeOf(obj), prop, { + Object.defineProperty(obj, prop, { + value, + writable: true, + enumerable: false, + configurable: true, + ...options + }); + +} + +module.exports = injectMethod; \ No newline at end of file diff --git a/helper/map.js b/helper/map.js new file mode 100644 index 0000000..7b6324e --- /dev/null +++ b/helper/map.js @@ -0,0 +1,28 @@ +/** + * @function map + * Maps a range to another range + * + * @param {Number} value + * @param {Number} low1 + * @param {Number} high1 + * @param {Number} low2 + * @param {Number} high2 + * + * @example + * ```js + * // convert hex to mb + * console.log(map(255, 0, 255, 0, 1024)); // 1024 + * ``` + * + * @example + * ```js + * console.log(map(128, 0, 255, 0, 1024)); // 512 + * ``` + * + * @returns {Number} Convert input number + */ +function map(value, low1, high1, low2, high2) { + return low2 + (high2 - low2) * (value - low1) / (high1 - low1); +} + +module.exports = map; \ No newline at end of file diff --git a/helper/request.js b/helper/request.js index 6a06e1f..206ef3b 100644 --- a/helper/request.js +++ b/helper/request.js @@ -1,5 +1,7 @@ const url = require("url"); +const promisify = require("./promisify.js"); + /** * Does a http request * @param {*} uri @@ -12,6 +14,11 @@ const url = require("url"); */ function perform(uri, options, cb) { + if(!options && !cb){ + options = {}; + cb = () => {}; + } + let { protocol } = new url.URL(uri); if (!["http:", "https:"].includes(protocol)) { @@ -51,7 +58,9 @@ function perform(uri, options, cb) { cb(null, { headers: res.headers, status: res.statusCode, - body + body, + res, + req: request }); }); @@ -84,17 +93,13 @@ function perform(uri, options, cb) { * @returns {http.ClientRequest} https://nodejs.org/dist/latest-v16.x/docs/api/http.html#class-httpclientrequest */ -module.exports = function request(uri, options, cb) { +function request(uri, options, cb) { if (!cb && options instanceof Function) { cb = options; options = {}; } - if (!cb) { - cb = () => { }; - } - options = Object.assign({ method: "GET", body: "", @@ -103,25 +108,26 @@ module.exports = function request(uri, options, cb) { setKeepAliveHeader: true }, options); + return promisify((done) => { + perform(uri, options, (err, result) => { + if (err) { - return perform(uri, options, (err, result) => { - if (err) { - - cb(err); - - } else { - - if (options.followRedirects && result.status >= 300 && result.status < 400) { - - perform(result.headers.location, options, cb); + done(err); } else { - cb(null, result); + if (options.followRedirects && result.status >= 300 && result.status < 400 && result.headers?.location) { + perform(result.headers.location, options, done); + } else { + done(null, result); + } } + }); + }, cb); - } - }); +} -}; \ No newline at end of file +module.exports = Object.assign(request, { + perform +}); \ No newline at end of file diff --git a/helper/timeout.js b/helper/timeout.js index c55af87..2a84b87 100644 --- a/helper/timeout.js +++ b/helper/timeout.js @@ -58,6 +58,7 @@ function timeout(time, cb) { if (!called) { called = true; + // NOTE: Deconstructing/array recreating needed?! cb(false, Date.now() - start, [...args]); } diff --git a/index.js b/index.js index 2a8cc72..c1cea04 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,10 @@ const path = require("path"); -const http = require("http"); -const fs = require("fs"); const readline = require("readline"); const process = require("process"); -const mongodb = require("mongodb"); const pkg = require("./package.json"); const { exec } = require("child_process"); const uuid = require("uuid"); +const semver = require("semver"); const env = require("dotenv").config({ @@ -57,7 +55,7 @@ process.env = Object.assign({ USERS_BCRYPT_SALT_ROUNDS: "12", USERS_JWT_SECRET: "", USERS_JWT_ALGORITHM: "HS384", - MQTT_BROKER_VERSION: "3", + MQTT_BROKER_VERSION: "4", MQTT_CLIENT_ID: "OpenHaus", MQTT_PING_INTERVAL: "5000" }, env.parsed, process.env); @@ -123,6 +121,12 @@ if (process.env.NODE_ENV !== "production") { } +// see #471 +if (!semver.satisfies(process.versions.node, pkg.engines.node)) { + logger.warn(`> OpenHaus runs not on supported node.js version! (got: "%s", needed: "%s")`, process.versions.node, pkg.engines.node); +} + + if (process.env.GC_INTERVAL !== null && global.gc) { setInterval(() => { try { @@ -140,234 +144,14 @@ if (process.env.GC_INTERVAL !== null && global.gc) { } -const init_db = () => { - return new Promise((resolve, reject) => { - - logger.debug("Init Database..."); - let constr = process.env.DATABASE_URL; - - if (!process.env.DATABASE_URL) { - constr = `mongodb://${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_NAME}`; - } - - // feedback - logger.verbose(`Connecting to "%s"...`, process.env.DATABASE_URL || constr); - - - mongodb.MongoClient.connect(constr, { - useUnifiedTopology: true, - useNewUrlParser: true, - //connectTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000, // #9 - //socketTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000 // #9 - }, (err, client) => { - - if (err) { - logger.error(err, "Could not connect to database"); - return reject(err); - } - - // monky patch db instance - // use this instance in other files - //mongodb.client = client.db(process.env.DATABASE_NAME); - mongodb.connection = client; - mongodb.client = client.db(); - - // feedback - logger.info(`Connected to "%s"`, constr); - - resolve(); - - client.on("error", (err) => { - logger.error(err, "Could not connecto to databse: %s", err.message); - }); - - client.on("close", () => { - process.exit(1000); - }); - - - }); - - }); -}; - - -const init_components = () => { - return new Promise((resolve) => { - - logger.debug("Init components..."); - - const componentNames = [ - "devices", - "endpoints", - "plugins", - "rooms", - "ssdp", - "store", - "users", - "vault", - "webhooks", - "mqtt", - "mdns", - "scenes" - ].sort(() => { - - // pseudo randomize start/init of components - // https://stackoverflow.com/a/18650169/5781499 - return 0.5 - Math.random(); - - }); - - let componentConter = 0; - //let counter = componentNames.length; - - - // map over array - // create from each promise - // use Promise.all() ? - // better/quicker start? - componentNames.forEach((name) => { - try { - - // this should be trace method - logger.verbose(`Starting component "${name}"`); - - let component = require(`./components/${name}/index.js`); - - component.events.on("ready", () => { - - componentConter += 1; - - logger.debug(`Component "${name}" ready to use. (${componentConter}/${componentNames.length})`); - - if (componentConter === componentNames.length) { - logger.info(`All ${componentNames.length} Components ready`); - resolve(); - } - - }); - - // see issue #53, this should fire: - // the procces should not exit with a "unhandled execption" - // the try/catch block is for unhandled exception, not for startup errors - component.events.on("error", (err) => { - logger.error(err, `Component "${name}" error!`); - process.exit(1); // fix #53 - }); - - } catch (err) { - - console.error(err, "Component error"); - process.exit(800); - - } - }); - - }); -}; - - -const init_http = () => { - return new Promise((resolve, reject) => { - - logger.debug("Init http server..."); - - const servers = [ - - // http server for ip/port - new Promise((resolve, reject) => { - if (process.env.HTTP_ADDRESS !== "") { - - let server = http.createServer(); - - server.on("error", (err) => { - logger.error(err, `Could not start http server: ${err.message}`); - reject(err); - }); - - server.on("listening", () => { - - let addr = server.address(); - logger.info(`HTTP Server listening on http://${addr.address}:${addr.port}`); - - resolve(server); - - }); - - require("./routes")(server); - - // bind/start http server - server.listen(Number(process.env.HTTP_PORT), process.env.HTTP_ADDRESS); - - } else { - resolve(); - } - }), - - // http server fo unix socket - new Promise((resolve, reject) => { - if (process.env.HTTP_SOCKET !== "") { - - let server = http.createServer(); - - server.on("error", (err) => { - - logger.error(err, `Could not start http server: ${err.message}`); - reject(err); - - }); - - server.on("listening", () => { - - logger.info(`HTTP Server listening on ${process.env.HTTP_SOCKET}`); - - resolve(server); - - }); - - require("./routes")(server); - - try { - - // cleanup - fs.unlinkSync(process.env.HTTP_SOCKET); - - } catch (err) { - if (err.code !== "ENOENT") { - - reject(err); - - } - } finally { - - // bind/start http server - server.listen(process.env.HTTP_SOCKET); - - } - - } else { - resolve(); - } - }) - - ]; - - Promise.all(servers).then(() => { - - resolve(); - - }).catch((err) => { - - logger.error(err, "Could not start http server(s)", err); - - reject(err); - - }); - - }); -}; +const init_db = require("./system/init/init.database.js")(logger); +const init_components = require("./system/init/init.components.js")(logger); +const init_http = require("./system/init/init.http-server.js")(logger); +// NOTE: Could/should be removed +// was only used in the early state of developing without the plugin component/system +/* const kickstart = () => { try { @@ -389,6 +173,7 @@ const kickstart = () => { } }; +*/ const starter = new Promise((resolve) => { @@ -426,7 +211,7 @@ const starter = new Promise((resolve) => { init_db, // phase 1 init_components, // phase 2 init_http, // phase 3 - kickstart + //kickstart ].reduce((cur, prev, i) => { return cur.then(prev).catch((err) => { @@ -475,7 +260,7 @@ const starter = new Promise((resolve) => { } catch (err) { - logger.warn(`Could not boot plugin "${plugin.name}" (${plugin.uuid})`); + logger.error(err, `Could not boot plugin "${plugin.name}" (${plugin.uuid})`); } }); @@ -488,4 +273,13 @@ const starter = new Promise((resolve) => { logger.info("Startup complete"); + // fix #435 + ["SIGINT", /*"SIGTERM", "SIGQUIT"*/].forEach((signal) => { + process.once(signal, () => { + + logger.warn("Shuting down..."); + + }); + }); + }); diff --git a/package-lock.json b/package-lock.json index 7c675f4..aa307e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "backend", - "version": "2.0.0", + "version": "2.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "backend", - "version": "2.0.0", + "version": "2.2.0", "hasInstallScript": true, "license": "ISC", "dependencies": { @@ -21,6 +21,8 @@ "jsonwebtoken": "^9.0.0", "mongodb": "^4.11.0", "mqtt-packet": "^8.1.2", + "semver": "^7.5.4", + "tar-stream": "^3.1.7", "uuid": "^9.0.0", "ws": "^8.10.0" }, @@ -31,21 +33,39 @@ "grunt-contrib-uglify": "^5.0.1", "grunt-env": "^1.0.1", "grunt-run": "^0.8.1", + "husky": "^8.0.3", "minimist": "^1.2.6", "mocha": "^9.2.2", "mocha.parallel": "^0.15.6", - "newman": "^5.3.2", - "nodemon": "^2.0.19", + "newman": "^6.0.0", + "nodemon": "^3.0.1", "sinon": "^14.0.2" }, "engines": { "node": ">=0.16.0" } }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, "node_modules/@aws-crypto/ie11-detection": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", - "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, "dependencies": { "tslib": "^1.11.1" @@ -58,16 +78,16 @@ "optional": true }, "node_modules/@aws-crypto/sha256-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", - "integrity": "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, "dependencies": { - "@aws-crypto/ie11-detection": "^2.0.0", - "@aws-crypto/sha256-js": "^2.0.0", - "@aws-crypto/supports-web-crypto": "^2.0.0", - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" @@ -80,13 +100,13 @@ "optional": true }, "node_modules/@aws-crypto/sha256-js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz", - "integrity": "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, "dependencies": { - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" } }, @@ -97,9 +117,9 @@ "optional": true }, "node_modules/@aws-crypto/supports-web-crypto": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.2.tgz", - "integrity": "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, "dependencies": { "tslib": "^1.11.1" @@ -112,12 +132,12 @@ "optional": true }, "node_modules/@aws-crypto/util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-2.0.2.tgz", - "integrity": "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, "dependencies": { - "@aws-sdk/types": "^3.110.0", + "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" } @@ -128,1196 +148,1397 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "optional": true }, - "node_modules/@aws-sdk/abort-controller": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.193.0.tgz", - "integrity": "sha512-MYPBm5PWyKP+Tq37mKs5wDbyAyVMocF5iYmx738LYXBSj8A1V4LTFrvfd4U16BRC/sM0DYB9fBFJUQ9ISFRVYw==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.196.0.tgz", - "integrity": "sha512-EwO3G3YPQuT1nkzaVByfoyV1Jyx1WVmbt3HH5nIQDP2bgKCPkq8mytiSS14H0VyejGHmc8/1wZ7Q/MRPosdgEg==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.196.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=12.0.0" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.423.0.tgz", + "integrity": "sha512-9nyilMrihznN7Y6T/dVhbg4YGsdk7szzShoyoSGwofOg61ugobnHbBvh0tPPOQcHhlzXvD8LZdOQ6Kd4KvNp/A==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.423.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.196.0.tgz", - "integrity": "sha512-u+UnxrVHLjLDdfCZft1AuyIhyv+77/inCHR4LcKsGASRA+jAg3z+OY+B7Q9hWHNcVt5ECMw7rxe4jA9BLf42sw==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=12.0.0" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.423.0.tgz", + "integrity": "sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.196.0.tgz", - "integrity": "sha512-ChzK8606CugwnRLm7iwerXzeMqOsjGLe3j1j1HtQShzXZu4/ysQ3mUBBPAt2Lltx+1ep8MoI9vaQVyfw5h35ww==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-sdk-sts": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@aws-sdk/config-resolver": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.193.0.tgz", - "integrity": "sha512-HIjuv2A1glgkXy9g/A8bfsiz3jTFaRbwGZheoHFZod6iEQQEbbeAsBe3u2AZyzOrVLgs8lOvBtgU8XKSJWjDkw==", - "optional": true, - "dependencies": { - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-config-provider": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.423.0.tgz", + "integrity": "sha512-EcpkKu02QZbRX6dQE0u7a8RgWrn/5riz1qAlKd7rM8FZJpr/D6GGX8ZzWxjgp7pRUgfNvinTmIudDnyQY3v9Mg==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-sdk-sts": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.196.0.tgz", - "integrity": "sha512-yXpb8kx1RpHRJty6MNX3ssTu0h3SYZVpUinQtBXPdHoVZ5/DyF/KGd2jr0LWYrgTx8G42GHTltz3Ss4nYjosnQ==", + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.423.0.tgz", + "integrity": "sha512-FuuCOeUkAn3tZU2GUN3eUjs4AC88t5je4N5/NVbTaSN0e2FGf9PnN5nrwTKwaOGVLSe6/FvfudW01LZ/+PRQOQ==", "optional": true, "dependencies": { - "@aws-sdk/client-cognito-identity": "3.196.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/client-cognito-identity": "3.423.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.193.0.tgz", - "integrity": "sha512-pRqZoIaqCdWB4JJdR6DqDn3u+CwKJchwiCPnRtChwC8KXCMkT4njq9J1bWG3imYeTxP/G06O1PDONEuD4pPtNQ==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz", + "integrity": "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/credential-provider-imds": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.193.0.tgz", - "integrity": "sha512-jC7uT7uVpO/iitz49toHMGFKXQ2igWQQG2SKirREqDRaz5HSXwEP1V3rcOlNNyGIBPMggDjZnxYgJHqBXSq9Ag==", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.423.0.tgz", + "integrity": "sha512-y/mutbiCU/4HGN/ChcNBhPaXo4pgg6lAcWyuMTSSfAR03hjoXe1cMwbPcUiEwzQrZ/+1yufLpZhmoiAWsgAkNw==", "optional": true, "dependencies": { - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.196.0.tgz", - "integrity": "sha512-3lL+YLBQ9KwQxG4AdRm4u2cvBNZeBmS/i3BWnCPomg96lNGPMrTEloVaVEpnrzOff6sgFxRtjkbLkVxmdipIrw==", - "optional": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.423.0.tgz", + "integrity": "sha512-7CsFWz8g7dQmblp57XzzxMirO4ClowGZIOwAheBkmk6q1XHbllcHFnbh2kdPyQQ0+JmjDg6waztIc7dY7Ycfvw==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.196.0.tgz", - "integrity": "sha512-PGY7pkmqgfEwTHsuUH6fGrXWri93jqKkMbhq/QJafMGtsVupfvXvE37Rl+qgjsZjRfROrEaeLw2DGrPPmVh2cg==", - "optional": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-ini": "3.196.0", - "@aws-sdk/credential-provider-process": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.423.0.tgz", + "integrity": "sha512-lygbGJJUnDpgo8OEqdoYd51BKkyBVQ1Catiua/m0aHvL+SCmVrHiYPQPawWYGxpH8X3DXdXa0nd0LkEaevrHRg==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.423.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.193.0.tgz", - "integrity": "sha512-zpXxtQzQqkaUuFqmHW9dSkh9p/1k+XNKlwEkG8FTwAJNUWmy2ZMJv+8NTVn4s4vaRu7xJ1er9chspYr7mvxHlA==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz", + "integrity": "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.196.0.tgz", - "integrity": "sha512-hJV4LDVfvPfj5zC0ysHx3zkwwJOyF+BaMGaMzaScrHyijv5e3qZzdoBLbOQFmrqVnt7DjCU02NvRSS8amLpmSw==", + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.423.0.tgz", + "integrity": "sha512-zAH68IjRMmW22USbsCVQ5Q6AHqhmWABwLbZAMocSGMasddTGv/nkA/nUiVCJ/B4LI3P81FoPQVrG5JxNmkNH0w==", "optional": true, "dependencies": { - "@aws-sdk/client-sso": "3.196.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/client-sso": "3.423.0", + "@aws-sdk/token-providers": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.193.0.tgz", - "integrity": "sha512-MIQY9KwLCBnRyIt7an4EtMrFQZz2HC1E8vQDdKVzmeQBBePhW61fnX9XDP9bfc3Ypg1NggLG00KBPEC88twLFg==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz", + "integrity": "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.196.0.tgz", - "integrity": "sha512-IE2Lq0EMCkPqvh0on6Dfg5Nofcm2hbsDH8etQNKRpvZ/K8elz1aArh2gcL9F01smrJChAHWwD8uZbk/eQ/Zf2w==", - "optional": true, - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.196.0", - "@aws-sdk/client-sso": "3.196.0", - "@aws-sdk/client-sts": "3.196.0", - "@aws-sdk/credential-provider-cognito-identity": "3.196.0", - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-ini": "3.196.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/credential-provider-process": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@aws-sdk/fetch-http-handler": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.193.0.tgz", - "integrity": "sha512-UhIS2LtCK9hqBzYVon6BI8WebJW1KC0GGIL/Gse5bqzU9iAGgFLAe66qg9k+/h3Jjc5LNAYzqXNVizMwn7689Q==", - "optional": true, - "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/querystring-builder": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/hash-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.193.0.tgz", - "integrity": "sha512-O2SLPVBjrCUo+4ouAdRUoHBYsyurO9LcjNZNYD7YQOotBTbVFA3cx7kTZu+K4B6kX7FDaGbqbE1C/T1/eg/r+w==", + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.423.0.tgz", + "integrity": "sha512-jsjIrnu+bVUz2lekcg9wxpPlO8jWd9q26MP/rRwdkm9LHqroICjZY7tIYqSJliVkeSyJHJ9pq/jNDceWhy6a0A==", "optional": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" + "@aws-sdk/client-cognito-identity": "3.423.0", + "@aws-sdk/client-sso": "3.423.0", + "@aws-sdk/client-sts": "3.423.0", + "@aws-sdk/credential-provider-cognito-identity": "3.423.0", + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-http": "3.423.0", + "@aws-sdk/credential-provider-ini": "3.423.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/invalid-dependency": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.193.0.tgz", - "integrity": "sha512-54DCknekLwJAI1os76XJ8XCzfAH7BGkBGtlWk5WCNkZTfj3rf5RUiXz4uoKUMWE1rZmyMDoDDS1PBo+yTVKW5w==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/is-array-buffer": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.188.0.tgz", - "integrity": "sha512-n69N4zJZCNd87Rf4NzufPzhactUeM877Y0Tp/F3KiHqGeTnVjYUa4Lv1vLBjqtfjYb2HWT3NKlYn5yzrhaEwiQ==", + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz", + "integrity": "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-content-length": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.193.0.tgz", - "integrity": "sha512-em0Sqo7O7DFOcVXU460pbcYuIjblDTZqK2YE62nQ0T+5Nbj+MSjuoite+rRRdRww9VqBkUROGKON45bUNjogtQ==", + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz", + "integrity": "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==", "optional": true, "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.193.0.tgz", - "integrity": "sha512-Inbpt7jcHGvzF7UOJOCxx9wih0+eAQYERikokidWJa7M405EJpVYq1mGbeOcQUPANU3uWF1AObmUUFhbkriHQw==", + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz", + "integrity": "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==", "optional": true, "dependencies": { - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-config-provider": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.193.0.tgz", - "integrity": "sha512-aegzj5oRWd//lmfmkzRmgG2b4l3140v8Ey4QkqCxcowvAEX5a7rh23yuKaGtmiePwv2RQalCKz+tN6JXCm8g6Q==", + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz", + "integrity": "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==", "optional": true, "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.193.0.tgz", - "integrity": "sha512-D/h1pU5tAcyJpJ8ZeD1Sta0S9QZPcxERYRBiJdEl8VUrYwfy3Cl1WJedVOmd5nG73ZLRSyHeXHewb/ohge3yKQ==", + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz", + "integrity": "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==", "optional": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.193.0.tgz", - "integrity": "sha512-fMWP76Q1GOb/9OzS1arizm6Dbfo02DPZ6xp7OoAN3PS6ybH3Eb47s/gP3jzgBPAITQacFj4St/4a06YWYrN3NA==", - "optional": true, - "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz", + "integrity": "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz", + "integrity": "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz", + "integrity": "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-retry": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.193.0.tgz", - "integrity": "sha512-zTQkHLBQBJi6ns655WYcYLyLPc1tgbEYU080Oc8zlveLUqoDn1ogkcmNhG7XMeQuBvWZBYN7J3/wFaXlDzeCKg==", + "node_modules/@aws-sdk/types": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz", + "integrity": "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==", "optional": true, "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/service-error-classification": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@aws-sdk/middleware-retry/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-sts": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.193.0.tgz", - "integrity": "sha512-TafiDkeflUsnbNa89TLkDnAiRRp1gAaZLDAjt75AzriRKZnhtFfYUXWb+qAuN50T+CkJ/gZI9LHDZL5ogz/HxQ==", + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz", + "integrity": "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==", "optional": true, "dependencies": { - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-serde": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.193.0.tgz", - "integrity": "sha512-dH93EJYVztY+ZDPzSMRi9LfAZfKO+luH62raNy49hlNa4jiyE1Tc/+qwlmOEpfGsrtcZ9TgsON1uFF9sgBXXaA==", + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "optional": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.193.0.tgz", - "integrity": "sha512-obBoELGPf5ikvHYZwbzllLeuODiokdDfe92Ve2ufeOa/d8+xsmbqNzNdCTLNNTmr1tEIaEE7ngZVTOiHqAVhyw==", + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz", + "integrity": "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" } }, - "node_modules/@aws-sdk/middleware-stack": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.193.0.tgz", - "integrity": "sha512-Ix5d7gE6bZwFNIVf0dGnjYuymz1gjitNoAZDPpv1nEZlUMek/jcno5lmzWFzUZXY/azpbIyaPwq/wm/c69au5A==", + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz", + "integrity": "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.193.0.tgz", - "integrity": "sha512-0vT6F9NwYQK7ARUUJeHTUIUPnupsO3IbmjHSi1+clkssFlJm2UfmSGeafiWe4AYH3anATTvZEtcxX5DZT/ExbA==", - "optional": true, - "dependencies": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "node": ">=14.0.0" }, - "engines": { - "node": ">= 12.0.0" + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/node-config-provider": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.193.0.tgz", - "integrity": "sha512-5RLdjQLH69ISRG8TX9klSLOpEySXxj+z9E9Em39HRvw0/rDcd8poCTADvjYIOqRVvMka0z/hm+elvUTIVn/DRw==", + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" } }, - "node_modules/@aws-sdk/node-http-handler": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.193.0.tgz", - "integrity": "sha512-DP4BmFw64HOShgpAPEEMZedVnRmKKjHOwMEoXcnNlAkMXnYUFHiKvudYq87Q2AnSlT6OHkyMviB61gEvIk73dA==", + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, "optional": true, - "dependencies": { - "@aws-sdk/abort-controller": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/querystring-builder": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - }, "engines": { - "node": ">= 12.0.0" + "node": ">=0.1.90" } }, - "node_modules/@aws-sdk/property-provider": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.193.0.tgz", - "integrity": "sha512-IaDR/PdZjKlAeSq2E/6u6nkPsZF9wvhHZckwH7uumq4ocWsWXFzaT+hKpV4YZPHx9n+K2YV4Gn/bDedpz99W1Q==", - "optional": true, + "node_modules/@eslint/eslintrc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "dev": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">= 12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@aws-sdk/protocol-http": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.193.0.tgz", - "integrity": "sha512-r0wbTwFJyXq0uiImI6giqG3g/RO1N/y4wwPA7qr7OC+KXJ0NkyVxIf6e7Vx8h06aM1ATtngbwJaMP59kVCp85A==", - "optional": true, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "ms": "2.1.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@aws-sdk/querystring-builder": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.193.0.tgz", - "integrity": "sha512-PRaK6649iw0UO45UjUoiUzFcOKXZb8pMjjFJpqALpEvdZT3twxqhlPXujT7GWPKrSwO4uPLNnyYEtPY82wx2vw==", - "optional": true, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@faker-js/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", + "dev": true + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", "dependencies": { - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-uri-escape": "3.188.0", - "tslib": "^2.3.1" - }, - "engines": { - "node": ">= 12.0.0" + "@hapi/hoek": "^9.0.0" } }, - "node_modules/@aws-sdk/querystring-parser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.193.0.tgz", - "integrity": "sha512-dGEPCe8SK4/td5dSpiaEI3SvT5eHXrbJWbLGyD4FL3n7WCGMy2xVWAB/yrgzD0GdLDjDa8L5vLVz6yT1P9i+hA==", - "optional": true, + "node_modules/@humanwhocodes/config-array": { + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "dev": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" }, "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@aws-sdk/service-error-classification": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.193.0.tgz", - "integrity": "sha512-bPnXVu8ErE1RfWVVQKc2TE7EuoImUi4dSPW9g80fGRzJdQNwXb636C+7OUuWvSDzmFwuBYqZza8GZjVd+rz2zQ==", - "optional": true, - "engines": { - "node": ">= 12.0.0" + "node": ">=10.10.0" } }, - "node_modules/@aws-sdk/shared-ini-file-loader": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.193.0.tgz", - "integrity": "sha512-hnvZup8RSpFXfah7Rrn6+lQJnAOCO+OiDJ2R/iMgZQh475GRQpLbu3cPhCOkjB14vVLygJtW8trK/0+zKq93bQ==", - "optional": true, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "ms": "2.1.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@aws-sdk/signature-v4": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.193.0.tgz", - "integrity": "sha512-JEqqOB8wQZz6g1ERNUOIBFDFt8OJtz5G5Uh1CdkS5W66gyWnJEz/dE1hA2VTqqQwHGGEsIEV/hlzruU1lXsvFA==", + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", "optional": true, "dependencies": { - "@aws-sdk/is-array-buffer": "3.188.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-hex-encoding": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "@aws-sdk/util-uri-escape": "3.188.0", - "tslib": "^2.3.1" + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 8" } }, - "node_modules/@aws-sdk/smithy-client": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.193.0.tgz", - "integrity": "sha512-BY0jhfW76vyXr7ODMaKO3eyS98RSrZgOMl6DTQV9sk7eFP/MPVlG7p7nfX/CDIgPBIO1z0A0i2CVIzYur9uGgQ==", - "optional": true, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">= 8" } }, - "node_modules/@aws-sdk/types": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.193.0.tgz", - "integrity": "sha512-LV/wcPolRZKORrcHwkH59QMCkiDR5sM+9ZtuTxvyUGG2QFW/kjoxs08fUF10OWNJMrotBI+czDc5QJRgN8BlAw==", - "optional": true, + "node_modules/@postman/form-data": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", + "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, "engines": { - "node": ">= 12.0.0" + "node": ">= 6" } }, - "node_modules/@aws-sdk/url-parser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.193.0.tgz", - "integrity": "sha512-hwD1koJlOu2a6GvaSbNbdo7I6a3tmrsNTZr8bCjAcbqpc5pDThcpnl/Uaz3zHmMPs92U8I6BvWoK6pH8By06qw==", - "optional": true, + "node_modules/@postman/tough-cookie": { + "version": "4.1.3-postman.1", + "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", + "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", + "dev": true, "dependencies": { - "@aws-sdk/querystring-parser": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" } }, - "node_modules/@aws-sdk/util-base64-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-browser/-/util-base64-browser-3.188.0.tgz", - "integrity": "sha512-qlH+5NZBLiyKziL335BEPedYxX6j+p7KFRWXvDQox9S+s+gLCayednpK+fteOhBenCcR9fUZOVuAPScy1I8qCg==", - "optional": true, + "node_modules/@postman/tunnel-agent": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", + "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", + "dev": true, "dependencies": { - "tslib": "^2.3.1" + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@aws-sdk/util-base64-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-3.188.0.tgz", - "integrity": "sha512-r1dccRsRjKq+OhVRUfqFiW3sGgZBjHbMeHLbrAs9jrOjU2PTQ8PSzAXLvX/9lmp7YjmX17Qvlsg0NCr1tbB9OA==", + "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", + "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.10.tgz", + "integrity": "sha512-xn7PnFD3m4rQIG00h1lPuDVnC2QMtTFhzRLX3y56KkgFaCysS7vpNevNBgmNUtmJ4eVFc+66Zucwo2KDLdicOg==", "optional": true, "dependencies": { - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-body-length-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", - "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "node_modules/@smithy/config-resolver": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.11.tgz", + "integrity": "sha512-q97FnlUmbai1c4JlQJgLVBsvSxgV/7Nvg/JK76E1nRq/U5UM56Eqo3dn2fY7JibqgJLg4LPsGdwtIyqyOk35CQ==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-body-length-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.188.0.tgz", - "integrity": "sha512-XwqP3vxk60MKp4YDdvDeCD6BPOiG2e+/Ou4AofZOy5/toB6NKz2pFNibQIUg2+jc7mPMnGnvOW3MQEgSJ+gu/Q==", + "node_modules/@smithy/credential-provider-imds": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.13.tgz", + "integrity": "sha512-/xe3wNoC4j+BeTemH9t2gSKLBfyZmk8LXB2pQm/TOEYi+QhBgT+PSolNDfNAhrR68eggNE17uOimsrnwSkCt4w==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-buffer-from": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.188.0.tgz", - "integrity": "sha512-NX1WXZ8TH20IZb4jPFT2CnLKSqZWddGxtfiWxD9M47YOtq/SSQeR82fhqqVjJn4P8w2F5E28f+Du4ntg/sGcxA==", + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.10.tgz", + "integrity": "sha512-3SSDgX2nIsFwif6m+I4+ar4KDcZX463Noes8ekBgQHitULiWvaDZX8XqPaRQSQ4bl1vbeVXHklJfv66MnVO+lw==", "optional": true, "dependencies": { - "@aws-sdk/is-array-buffer": "3.188.0", - "tslib": "^2.3.1" + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.1.tgz", + "integrity": "sha512-bXyM8PBAIKxVV++2ZSNBEposTDjFQ31XWOdHED+2hWMNvJHUoQqFbECg/uhcVOa6vHie2/UnzIZfXBSTpDBnEw==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.10.tgz", + "integrity": "sha512-jSTf6uzPk/Vf+8aQ7tVXeHfjxe9wRXSCqIZcBymSDTf7/YrVxniBdpyN74iI8ZUOx/Pyagc81OK5FROLaEjbXQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-config-provider": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.188.0.tgz", - "integrity": "sha512-LBA7tLbi7v4uvbOJhSnjJrxbcRifKK/1ZVK94JTV2MNSCCyNkFotyEI5UWDl10YKriTIUyf7o5cakpiDZ3O4xg==", + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.10.tgz", + "integrity": "sha512-zw9p/zsmJ2cFcW4KMz3CJoznlbRvEA6HG2mvEaX5eAca5dq4VGI2MwPDTfmteC/GsnURS4ogoMQ0p6aHM2SDVQ==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-defaults-mode-browser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.193.0.tgz", - "integrity": "sha512-9riQKFrSJcsNAMnPA/3ltpSxNykeO20klE/UKjxEoD7UWjxLwsPK22UJjFwMRaHoAFcZD0LU/SgPxbC0ktCYCg==", + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.12.tgz", + "integrity": "sha512-QRhJTo5TjG7oF7np6yY4ZO9GDKFVzU/GtcqUqyEa96bLHE3yZHgNmsolOQ97pfxPHmFhH4vDP//PdpAIN3uI1Q==", "optional": true, "dependencies": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "bowser": "^2.11.0", - "tslib": "^2.3.1" + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-defaults-mode-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.193.0.tgz", - "integrity": "sha512-occQmckvPRiM4YQIZnulfKKKjykGKWloa5ByGC5gOEGlyeP9zJpfs4zc/M2kArTAt+d2r3wkBtsKe5yKSlVEhA==", + "node_modules/@smithy/middleware-endpoint": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.10.tgz", + "integrity": "sha512-O6m4puZc16xfenotZUHL4bRlMrwf4gTp+0I5l954M5KNd3dOK18P+FA/IIUgnXF/dX6hlCUcJkBp7nAzwrePKA==", "optional": true, "dependencies": { - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@smithy/middleware-serde": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.196.0.tgz", - "integrity": "sha512-X+DOpRUy/ij49a0GQtggk09oyIQGn0mhER6PbMT69IufZPIg3D5fC5FPEp8bfsPkb70fTEYQEsj/X/rgMQJKsA==", + "node_modules/@smithy/middleware-retry": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.13.tgz", + "integrity": "sha512-zuOva8xgWC7KYG8rEXyWIcZv2GWszO83DCTU6IKcf/FKu6OBmSE+EYv3EUcCGY+GfiwCX0EyJExC9Lpq9b0w5Q==", "optional": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@smithy/node-config-provider": "^2.0.13", + "@smithy/protocol-http": "^3.0.6", + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-retry": "^2.0.3", + "tslib": "^2.5.0", + "uuid": "^8.3.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/@aws-sdk/util-hex-encoding": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.188.0.tgz", - "integrity": "sha512-QyWovTtjQ2RYxqVM+STPh65owSqzuXURnfoof778spyX4iQ4z46wOge1YV2ZtwS8w5LWd9eeVvDrLu5POPYOnA==", + "node_modules/@smithy/middleware-serde": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.10.tgz", + "integrity": "sha512-+A0AFqs768256H/BhVEsBF6HijFbVyAwYRVXY/izJFkTalVWJOp4JA0YdY0dpXQd+AlW0tzs+nMQCE1Ew+DcgQ==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.188.0.tgz", - "integrity": "sha512-SxobBVLZkkLSawTCfeQnhVX3Azm9O+C2dngZVe1+BqtF8+retUbVTs7OfYeWBlawVkULKF2e781lTzEHBBjCzw==", + "node_modules/@smithy/middleware-stack": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.4.tgz", + "integrity": "sha512-MW0KNKfh8ZGLagMZnxcLJWPNXoKqW6XV/st5NnCBmmA2e2JhrUjU0AJ5Ca/yjTyNEKs3xH7AQDwp1YmmpEpmQQ==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-middleware": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.193.0.tgz", - "integrity": "sha512-+aC6pmkcGgpxaMWCH/FXTsGWl2W342oQGs1OYKGi+W8z9UguXrqamWjdkdMqgunvj9qOEG2KBMKz1FWFFZlUyA==", + "node_modules/@smithy/node-config-provider": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.13.tgz", + "integrity": "sha512-pPpLqYuJcOq1sj1EGu+DoZK47DUS4gepqSTNgRezmrjnzNlSU2/Dcc9Ebzs+WZ0Z5vXKazuE+k+NksFLo07/AA==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/property-provider": "^2.0.11", + "@smithy/shared-ini-file-loader": "^2.0.12", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-uri-escape": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.188.0.tgz", - "integrity": "sha512-4Y6AYZMT483Tiuq8dxz5WHIiPNdSFPGrl6tRTo2Oi2FcwypwmFhqgEGcqxeXDUJktvaCBxeA08DLr/AemVhPCg==", + "node_modules/@smithy/node-http-handler": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.6.tgz", + "integrity": "sha512-NspvD3aCwiUNtoSTcVHz0RZz1tQ/SaRIe1KPF+r0mAdCZ9eWuhIeJT8ZNPYa1ITn7/Lgg64IyFjqPynZ8KnYQw==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/abort-controller": "^2.0.10", + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.193.0.tgz", - "integrity": "sha512-1EkGYsUtOMEyJG/UBIR4PtmO3lVjKNoUImoMpLtEucoGbWz5RG9zFSwLevjFyFs5roUBFlxkSpTMo8xQ3aRzQg==", + "node_modules/@smithy/property-provider": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.11.tgz", + "integrity": "sha512-kzuOadu6XvrnlF1iXofpKXYmo4oe19st9/DE8f5gHNaFepb4eTkR8gD8BSdTnNnv7lxfv6uOwZPg4VS6hemX1w==", "optional": true, "dependencies": { - "@aws-sdk/types": "3.193.0", - "bowser": "^2.11.0", - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.193.0.tgz", - "integrity": "sha512-G/2/1cSgsxVtREAm8Eq8Duib5PXzXknFRHuDpAxJ5++lsJMXoYMReS278KgV54cojOkAVfcODDTqmY3Av0WHhQ==", + "node_modules/@smithy/protocol-http": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.6.tgz", + "integrity": "sha512-F0jAZzwznMmHaggiZgc7YoS08eGpmLvhVktY/Taz6+OAOHfyIqWSDNgFqYR+WHW9z5fp2XvY4mEUrQgYMQ71jw==", "optional": true, "dependencies": { - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.188.0.tgz", - "integrity": "sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==", + "node_modules/@smithy/querystring-builder": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.10.tgz", + "integrity": "sha512-uujJGp8jzrrU1UHme8sUKEbawQTcTmUWsh8rbGXYD/lMwNLQ+9jQ9dMDWbbH9Hpoa9RER1BeL/38WzGrbpob2w==", "optional": true, "dependencies": { - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/util-utf8-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-3.188.0.tgz", - "integrity": "sha512-hCgP4+C0Lekjpjt2zFJ2R/iHes5sBGljXa5bScOFAEkRUc0Qw0VNgTv7LpEbIOAwGmqyxBoCwBW0YHPW1DfmYQ==", + "node_modules/@smithy/querystring-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.10.tgz", + "integrity": "sha512-WSD4EU60Q8scacT5PIpx4Bahn6nWpt+MiYLcBkFt6fOj7AssrNeaNIU2Z0g40ftVmrwLcEOIKGX92ynbVDb3ZA==", "optional": true, "dependencies": { - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", - "dev": true, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.3.tgz", + "integrity": "sha512-b+m4QCHXb7oKAkM/jHwHrl5gpqhFoMTHF643L0/vAEkegrcUWyh1UjyoHttuHcP5FnHVVy4EtpPtLkEYD+xMFw==", + "optional": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@smithy/types": "^2.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=14.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.12.tgz", + "integrity": "sha512-umi0wc4UBGYullAgYNUVfGLgVpxQyES47cnomTqzCKeKO5oudO4hyDNj+wzrOjqDFwK2nWYGVgS8Y0JgGietrw==", + "optional": true, "dependencies": { - "ms": "2.1.2" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=14.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "node_modules/@smithy/signature-v4": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.10.tgz", + "integrity": "sha512-S6gcP4IXfO/VMswovrhxPpqvQvMal7ZRjM4NvblHSPpE5aNBYx67UkHFF3kg0hR3tJKqNpBGbxwq0gzpdHKLRA==", + "optional": true, "dependencies": { - "@hapi/hoek": "^9.0.0" + "@smithy/eventstream-codec": "^2.0.10", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", - "dev": true, + "node_modules/@smithy/smithy-client": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.9.tgz", + "integrity": "sha512-HTicQSn/lOcXKJT+DKJ4YMu51S6PzbWsO8Z6Pwueo30mSoFKXg5P0BDkg2VCDqCVR0mtddM/F6hKhjW6YAV/yg==", + "optional": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@smithy/middleware-stack": "^2.0.4", + "@smithy/types": "^2.3.4", + "@smithy/util-stream": "^2.0.14", + "tslib": "^2.5.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=14.0.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, + "node_modules/@smithy/types": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.4.tgz", + "integrity": "sha512-D7xlM9FOMFyFw7YnMXn9dK2KuN6+JhnrZwVt1fWaIu8hCk5CigysweeIT/H/nCo4YV+s8/oqUdLfexbkPZtvqw==", + "optional": true, "dependencies": { - "ms": "2.1.2" + "tslib": "^2.5.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=14.0.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "node_modules/@smithy/url-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.10.tgz", + "integrity": "sha512-4TXQFGjHcqru8aH5VRB4dSnOFKCYNX6SR1Do6fwxZ+ExT2onLsh2W77cHpks7ma26W5jv6rI1u7d0+KX9F0aOw==", + "optional": true, + "dependencies": { + "@smithy/querystring-parser": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" + "node_modules/@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + } }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "optional": true, "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" + "tslib": "^2.5.0" }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "optional": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.13.tgz", + "integrity": "sha512-UmmOdUzaQjqdsl1EjbpEaQxM0VDFqTj6zDuI26/hXN7L/a1k1koTwkYpogHMvunDX3fjrQusg5gv1Td4UsGyog==", + "optional": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "bowser": "^2.11.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 8" + "node": ">= 10.0.0" } }, - "node_modules/@postman/form-data": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", - "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", - "dev": true, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.15.tgz", + "integrity": "sha512-g6J7MHAibVPMTlXyH3mL+Iet4lMJKFVhsOhJmn+IKG81uy9m42CkRSDlwdQSJAcprLQBIaOPdFxNXQvrg2w1Uw==", + "optional": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@smithy/config-resolver": "^2.0.11", + "@smithy/credential-provider-imds": "^2.0.13", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 6" + "node": ">= 10.0.0" } }, - "node_modules/@postman/tunnel-agent": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", - "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", - "dev": true, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "optional": true, "dependencies": { - "safe-buffer": "^5.0.1" + "tslib": "^2.5.0" }, "engines": { - "node": "*" + "node": ">=14.0.0" } }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "node_modules/@smithy/util-middleware": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.3.tgz", + "integrity": "sha512-+FOCFYOxd2HO7v/0hkFSETKf7FYQWa08wh/x/4KUeoVBnLR4juw8Qi+TTqZI6E2h5LkzD9uOaxC9lAjrpVzaaA==", + "optional": true, "dependencies": { - "@hapi/hoek": "^9.0.0" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, + "node_modules/@smithy/util-retry": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.3.tgz", + "integrity": "sha512-gw+czMnj82i+EaH7NL7XKkfX/ZKrCS2DIWwJFPKs76bMgkhf0y1C94Lybn7f8GkBI9lfIOUdPYtzm19zQOC8sw==", + "optional": true, "dependencies": { - "type-detect": "4.0.8" + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, + "node_modules/@smithy/util-stream": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.14.tgz", + "integrity": "sha512-XjvlDYe+9DieXhLf7p+EgkXwFtl34kHZcWfHnc5KaILbhyVfDLWuqKTFx6WwCFqb01iFIig8trGwExRIqqkBYg==", + "optional": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", - "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", - "dev": true, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "optional": true, "dependencies": { - "type-detect": "4.0.8" + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@sinonjs/samsam": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", - "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", - "dev": true, + "node_modules/@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "optional": true, "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, "node_modules/@types/node": { - "version": "18.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.6.tgz", - "integrity": "sha512-j3CEDa2vd96K0AXF8Wur7UucACvnjkk8hYyQAHhUNciabZLDl9nfAEVUSwmh245OOZV15bRA3Y590Gi5jUcDJg==" + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" }, "node_modules/@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.1.tgz", + "integrity": "sha512-8hKOnOan+Uu+NgMaCouhg3cT9x5fFZ92Jwf+uDLXLu/MFRbXxlWwGeQY7KVHkeSft6RvY+tdxklUBuyY9eIEKg==" }, "node_modules/@types/whatwg-url": { "version": "8.2.2", @@ -1548,6 +1769,33 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/archiver/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/archiver/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", @@ -1638,16 +1886,27 @@ } }, "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz", + "integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==", + "optional": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1803,9 +2062,9 @@ "dev": true }, "node_modules/bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", "dependencies": { "buffer": "^5.6.0" }, @@ -1914,9 +2173,9 @@ } }, "node_modules/chardet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", - "integrity": "sha512-NpwMDdSIprbYx1CLnfbxEIarI0Z+s9MssEgggMNheGM+WD68yOhV7IEA/3r6tr0yTRgQD0HuZJDw32s99i6L+A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.6.0.tgz", + "integrity": "sha512-+QOTw3otC4+FxdjK9RopGpNOglADbr4WPFi0SonkO99JbpkTPbMxmdm4NenhF5Zs+4gPXLI1+y2uazws5TMe8w==", "dev": true }, "node_modules/charset": { @@ -1976,21 +2235,21 @@ } }, "node_modules/cli-progress": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", - "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", "dev": true, "dependencies": { - "string-width": "^4.2.0" + "string-width": "^4.2.3" }, "engines": { "node": ">=4" } }, "node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, "dependencies": { "string-width": "^4.2.0" @@ -1999,7 +2258,7 @@ "node": "10.* || >= 12.*" }, "optionalDependencies": { - "colors": "1.4.0" + "@colors/colors": "1.5.0" } }, "node_modules/cliui": { @@ -2060,12 +2319,12 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=16" } }, "node_modules/compress-commons": { @@ -2236,14 +2495,6 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2252,6 +2503,16 @@ "node": ">= 0.8" } }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -2620,12 +2881,6 @@ "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", "dev": true }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -2703,18 +2958,17 @@ "node >=0.6.0" ] }, - "node_modules/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -2756,19 +3010,25 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", - "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "optional": true, "dependencies": { "strnum": "^1.0.5" }, "bin": { "fxparser": "src/cli/cli.js" - }, - "funding": { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } }, "node_modules/fastq": { @@ -2826,12 +3086,12 @@ } }, "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.12.tgz", + "integrity": "sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==", "dev": true, "engines": { - "node": ">= 0.4.0" + "node": ">= 10.4.0" } }, "node_modules/fill-range": { @@ -3516,13 +3776,13 @@ } }, "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "dependencies": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, @@ -3661,22 +3921,34 @@ } }, "node_modules/httpntlm": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", - "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "version": "1.8.13", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", + "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", "dev": true, + "funding": [ + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=2CKNJLZJBW8ZC" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/samdecrock" + } + ], "dependencies": { + "des.js": "^1.0.1", "httpreq": ">=0.4.22", + "js-md4": "^0.3.2", "underscore": "~1.12.1" }, "engines": { - "node": ">=0.8.0" + "node": ">=10.4.0" } }, "node_modules/httpreq": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.5.2.tgz", - "integrity": "sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", + "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", "dev": true, "engines": { "node": ">= 6.15.1" @@ -3715,6 +3987,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3816,15 +4103,6 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4019,6 +4297,21 @@ "@sideway/pinpoint": "^2.0.0" } }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "dev": true + }, "node_modules/js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -4344,9 +4637,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -4478,6 +4771,12 @@ "node": ">= 0.6" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4677,13 +4976,12 @@ } }, "node_modules/mongodb": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz", - "integrity": "sha512-9l9n4Nk2BYZzljW3vHah3Z0rfS5npKw6ktnkmFgTcnzaXH1DRm3pDl6VMHu84EVb1lzmSaJC4OzWZqTkB5i2wg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.1.tgz", + "integrity": "sha512-MBuyYiPUPRTqfH2dV0ya4dcr2E5N52ocBuZ8Sgg/M030nGF78v855B3Z27mZJnp8PxjnUquEnAtjOsphgMZOlQ==", "dependencies": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.4", + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" }, "engines": { @@ -4691,13 +4989,13 @@ }, "optionalDependencies": { "@aws-sdk/credential-providers": "^3.186.0", - "saslprep": "^1.0.3" + "@mongodb-js/saslprep": "^1.1.0" } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", - "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" @@ -4803,59 +5101,53 @@ "dev": true }, "node_modules/newman": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/newman/-/newman-5.3.2.tgz", - "integrity": "sha512-cWy8pV0iwvMOZLTw3hkAHcwo2ZA0GKkXm8oUMn1Ltii3ZI2nKpnrg9QGdIT0hGHChRkX6prY5e3Aar7uykMGNg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/newman/-/newman-6.0.0.tgz", + "integrity": "sha512-QaANQC5b6ga348MezIVRI9ZmMs+cg3MdYIp0tSEauH2tmWOAR9+cghNsFJNjU9JPui3jJp1ALC7pQq6g3Jqpxw==", "dev": true, "dependencies": { - "async": "3.2.3", - "chardet": "1.4.0", - "cli-progress": "3.10.0", - "cli-table3": "0.6.1", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "chardet": "1.6.0", + "cli-progress": "3.12.0", + "cli-table3": "0.6.3", "colors": "1.4.0", - "commander": "7.2.0", + "commander": "11.0.0", "csv-parse": "4.16.3", - "eventemitter3": "4.0.7", - "filesize": "8.0.7", + "filesize": "10.0.12", + "liquid-json": "0.3.1", "lodash": "4.17.21", - "mkdirp": "1.0.4", - "postman-collection": "4.1.1", - "postman-collection-transformer": "4.1.6", - "postman-request": "2.88.1-postman.31", - "postman-runtime": "7.29.0", + "mkdirp": "3.0.1", + "postman-collection": "4.2.1", + "postman-collection-transformer": "4.1.7", + "postman-request": "2.88.1-postman.33", + "postman-runtime": "7.33.0", "pretty-ms": "7.0.1", - "semver": "7.3.5", + "semver": "7.5.4", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", - "word-wrap": "1.2.3", + "word-wrap": "1.2.5", "xmlbuilder": "15.1.1" }, "bin": { "newman": "bin/newman.js" }, "engines": { - "node": ">=10" + "node": ">=16" } }, - "node_modules/newman/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "node_modules/newman/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/newman/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { - "semver": "bin/semver.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/nise": { @@ -4935,9 +5227,9 @@ "dev": true }, "node_modules/nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -4945,8 +5237,8 @@ "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -4955,7 +5247,7 @@ "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { "type": "opencollective", @@ -4986,15 +5278,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -5356,21 +5639,21 @@ } }, "node_modules/postman-collection": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.1.1.tgz", - "integrity": "sha512-ODpJtlf8r99DMcTU7gFmi/yvQYckFzcuE6zL/fWnyrFT34ugdCBFlX+DN7M+AnP6lmR822fv5s60H4DnL4+fAg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.1.tgz", + "integrity": "sha512-DFLt3/yu8+ldtOTIzmBUctoupKJBOVK4NZO0t68K2lIir9smQg7OdQTBjOXYy+PDh7u0pSDvD66tm93eBHEPHA==", "dev": true, "dependencies": { - "faker": "5.5.3", + "@faker-js/faker": "5.5.3", "file-type": "3.9.0", "http-reasons": "0.1.0", "iconv-lite": "0.6.3", "liquid-json": "0.3.1", "lodash": "4.17.21", "mime-format": "2.0.1", - "mime-types": "2.1.34", + "mime-types": "2.1.35", "postman-url-encoder": "3.0.5", - "semver": "7.3.5", + "semver": "7.5.4", "uuid": "8.3.2" }, "engines": { @@ -5378,15 +5661,15 @@ } }, "node_modules/postman-collection-transformer": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.6.tgz", - "integrity": "sha512-xvdQb6sZoWcG9xZXUPSuxocjcd6WCZlINlGGiuHdSfxhgiwQhj9qhF0JRFbagZ8xB0+pYUairD5MiCENc6DEVA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.7.tgz", + "integrity": "sha512-SxJkm/LnlFZs2splUBnS4jQFicgBptghpm4voHtNnaum3Ad64E2MHLV4fJhv58dVUmFwdSwdQUN3m2q0iLecnQ==", "dev": true, "dependencies": { "commander": "8.3.0", "inherits": "2.0.4", "lodash": "4.17.21", - "semver": "7.3.5", + "semver": "7.5.4", "strip-json-comments": "3.1.1" }, "bin": { @@ -5405,21 +5688,6 @@ "node": ">= 12" } }, - "node_modules/postman-collection-transformer/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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/postman-collection/node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -5432,42 +5700,6 @@ "node": ">=0.10.0" } }, - "node_modules/postman-collection/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/postman-collection/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/postman-collection/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" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/postman-collection/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -5478,16 +5710,17 @@ } }, "node_modules/postman-request": { - "version": "2.88.1-postman.31", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.31.tgz", - "integrity": "sha512-OJbYqP7ItxQ84yHyuNpDywCZB0HYbpHJisMQ9lb1cSL3N5H3Td6a2+3l/a74UMd3u82BiGC5yQyYmdOIETP/nQ==", + "version": "2.88.1-postman.33", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", + "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", "dev": true, "dependencies": { "@postman/form-data": "~3.1.1", + "@postman/tough-cookie": "~4.1.3-postman.1", "@postman/tunnel-agent": "^0.6.3", "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "brotli": "~1.3.2", + "aws4": "^1.12.0", + "brotli": "^1.3.3", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", @@ -5497,14 +5730,13 @@ "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", + "mime-types": "^2.1.35", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.5.3", "safe-buffer": "^5.1.2", "stream-length": "^1.0.2", - "tough-cookie": "~2.5.0", - "uuid": "^3.3.2" + "uuid": "^8.3.2" }, "engines": { "node": ">= 6" @@ -5519,81 +5751,76 @@ "node": ">=0.6" } }, - "node_modules/postman-request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/postman-request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/postman-runtime": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.29.0.tgz", - "integrity": "sha512-eXxHREE/fUpohkGPRgBY1YccSGx9cyW3mtGiPyIE4zD5fYzasgBHqW6kbEND3Xrd3yf/uht/YI1H8O7J1+A1+w==", + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.33.0.tgz", + "integrity": "sha512-cYCb+5Y12FwZU/T3gOj2SKiOz38pisVLc0tdppb+ZlG7iqn5aLgxghJwhjG62pZCV6uixKiQX1hNdLSk9a9Xtw==", "dev": true, "dependencies": { - "async": "3.2.3", - "aws4": "1.11.0", - "handlebars": "4.7.7", - "httpntlm": "1.7.7", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "aws4": "1.12.0", + "handlebars": "4.7.8", + "httpntlm": "1.8.13", + "jose": "4.14.4", "js-sha512": "0.8.0", "lodash": "4.17.21", - "mime-types": "2.1.34", + "mime-types": "2.1.35", "node-oauth1": "1.3.0", "performance-now": "2.1.0", - "postman-collection": "4.1.1", - "postman-request": "2.88.1-postman.31", - "postman-sandbox": "4.0.6", + "postman-collection": "4.2.0", + "postman-request": "2.88.1-postman.33", + "postman-sandbox": "4.2.7", "postman-url-encoder": "3.0.5", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", + "strip-json-comments": "3.1.1", "uuid": "8.3.2" }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/postman-runtime/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "node_modules/postman-runtime/node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "node_modules/postman-runtime/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/postman-runtime/node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "node_modules/postman-runtime/node_modules/postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", "dev": true, "dependencies": { - "mime-db": "1.51.0" + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, "node_modules/postman-runtime/node_modules/uuid": { @@ -5606,19 +5833,63 @@ } }, "node_modules/postman-sandbox": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.0.6.tgz", - "integrity": "sha512-PPRanSNEE4zy3kO7CeSBHmAfJnGdD9ecHY/Mjh26CQuZZarGkNO8c0U/n+xX3+5M1BRNc82UYq6YCtdsSDqcng==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.2.7.tgz", + "integrity": "sha512-/EcCrKnb/o+9iLS4u+H76E0kBomJFjPptVjoDiq1uZ7Es/4aTv0MAX+0aoDxdDO+0h9sl8vy65uKQwyjN7AOaw==", "dev": true, "dependencies": { "lodash": "4.17.21", + "postman-collection": "4.2.0", "teleport-javascript": "1.0.0", - "uvm": "2.0.2" + "uvm": "2.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-sandbox/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postman-sandbox/node_modules/postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", + "dev": true, + "dependencies": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" }, "engines": { "node": ">=10" } }, + "node_modules/postman-sandbox/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/postman-url-encoder": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", @@ -5718,6 +5989,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5738,6 +6015,11 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5857,6 +6139,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -5967,18 +6255,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "dependencies": { - "sparse-bitfield": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/semaphore": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", @@ -5989,9 +6265,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6124,24 +6400,15 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "dependencies": { - "semver": "~7.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10" } }, "node_modules/sinon": { @@ -6277,6 +6544,18 @@ "bluebird": "^2.6.2" } }, + "node_modules/streamx": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.17.0.tgz", + "integrity": "sha512-mzRXEeafEA0skX5XLiDht/zdIqEVs4kgayUTFHDoMjiaZ2kC7DoFsQDJVXRILI2Qme/kWXxLpuU6P0B+xcXpFA==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -6353,45 +6632,28 @@ }, "node_modules/tar": { "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">= 10" } }, - "node_modules/tar-stream/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, "node_modules/teleport-javascript": { @@ -6453,29 +6715,15 @@ "node": "*" } }, - "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "optional": true }, "node_modules/tweetnacl": { @@ -6575,6 +6823,15 @@ "node": "*" } }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -6601,6 +6858,16 @@ "node": ">= 0.10" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6623,21 +6890,21 @@ } }, "node_modules/uvm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.0.2.tgz", - "integrity": "sha512-Ra+aPiS5GXAbwXmyNExqdS42sTqmmx4XWEDF8uJlsTfOkKf9Rd9xNgav1Yckv4HfVEZg4iOFODWHFYuJ+9Fzfg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", + "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", "dev": true, "dependencies": { - "flatted": "3.1.1" + "flatted": "3.2.6" }, "engines": { "node": ">=10" } }, "node_modules/uvm/node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, "node_modules/v8flags": { @@ -6712,9 +6979,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6867,10 +7134,29 @@ } }, "dependencies": { + "@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "optional": true, + "requires": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, "@aws-crypto/ie11-detection": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", - "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, "requires": { "tslib": "^1.11.1" @@ -6885,16 +7171,16 @@ } }, "@aws-crypto/sha256-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", - "integrity": "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, "requires": { - "@aws-crypto/ie11-detection": "^2.0.0", - "@aws-crypto/sha256-js": "^2.0.0", - "@aws-crypto/supports-web-crypto": "^2.0.0", - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" @@ -6909,13 +7195,13 @@ } }, "@aws-crypto/sha256-js": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz", - "integrity": "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, "requires": { - "@aws-crypto/util": "^2.0.0", - "@aws-sdk/types": "^3.1.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", "tslib": "^1.11.1" }, "dependencies": { @@ -6928,9 +7214,9 @@ } }, "@aws-crypto/supports-web-crypto": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.2.tgz", - "integrity": "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, "requires": { "tslib": "^1.11.1" @@ -6945,12 +7231,12 @@ } }, "@aws-crypto/util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-2.0.2.tgz", - "integrity": "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, "requires": { - "@aws-sdk/types": "^3.110.0", + "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", "tslib": "^1.11.1" }, @@ -6963,762 +7249,479 @@ } } }, - "@aws-sdk/abort-controller": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.193.0.tgz", - "integrity": "sha512-MYPBm5PWyKP+Tq37mKs5wDbyAyVMocF5iYmx738LYXBSj8A1V4LTFrvfd4U16BRC/sM0DYB9fBFJUQ9ISFRVYw==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, "@aws-sdk/client-cognito-identity": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.196.0.tgz", - "integrity": "sha512-EwO3G3YPQuT1nkzaVByfoyV1Jyx1WVmbt3HH5nIQDP2bgKCPkq8mytiSS14H0VyejGHmc8/1wZ7Q/MRPosdgEg==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/client-sts": "3.196.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "tslib": "^2.3.1" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.423.0.tgz", + "integrity": "sha512-9nyilMrihznN7Y6T/dVhbg4YGsdk7szzShoyoSGwofOg61ugobnHbBvh0tPPOQcHhlzXvD8LZdOQ6Kd4KvNp/A==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.423.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" } }, "@aws-sdk/client-sso": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.196.0.tgz", - "integrity": "sha512-u+UnxrVHLjLDdfCZft1AuyIhyv+77/inCHR4LcKsGASRA+jAg3z+OY+B7Q9hWHNcVt5ECMw7rxe4jA9BLf42sw==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "tslib": "^2.3.1" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.423.0.tgz", + "integrity": "sha512-znIufHkwhCIePgaYciIs3x/+BpzR57CZzbCKHR9+oOvGyufEPPpUT5bFLvbwTgfiVkTjuk6sG/ES3U5Bc+xtrA==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" } }, "@aws-sdk/client-sts": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.196.0.tgz", - "integrity": "sha512-ChzK8606CugwnRLm7iwerXzeMqOsjGLe3j1j1HtQShzXZu4/ysQ3mUBBPAt2Lltx+1ep8MoI9vaQVyfw5h35ww==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "2.0.0", - "@aws-crypto/sha256-js": "2.0.0", - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/fetch-http-handler": "3.193.0", - "@aws-sdk/hash-node": "3.193.0", - "@aws-sdk/invalid-dependency": "3.193.0", - "@aws-sdk/middleware-content-length": "3.193.0", - "@aws-sdk/middleware-endpoint": "3.193.0", - "@aws-sdk/middleware-host-header": "3.193.0", - "@aws-sdk/middleware-logger": "3.193.0", - "@aws-sdk/middleware-recursion-detection": "3.193.0", - "@aws-sdk/middleware-retry": "3.193.0", - "@aws-sdk/middleware-sdk-sts": "3.193.0", - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/middleware-user-agent": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/node-http-handler": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/smithy-client": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "@aws-sdk/util-base64-node": "3.188.0", - "@aws-sdk/util-body-length-browser": "3.188.0", - "@aws-sdk/util-body-length-node": "3.188.0", - "@aws-sdk/util-defaults-mode-browser": "3.193.0", - "@aws-sdk/util-defaults-mode-node": "3.193.0", - "@aws-sdk/util-endpoints": "3.196.0", - "@aws-sdk/util-user-agent-browser": "3.193.0", - "@aws-sdk/util-user-agent-node": "3.193.0", - "@aws-sdk/util-utf8-browser": "3.188.0", - "@aws-sdk/util-utf8-node": "3.188.0", - "fast-xml-parser": "4.0.11", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/config-resolver": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.193.0.tgz", - "integrity": "sha512-HIjuv2A1glgkXy9g/A8bfsiz3jTFaRbwGZheoHFZod6iEQQEbbeAsBe3u2AZyzOrVLgs8lOvBtgU8XKSJWjDkw==", - "optional": true, - "requires": { - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-config-provider": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.423.0.tgz", + "integrity": "sha512-EcpkKu02QZbRX6dQE0u7a8RgWrn/5riz1qAlKd7rM8FZJpr/D6GGX8ZzWxjgp7pRUgfNvinTmIudDnyQY3v9Mg==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-sdk-sts": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.196.0.tgz", - "integrity": "sha512-yXpb8kx1RpHRJty6MNX3ssTu0h3SYZVpUinQtBXPdHoVZ5/DyF/KGd2jr0LWYrgTx8G42GHTltz3Ss4nYjosnQ==", + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.423.0.tgz", + "integrity": "sha512-FuuCOeUkAn3tZU2GUN3eUjs4AC88t5je4N5/NVbTaSN0e2FGf9PnN5nrwTKwaOGVLSe6/FvfudW01LZ/+PRQOQ==", "optional": true, "requires": { - "@aws-sdk/client-cognito-identity": "3.196.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/client-cognito-identity": "3.423.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-env": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.193.0.tgz", - "integrity": "sha512-pRqZoIaqCdWB4JJdR6DqDn3u+CwKJchwiCPnRtChwC8KXCMkT4njq9J1bWG3imYeTxP/G06O1PDONEuD4pPtNQ==", - "optional": true, - "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-imds": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.193.0.tgz", - "integrity": "sha512-jC7uT7uVpO/iitz49toHMGFKXQ2igWQQG2SKirREqDRaz5HSXwEP1V3rcOlNNyGIBPMggDjZnxYgJHqBXSq9Ag==", - "optional": true, - "requires": { - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.196.0.tgz", - "integrity": "sha512-3lL+YLBQ9KwQxG4AdRm4u2cvBNZeBmS/i3BWnCPomg96lNGPMrTEloVaVEpnrzOff6sgFxRtjkbLkVxmdipIrw==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.196.0.tgz", - "integrity": "sha512-PGY7pkmqgfEwTHsuUH6fGrXWri93jqKkMbhq/QJafMGtsVupfvXvE37Rl+qgjsZjRfROrEaeLw2DGrPPmVh2cg==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-ini": "3.196.0", - "@aws-sdk/credential-provider-process": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-process": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.193.0.tgz", - "integrity": "sha512-zpXxtQzQqkaUuFqmHW9dSkh9p/1k+XNKlwEkG8FTwAJNUWmy2ZMJv+8NTVn4s4vaRu7xJ1er9chspYr7mvxHlA==", - "optional": true, - "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.196.0.tgz", - "integrity": "sha512-hJV4LDVfvPfj5zC0ysHx3zkwwJOyF+BaMGaMzaScrHyijv5e3qZzdoBLbOQFmrqVnt7DjCU02NvRSS8amLpmSw==", - "optional": true, - "requires": { - "@aws-sdk/client-sso": "3.196.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-provider-web-identity": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.193.0.tgz", - "integrity": "sha512-MIQY9KwLCBnRyIt7an4EtMrFQZz2HC1E8vQDdKVzmeQBBePhW61fnX9XDP9bfc3Ypg1NggLG00KBPEC88twLFg==", - "optional": true, - "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/credential-providers": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.196.0.tgz", - "integrity": "sha512-IE2Lq0EMCkPqvh0on6Dfg5Nofcm2hbsDH8etQNKRpvZ/K8elz1aArh2gcL9F01smrJChAHWwD8uZbk/eQ/Zf2w==", - "optional": true, - "requires": { - "@aws-sdk/client-cognito-identity": "3.196.0", - "@aws-sdk/client-sso": "3.196.0", - "@aws-sdk/client-sts": "3.196.0", - "@aws-sdk/credential-provider-cognito-identity": "3.196.0", - "@aws-sdk/credential-provider-env": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/credential-provider-ini": "3.196.0", - "@aws-sdk/credential-provider-node": "3.196.0", - "@aws-sdk/credential-provider-process": "3.193.0", - "@aws-sdk/credential-provider-sso": "3.196.0", - "@aws-sdk/credential-provider-web-identity": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/fetch-http-handler": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.193.0.tgz", - "integrity": "sha512-UhIS2LtCK9hqBzYVon6BI8WebJW1KC0GGIL/Gse5bqzU9iAGgFLAe66qg9k+/h3Jjc5LNAYzqXNVizMwn7689Q==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/querystring-builder": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-base64-browser": "3.188.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/hash-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.193.0.tgz", - "integrity": "sha512-O2SLPVBjrCUo+4ouAdRUoHBYsyurO9LcjNZNYD7YQOotBTbVFA3cx7kTZu+K4B6kX7FDaGbqbE1C/T1/eg/r+w==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/invalid-dependency": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.193.0.tgz", - "integrity": "sha512-54DCknekLwJAI1os76XJ8XCzfAH7BGkBGtlWk5WCNkZTfj3rf5RUiXz4uoKUMWE1rZmyMDoDDS1PBo+yTVKW5w==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/is-array-buffer": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.188.0.tgz", - "integrity": "sha512-n69N4zJZCNd87Rf4NzufPzhactUeM877Y0Tp/F3KiHqGeTnVjYUa4Lv1vLBjqtfjYb2HWT3NKlYn5yzrhaEwiQ==", - "optional": true, - "requires": { - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-content-length": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.193.0.tgz", - "integrity": "sha512-em0Sqo7O7DFOcVXU460pbcYuIjblDTZqK2YE62nQ0T+5Nbj+MSjuoite+rRRdRww9VqBkUROGKON45bUNjogtQ==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-endpoint": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.193.0.tgz", - "integrity": "sha512-Inbpt7jcHGvzF7UOJOCxx9wih0+eAQYERikokidWJa7M405EJpVYq1mGbeOcQUPANU3uWF1AObmUUFhbkriHQw==", - "optional": true, - "requires": { - "@aws-sdk/middleware-serde": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/url-parser": "3.193.0", - "@aws-sdk/util-config-provider": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-host-header": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.193.0.tgz", - "integrity": "sha512-aegzj5oRWd//lmfmkzRmgG2b4l3140v8Ey4QkqCxcowvAEX5a7rh23yuKaGtmiePwv2RQalCKz+tN6JXCm8g6Q==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-logger": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.193.0.tgz", - "integrity": "sha512-D/h1pU5tAcyJpJ8ZeD1Sta0S9QZPcxERYRBiJdEl8VUrYwfy3Cl1WJedVOmd5nG73ZLRSyHeXHewb/ohge3yKQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-recursion-detection": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.193.0.tgz", - "integrity": "sha512-fMWP76Q1GOb/9OzS1arizm6Dbfo02DPZ6xp7OoAN3PS6ybH3Eb47s/gP3jzgBPAITQacFj4St/4a06YWYrN3NA==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-retry": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.193.0.tgz", - "integrity": "sha512-zTQkHLBQBJi6ns655WYcYLyLPc1tgbEYU080Oc8zlveLUqoDn1ogkcmNhG7XMeQuBvWZBYN7J3/wFaXlDzeCKg==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/service-error-classification": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1", - "uuid": "^8.3.2" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true - } - } - }, - "@aws-sdk/middleware-sdk-sts": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.193.0.tgz", - "integrity": "sha512-TafiDkeflUsnbNa89TLkDnAiRRp1gAaZLDAjt75AzriRKZnhtFfYUXWb+qAuN50T+CkJ/gZI9LHDZL5ogz/HxQ==", - "optional": true, - "requires": { - "@aws-sdk/middleware-signing": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-serde": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.193.0.tgz", - "integrity": "sha512-dH93EJYVztY+ZDPzSMRi9LfAZfKO+luH62raNy49hlNa4jiyE1Tc/+qwlmOEpfGsrtcZ9TgsON1uFF9sgBXXaA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-signing": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.193.0.tgz", - "integrity": "sha512-obBoELGPf5ikvHYZwbzllLeuODiokdDfe92Ve2ufeOa/d8+xsmbqNzNdCTLNNTmr1tEIaEE7ngZVTOiHqAVhyw==", - "optional": true, - "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/signature-v4": "3.193.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-middleware": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-stack": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.193.0.tgz", - "integrity": "sha512-Ix5d7gE6bZwFNIVf0dGnjYuymz1gjitNoAZDPpv1nEZlUMek/jcno5lmzWFzUZXY/azpbIyaPwq/wm/c69au5A==", - "optional": true, - "requires": { - "tslib": "^2.3.1" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.193.0.tgz", - "integrity": "sha512-0vT6F9NwYQK7ARUUJeHTUIUPnupsO3IbmjHSi1+clkssFlJm2UfmSGeafiWe4AYH3anATTvZEtcxX5DZT/ExbA==", - "optional": true, - "requires": { - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/node-config-provider": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.193.0.tgz", - "integrity": "sha512-5RLdjQLH69ISRG8TX9klSLOpEySXxj+z9E9Em39HRvw0/rDcd8poCTADvjYIOqRVvMka0z/hm+elvUTIVn/DRw==", - "optional": true, - "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/shared-ini-file-loader": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/node-http-handler": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.193.0.tgz", - "integrity": "sha512-DP4BmFw64HOShgpAPEEMZedVnRmKKjHOwMEoXcnNlAkMXnYUFHiKvudYq87Q2AnSlT6OHkyMviB61gEvIk73dA==", - "optional": true, - "requires": { - "@aws-sdk/abort-controller": "3.193.0", - "@aws-sdk/protocol-http": "3.193.0", - "@aws-sdk/querystring-builder": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/property-provider": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.193.0.tgz", - "integrity": "sha512-IaDR/PdZjKlAeSq2E/6u6nkPsZF9wvhHZckwH7uumq4ocWsWXFzaT+hKpV4YZPHx9n+K2YV4Gn/bDedpz99W1Q==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/protocol-http": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.193.0.tgz", - "integrity": "sha512-r0wbTwFJyXq0uiImI6giqG3g/RO1N/y4wwPA7qr7OC+KXJ0NkyVxIf6e7Vx8h06aM1ATtngbwJaMP59kVCp85A==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz", + "integrity": "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==", "optional": true, "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/querystring-builder": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.193.0.tgz", - "integrity": "sha512-PRaK6649iw0UO45UjUoiUzFcOKXZb8pMjjFJpqALpEvdZT3twxqhlPXujT7GWPKrSwO4uPLNnyYEtPY82wx2vw==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-uri-escape": "3.188.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/querystring-parser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.193.0.tgz", - "integrity": "sha512-dGEPCe8SK4/td5dSpiaEI3SvT5eHXrbJWbLGyD4FL3n7WCGMy2xVWAB/yrgzD0GdLDjDa8L5vLVz6yT1P9i+hA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/service-error-classification": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.193.0.tgz", - "integrity": "sha512-bPnXVu8ErE1RfWVVQKc2TE7EuoImUi4dSPW9g80fGRzJdQNwXb636C+7OUuWvSDzmFwuBYqZza8GZjVd+rz2zQ==", - "optional": true - }, - "@aws-sdk/shared-ini-file-loader": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.193.0.tgz", - "integrity": "sha512-hnvZup8RSpFXfah7Rrn6+lQJnAOCO+OiDJ2R/iMgZQh475GRQpLbu3cPhCOkjB14vVLygJtW8trK/0+zKq93bQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/signature-v4": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.193.0.tgz", - "integrity": "sha512-JEqqOB8wQZz6g1ERNUOIBFDFt8OJtz5G5Uh1CdkS5W66gyWnJEz/dE1hA2VTqqQwHGGEsIEV/hlzruU1lXsvFA==", - "optional": true, - "requires": { - "@aws-sdk/is-array-buffer": "3.188.0", - "@aws-sdk/types": "3.193.0", - "@aws-sdk/util-hex-encoding": "3.188.0", - "@aws-sdk/util-middleware": "3.193.0", - "@aws-sdk/util-uri-escape": "3.188.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/smithy-client": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.193.0.tgz", - "integrity": "sha512-BY0jhfW76vyXr7ODMaKO3eyS98RSrZgOMl6DTQV9sk7eFP/MPVlG7p7nfX/CDIgPBIO1z0A0i2CVIzYur9uGgQ==", - "optional": true, - "requires": { - "@aws-sdk/middleware-stack": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" - } - }, - "@aws-sdk/types": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.193.0.tgz", - "integrity": "sha512-LV/wcPolRZKORrcHwkH59QMCkiDR5sM+9ZtuTxvyUGG2QFW/kjoxs08fUF10OWNJMrotBI+czDc5QJRgN8BlAw==", - "optional": true + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } }, - "@aws-sdk/url-parser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.193.0.tgz", - "integrity": "sha512-hwD1koJlOu2a6GvaSbNbdo7I6a3tmrsNTZr8bCjAcbqpc5pDThcpnl/Uaz3zHmMPs92U8I6BvWoK6pH8By06qw==", + "@aws-sdk/credential-provider-http": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.423.0.tgz", + "integrity": "sha512-y/mutbiCU/4HGN/ChcNBhPaXo4pgg6lAcWyuMTSSfAR03hjoXe1cMwbPcUiEwzQrZ/+1yufLpZhmoiAWsgAkNw==", "optional": true, "requires": { - "@aws-sdk/querystring-parser": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-base64-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-browser/-/util-base64-browser-3.188.0.tgz", - "integrity": "sha512-qlH+5NZBLiyKziL335BEPedYxX6j+p7KFRWXvDQox9S+s+gLCayednpK+fteOhBenCcR9fUZOVuAPScy1I8qCg==", + "@aws-sdk/credential-provider-ini": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.423.0.tgz", + "integrity": "sha512-7CsFWz8g7dQmblp57XzzxMirO4ClowGZIOwAheBkmk6q1XHbllcHFnbh2kdPyQQ0+JmjDg6waztIc7dY7Ycfvw==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-base64-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-3.188.0.tgz", - "integrity": "sha512-r1dccRsRjKq+OhVRUfqFiW3sGgZBjHbMeHLbrAs9jrOjU2PTQ8PSzAXLvX/9lmp7YjmX17Qvlsg0NCr1tbB9OA==", + "@aws-sdk/credential-provider-node": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.423.0.tgz", + "integrity": "sha512-lygbGJJUnDpgo8OEqdoYd51BKkyBVQ1Catiua/m0aHvL+SCmVrHiYPQPawWYGxpH8X3DXdXa0nd0LkEaevrHRg==", "optional": true, "requires": { - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.423.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-body-length-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", - "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "@aws-sdk/credential-provider-process": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz", + "integrity": "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-body-length-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.188.0.tgz", - "integrity": "sha512-XwqP3vxk60MKp4YDdvDeCD6BPOiG2e+/Ou4AofZOy5/toB6NKz2pFNibQIUg2+jc7mPMnGnvOW3MQEgSJ+gu/Q==", + "@aws-sdk/credential-provider-sso": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.423.0.tgz", + "integrity": "sha512-zAH68IjRMmW22USbsCVQ5Q6AHqhmWABwLbZAMocSGMasddTGv/nkA/nUiVCJ/B4LI3P81FoPQVrG5JxNmkNH0w==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/client-sso": "3.423.0", + "@aws-sdk/token-providers": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-buffer-from": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.188.0.tgz", - "integrity": "sha512-NX1WXZ8TH20IZb4jPFT2CnLKSqZWddGxtfiWxD9M47YOtq/SSQeR82fhqqVjJn4P8w2F5E28f+Du4ntg/sGcxA==", + "@aws-sdk/credential-provider-web-identity": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz", + "integrity": "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==", "optional": true, "requires": { - "@aws-sdk/is-array-buffer": "3.188.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-config-provider": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.188.0.tgz", - "integrity": "sha512-LBA7tLbi7v4uvbOJhSnjJrxbcRifKK/1ZVK94JTV2MNSCCyNkFotyEI5UWDl10YKriTIUyf7o5cakpiDZ3O4xg==", + "@aws-sdk/credential-providers": { + "version": "3.423.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.423.0.tgz", + "integrity": "sha512-jsjIrnu+bVUz2lekcg9wxpPlO8jWd9q26MP/rRwdkm9LHqroICjZY7tIYqSJliVkeSyJHJ9pq/jNDceWhy6a0A==", + "optional": true, + "requires": { + "@aws-sdk/client-cognito-identity": "3.423.0", + "@aws-sdk/client-sso": "3.423.0", + "@aws-sdk/client-sts": "3.423.0", + "@aws-sdk/credential-provider-cognito-identity": "3.423.0", + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-http": "3.423.0", + "@aws-sdk/credential-provider-ini": "3.423.0", + "@aws-sdk/credential-provider-node": "3.423.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.423.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz", + "integrity": "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-defaults-mode-browser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.193.0.tgz", - "integrity": "sha512-9riQKFrSJcsNAMnPA/3ltpSxNykeO20klE/UKjxEoD7UWjxLwsPK22UJjFwMRaHoAFcZD0LU/SgPxbC0ktCYCg==", + "@aws-sdk/middleware-logger": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz", + "integrity": "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==", "optional": true, "requires": { - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "bowser": "^2.11.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-defaults-mode-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.193.0.tgz", - "integrity": "sha512-occQmckvPRiM4YQIZnulfKKKjykGKWloa5ByGC5gOEGlyeP9zJpfs4zc/M2kArTAt+d2r3wkBtsKe5yKSlVEhA==", + "@aws-sdk/middleware-recursion-detection": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz", + "integrity": "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==", "optional": true, "requires": { - "@aws-sdk/config-resolver": "3.193.0", - "@aws-sdk/credential-provider-imds": "3.193.0", - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/property-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-endpoints": { - "version": "3.196.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.196.0.tgz", - "integrity": "sha512-X+DOpRUy/ij49a0GQtggk09oyIQGn0mhER6PbMT69IufZPIg3D5fC5FPEp8bfsPkb70fTEYQEsj/X/rgMQJKsA==", + "@aws-sdk/middleware-sdk-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz", + "integrity": "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==", "optional": true, "requires": { - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-hex-encoding": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.188.0.tgz", - "integrity": "sha512-QyWovTtjQ2RYxqVM+STPh65owSqzuXURnfoof778spyX4iQ4z46wOge1YV2ZtwS8w5LWd9eeVvDrLu5POPYOnA==", + "@aws-sdk/middleware-signing": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz", + "integrity": "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-locate-window": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.188.0.tgz", - "integrity": "sha512-SxobBVLZkkLSawTCfeQnhVX3Azm9O+C2dngZVe1+BqtF8+retUbVTs7OfYeWBlawVkULKF2e781lTzEHBBjCzw==", + "@aws-sdk/middleware-user-agent": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz", + "integrity": "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/region-config-resolver": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz", + "integrity": "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==", + "optional": true, + "requires": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/token-providers": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz", + "integrity": "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/types": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz", + "integrity": "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-middleware": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.193.0.tgz", - "integrity": "sha512-+aC6pmkcGgpxaMWCH/FXTsGWl2W342oQGs1OYKGi+W8z9UguXrqamWjdkdMqgunvj9qOEG2KBMKz1FWFFZlUyA==", + "@aws-sdk/util-endpoints": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz", + "integrity": "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==", "optional": true, "requires": { - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "tslib": "^2.5.0" } }, - "@aws-sdk/util-uri-escape": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.188.0.tgz", - "integrity": "sha512-4Y6AYZMT483Tiuq8dxz5WHIiPNdSFPGrl6tRTo2Oi2FcwypwmFhqgEGcqxeXDUJktvaCBxeA08DLr/AemVhPCg==", + "@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "optional": true, "requires": { - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-browser": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.193.0.tgz", - "integrity": "sha512-1EkGYsUtOMEyJG/UBIR4PtmO3lVjKNoUImoMpLtEucoGbWz5RG9zFSwLevjFyFs5roUBFlxkSpTMo8xQ3aRzQg==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz", + "integrity": "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==", "optional": true, "requires": { - "@aws-sdk/types": "3.193.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", "bowser": "^2.11.0", - "tslib": "^2.3.1" + "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-node": { - "version": "3.193.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.193.0.tgz", - "integrity": "sha512-G/2/1cSgsxVtREAm8Eq8Duib5PXzXknFRHuDpAxJ5++lsJMXoYMReS278KgV54cojOkAVfcODDTqmY3Av0WHhQ==", + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz", + "integrity": "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==", "optional": true, "requires": { - "@aws-sdk/node-config-provider": "3.193.0", - "@aws-sdk/types": "3.193.0", - "tslib": "^2.3.1" + "@aws-sdk/types": "3.418.0", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" } }, "@aws-sdk/util-utf8-browser": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.188.0.tgz", - "integrity": "sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==", + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, "requires": { "tslib": "^2.3.1" } }, - "@aws-sdk/util-utf8-node": { - "version": "3.188.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-3.188.0.tgz", - "integrity": "sha512-hCgP4+C0Lekjpjt2zFJ2R/iHes5sBGljXa5bScOFAEkRUc0Qw0VNgTv7LpEbIOAwGmqyxBoCwBW0YHPW1DfmYQ==", - "optional": true, - "requires": { - "@aws-sdk/util-buffer-from": "3.188.0", - "tslib": "^2.3.1" - } + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true }, "@eslint/eslintrc": { "version": "1.3.3", @@ -7754,6 +7757,12 @@ } } }, + "@faker-js/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", + "dev": true + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -7828,6 +7837,15 @@ "tar": "^6.1.11" } }, + "@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7865,6 +7883,18 @@ "mime-types": "^2.1.12" } }, + "@postman/tough-cookie": { + "version": "4.1.3-postman.1", + "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", + "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + } + }, "@postman/tunnel-agent": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", @@ -7887,66 +7917,499 @@ "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, - "@sideway/pinpoint": { + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", + "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "@smithy/abort-controller": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.10.tgz", + "integrity": "sha512-xn7PnFD3m4rQIG00h1lPuDVnC2QMtTFhzRLX3y56KkgFaCysS7vpNevNBgmNUtmJ4eVFc+66Zucwo2KDLdicOg==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/config-resolver": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.11.tgz", + "integrity": "sha512-q97FnlUmbai1c4JlQJgLVBsvSxgV/7Nvg/JK76E1nRq/U5UM56Eqo3dn2fY7JibqgJLg4LPsGdwtIyqyOk35CQ==", + "optional": true, + "requires": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + } + }, + "@smithy/credential-provider-imds": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.13.tgz", + "integrity": "sha512-/xe3wNoC4j+BeTemH9t2gSKLBfyZmk8LXB2pQm/TOEYi+QhBgT+PSolNDfNAhrR68eggNE17uOimsrnwSkCt4w==", + "optional": true, + "requires": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "tslib": "^2.5.0" + } + }, + "@smithy/eventstream-codec": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.10.tgz", + "integrity": "sha512-3SSDgX2nIsFwif6m+I4+ar4KDcZX463Noes8ekBgQHitULiWvaDZX8XqPaRQSQ4bl1vbeVXHklJfv66MnVO+lw==", + "optional": true, + "requires": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/fetch-http-handler": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.1.tgz", + "integrity": "sha512-bXyM8PBAIKxVV++2ZSNBEposTDjFQ31XWOdHED+2hWMNvJHUoQqFbECg/uhcVOa6vHie2/UnzIZfXBSTpDBnEw==", + "optional": true, + "requires": { + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/hash-node": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.10.tgz", + "integrity": "sha512-jSTf6uzPk/Vf+8aQ7tVXeHfjxe9wRXSCqIZcBymSDTf7/YrVxniBdpyN74iI8ZUOx/Pyagc81OK5FROLaEjbXQ==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/invalid-dependency": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.10.tgz", + "integrity": "sha512-zw9p/zsmJ2cFcW4KMz3CJoznlbRvEA6HG2mvEaX5eAca5dq4VGI2MwPDTfmteC/GsnURS4ogoMQ0p6aHM2SDVQ==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-content-length": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.12.tgz", + "integrity": "sha512-QRhJTo5TjG7oF7np6yY4ZO9GDKFVzU/GtcqUqyEa96bLHE3yZHgNmsolOQ97pfxPHmFhH4vDP//PdpAIN3uI1Q==", + "optional": true, + "requires": { + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-endpoint": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.10.tgz", + "integrity": "sha512-O6m4puZc16xfenotZUHL4bRlMrwf4gTp+0I5l954M5KNd3dOK18P+FA/IIUgnXF/dX6hlCUcJkBp7nAzwrePKA==", + "optional": true, + "requires": { + "@smithy/middleware-serde": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-retry": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.13.tgz", + "integrity": "sha512-zuOva8xgWC7KYG8rEXyWIcZv2GWszO83DCTU6IKcf/FKu6OBmSE+EYv3EUcCGY+GfiwCX0EyJExC9Lpq9b0w5Q==", + "optional": true, + "requires": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/protocol-http": "^3.0.6", + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-retry": "^2.0.3", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true + } + } + }, + "@smithy/middleware-serde": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.10.tgz", + "integrity": "sha512-+A0AFqs768256H/BhVEsBF6HijFbVyAwYRVXY/izJFkTalVWJOp4JA0YdY0dpXQd+AlW0tzs+nMQCE1Ew+DcgQ==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-stack": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.4.tgz", + "integrity": "sha512-MW0KNKfh8ZGLagMZnxcLJWPNXoKqW6XV/st5NnCBmmA2e2JhrUjU0AJ5Ca/yjTyNEKs3xH7AQDwp1YmmpEpmQQ==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/node-config-provider": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.13.tgz", + "integrity": "sha512-pPpLqYuJcOq1sj1EGu+DoZK47DUS4gepqSTNgRezmrjnzNlSU2/Dcc9Ebzs+WZ0Z5vXKazuE+k+NksFLo07/AA==", + "optional": true, + "requires": { + "@smithy/property-provider": "^2.0.11", + "@smithy/shared-ini-file-loader": "^2.0.12", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/node-http-handler": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.6.tgz", + "integrity": "sha512-NspvD3aCwiUNtoSTcVHz0RZz1tQ/SaRIe1KPF+r0mAdCZ9eWuhIeJT8ZNPYa1ITn7/Lgg64IyFjqPynZ8KnYQw==", + "optional": true, + "requires": { + "@smithy/abort-controller": "^2.0.10", + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/property-provider": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.11.tgz", + "integrity": "sha512-kzuOadu6XvrnlF1iXofpKXYmo4oe19st9/DE8f5gHNaFepb4eTkR8gD8BSdTnNnv7lxfv6uOwZPg4VS6hemX1w==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/protocol-http": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.6.tgz", + "integrity": "sha512-F0jAZzwznMmHaggiZgc7YoS08eGpmLvhVktY/Taz6+OAOHfyIqWSDNgFqYR+WHW9z5fp2XvY4mEUrQgYMQ71jw==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-builder": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.10.tgz", + "integrity": "sha512-uujJGp8jzrrU1UHme8sUKEbawQTcTmUWsh8rbGXYD/lMwNLQ+9jQ9dMDWbbH9Hpoa9RER1BeL/38WzGrbpob2w==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.10.tgz", + "integrity": "sha512-WSD4EU60Q8scacT5PIpx4Bahn6nWpt+MiYLcBkFt6fOj7AssrNeaNIU2Z0g40ftVmrwLcEOIKGX92ynbVDb3ZA==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/service-error-classification": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.3.tgz", + "integrity": "sha512-b+m4QCHXb7oKAkM/jHwHrl5gpqhFoMTHF643L0/vAEkegrcUWyh1UjyoHttuHcP5FnHVVy4EtpPtLkEYD+xMFw==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.12.tgz", + "integrity": "sha512-umi0wc4UBGYullAgYNUVfGLgVpxQyES47cnomTqzCKeKO5oudO4hyDNj+wzrOjqDFwK2nWYGVgS8Y0JgGietrw==", + "optional": true, + "requires": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/signature-v4": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.10.tgz", + "integrity": "sha512-S6gcP4IXfO/VMswovrhxPpqvQvMal7ZRjM4NvblHSPpE5aNBYx67UkHFF3kg0hR3tJKqNpBGbxwq0gzpdHKLRA==", + "optional": true, + "requires": { + "@smithy/eventstream-codec": "^2.0.10", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/smithy-client": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.9.tgz", + "integrity": "sha512-HTicQSn/lOcXKJT+DKJ4YMu51S6PzbWsO8Z6Pwueo30mSoFKXg5P0BDkg2VCDqCVR0mtddM/F6hKhjW6YAV/yg==", + "optional": true, + "requires": { + "@smithy/middleware-stack": "^2.0.4", + "@smithy/types": "^2.3.4", + "@smithy/util-stream": "^2.0.14", + "tslib": "^2.5.0" + } + }, + "@smithy/types": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.4.tgz", + "integrity": "sha512-D7xlM9FOMFyFw7YnMXn9dK2KuN6+JhnrZwVt1fWaIu8hCk5CigysweeIT/H/nCo4YV+s8/oqUdLfexbkPZtvqw==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/url-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.10.tgz", + "integrity": "sha512-4TXQFGjHcqru8aH5VRB4dSnOFKCYNX6SR1Do6fwxZ+ExT2onLsh2W77cHpks7ma26W5jv6rI1u7d0+KX9F0aOw==", + "optional": true, + "requires": { + "@smithy/querystring-parser": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "optional": true, + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "optional": true, + "requires": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.13.tgz", + "integrity": "sha512-UmmOdUzaQjqdsl1EjbpEaQxM0VDFqTj6zDuI26/hXN7L/a1k1koTwkYpogHMvunDX3fjrQusg5gv1Td4UsGyog==", + "optional": true, + "requires": { + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-defaults-mode-node": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.15.tgz", + "integrity": "sha512-g6J7MHAibVPMTlXyH3mL+Iet4lMJKFVhsOhJmn+IKG81uy9m42CkRSDlwdQSJAcprLQBIaOPdFxNXQvrg2w1Uw==", + "optional": true, + "requires": { + "@smithy/config-resolver": "^2.0.11", + "@smithy/credential-provider-imds": "^2.0.13", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.9", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "@smithy/util-hex-encoding": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } }, - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, + "@smithy/util-middleware": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.3.tgz", + "integrity": "sha512-+FOCFYOxd2HO7v/0hkFSETKf7FYQWa08wh/x/4KUeoVBnLR4juw8Qi+TTqZI6E2h5LkzD9uOaxC9lAjrpVzaaA==", + "optional": true, "requires": { - "type-detect": "4.0.8" + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" } }, - "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, + "@smithy/util-retry": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.3.tgz", + "integrity": "sha512-gw+czMnj82i+EaH7NL7XKkfX/ZKrCS2DIWwJFPKs76bMgkhf0y1C94Lybn7f8GkBI9lfIOUdPYtzm19zQOC8sw==", + "optional": true, "requires": { - "@sinonjs/commons": "^1.7.0" - }, - "dependencies": { - "@sinonjs/commons": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz", - "integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - } + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" } }, - "@sinonjs/samsam": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", - "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", - "dev": true, + "@smithy/util-stream": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.14.tgz", + "integrity": "sha512-XjvlDYe+9DieXhLf7p+EgkXwFtl34kHZcWfHnc5KaILbhyVfDLWuqKTFx6WwCFqb01iFIig8trGwExRIqqkBYg==", + "optional": true, "requires": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@smithy/fetch-http-handler": "^2.2.1", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" } }, - "@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true + "@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "optional": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "optional": true, + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } }, "@types/node": { - "version": "18.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.6.tgz", - "integrity": "sha512-j3CEDa2vd96K0AXF8Wur7UucACvnjkk8hYyQAHhUNciabZLDl9nfAEVUSwmh245OOZV15bRA3Y590Gi5jUcDJg==" + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" }, "@types/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.1.tgz", + "integrity": "sha512-8hKOnOan+Uu+NgMaCouhg3cT9x5fFZ92Jwf+uDLXLu/MFRbXxlWwGeQY7KVHkeSft6RvY+tdxklUBuyY9eIEKg==" }, "@types/whatwg-url": { "version": "8.2.2", @@ -8079,6 +8542,32 @@ "readdir-glob": "^1.0.0", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" + }, + "dependencies": { + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } } }, "archiver-utils": { @@ -8203,16 +8692,27 @@ "dev": true }, "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, + "b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "bare-events": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.3.1.tgz", + "integrity": "sha512-sJnSOTVESURZ61XgEleqmP255T6zTYwHPwE4r6SssIh0U9/uDvfpdoJYpVUerJJZH2fueO+CdT8ZT+OC/7aZDA==", + "optional": true + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -8328,9 +8828,9 @@ "dev": true }, "bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", "requires": { "buffer": "^5.6.0" } @@ -8398,9 +8898,9 @@ } }, "chardet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", - "integrity": "sha512-NpwMDdSIprbYx1CLnfbxEIarI0Z+s9MssEgggMNheGM+WD68yOhV7IEA/3r6tr0yTRgQD0HuZJDw32s99i6L+A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.6.0.tgz", + "integrity": "sha512-+QOTw3otC4+FxdjK9RopGpNOglADbr4WPFi0SonkO99JbpkTPbMxmdm4NenhF5Zs+4gPXLI1+y2uazws5TMe8w==", "dev": true }, "charset": { @@ -8442,21 +8942,21 @@ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" }, "cli-progress": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", - "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", "dev": true, "requires": { - "string-width": "^4.2.0" + "string-width": "^4.2.3" } }, "cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, "requires": { - "colors": "1.4.0", + "@colors/colors": "1.5.0", "string-width": "^4.2.0" } }, @@ -8506,9 +9006,9 @@ } }, "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "dev": true }, "compress-commons": { @@ -8640,16 +9140,21 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -8922,12 +9427,6 @@ "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", "dev": true }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -8993,18 +9492,17 @@ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, - "faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", - "dev": true - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -9042,9 +9540,9 @@ "dev": true }, "fast-xml-parser": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", - "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "optional": true, "requires": { "strnum": "^1.0.5" @@ -9092,9 +9590,9 @@ "dev": true }, "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.12.tgz", + "integrity": "sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==", "dev": true }, "fill-range": { @@ -9625,13 +10123,13 @@ } }, "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "requires": { "minimist": "^1.2.5", - "neo-async": "^2.6.0", + "neo-async": "^2.6.2", "source-map": "^0.6.1", "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" @@ -9728,19 +10226,21 @@ } }, "httpntlm": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", - "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "version": "1.8.13", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", + "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", "dev": true, "requires": { + "des.js": "^1.0.1", "httpreq": ">=0.4.22", + "js-md4": "^0.3.2", "underscore": "~1.12.1" } }, "httpreq": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.5.2.tgz", - "integrity": "sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", + "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", "dev": true }, "https-proxy-agent": { @@ -9767,6 +10267,12 @@ } } }, + "husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -9839,12 +10345,6 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true - }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -9991,6 +10491,18 @@ "@sideway/pinpoint": "^2.0.0" } }, + "jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "dev": true + }, + "js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "dev": true + }, "js-sdsl": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", @@ -10273,9 +10785,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -10370,6 +10882,12 @@ "mime-db": "1.52.0" } }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -10517,22 +11035,21 @@ } }, "mongodb": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz", - "integrity": "sha512-9l9n4Nk2BYZzljW3vHah3Z0rfS5npKw6ktnkmFgTcnzaXH1DRm3pDl6VMHu84EVb1lzmSaJC4OzWZqTkB5i2wg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.1.tgz", + "integrity": "sha512-MBuyYiPUPRTqfH2dV0ya4dcr2E5N52ocBuZ8Sgg/M030nGF78v855B3Z27mZJnp8PxjnUquEnAtjOsphgMZOlQ==", "requires": { "@aws-sdk/credential-providers": "^3.186.0", - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.4", - "saslprep": "^1.0.3", + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" } }, "mongodb-connection-string-url": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", - "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" @@ -10616,48 +11133,39 @@ "dev": true }, "newman": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/newman/-/newman-5.3.2.tgz", - "integrity": "sha512-cWy8pV0iwvMOZLTw3hkAHcwo2ZA0GKkXm8oUMn1Ltii3ZI2nKpnrg9QGdIT0hGHChRkX6prY5e3Aar7uykMGNg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/newman/-/newman-6.0.0.tgz", + "integrity": "sha512-QaANQC5b6ga348MezIVRI9ZmMs+cg3MdYIp0tSEauH2tmWOAR9+cghNsFJNjU9JPui3jJp1ALC7pQq6g3Jqpxw==", "dev": true, "requires": { - "async": "3.2.3", - "chardet": "1.4.0", - "cli-progress": "3.10.0", - "cli-table3": "0.6.1", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "chardet": "1.6.0", + "cli-progress": "3.12.0", + "cli-table3": "0.6.3", "colors": "1.4.0", - "commander": "7.2.0", + "commander": "11.0.0", "csv-parse": "4.16.3", - "eventemitter3": "4.0.7", - "filesize": "8.0.7", + "filesize": "10.0.12", + "liquid-json": "0.3.1", "lodash": "4.17.21", - "mkdirp": "1.0.4", - "postman-collection": "4.1.1", - "postman-collection-transformer": "4.1.6", - "postman-request": "2.88.1-postman.31", - "postman-runtime": "7.29.0", + "mkdirp": "3.0.1", + "postman-collection": "4.2.1", + "postman-collection-transformer": "4.1.7", + "postman-request": "2.88.1-postman.33", + "postman-runtime": "7.33.0", "pretty-ms": "7.0.1", - "semver": "7.3.5", + "semver": "7.5.4", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", - "word-wrap": "1.2.3", + "word-wrap": "1.2.5", "xmlbuilder": "15.1.1" }, "dependencies": { - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true - }, - "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" - } } } }, @@ -10731,9 +11239,9 @@ "dev": true }, "nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, "requires": { "chokidar": "^3.5.2", @@ -10741,8 +11249,8 @@ "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -10769,12 +11277,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -11039,21 +11541,21 @@ "dev": true }, "postman-collection": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.1.1.tgz", - "integrity": "sha512-ODpJtlf8r99DMcTU7gFmi/yvQYckFzcuE6zL/fWnyrFT34ugdCBFlX+DN7M+AnP6lmR822fv5s60H4DnL4+fAg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.1.tgz", + "integrity": "sha512-DFLt3/yu8+ldtOTIzmBUctoupKJBOVK4NZO0t68K2lIir9smQg7OdQTBjOXYy+PDh7u0pSDvD66tm93eBHEPHA==", "dev": true, "requires": { - "faker": "5.5.3", + "@faker-js/faker": "5.5.3", "file-type": "3.9.0", "http-reasons": "0.1.0", "iconv-lite": "0.6.3", "liquid-json": "0.3.1", "lodash": "4.17.21", "mime-format": "2.0.1", - "mime-types": "2.1.34", + "mime-types": "2.1.35", "postman-url-encoder": "3.0.5", - "semver": "7.3.5", + "semver": "7.5.4", "uuid": "8.3.2" }, "dependencies": { @@ -11066,30 +11568,6 @@ "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "requires": { - "mime-db": "1.51.0" - } - }, - "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" - } - }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -11099,15 +11577,15 @@ } }, "postman-collection-transformer": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.6.tgz", - "integrity": "sha512-xvdQb6sZoWcG9xZXUPSuxocjcd6WCZlINlGGiuHdSfxhgiwQhj9qhF0JRFbagZ8xB0+pYUairD5MiCENc6DEVA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.7.tgz", + "integrity": "sha512-SxJkm/LnlFZs2splUBnS4jQFicgBptghpm4voHtNnaum3Ad64E2MHLV4fJhv58dVUmFwdSwdQUN3m2q0iLecnQ==", "dev": true, "requires": { "commander": "8.3.0", "inherits": "2.0.4", "lodash": "4.17.21", - "semver": "7.3.5", + "semver": "7.5.4", "strip-json-comments": "3.1.1" }, "dependencies": { @@ -11116,29 +11594,21 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true - }, - "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" - } } } }, "postman-request": { - "version": "2.88.1-postman.31", - "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.31.tgz", - "integrity": "sha512-OJbYqP7ItxQ84yHyuNpDywCZB0HYbpHJisMQ9lb1cSL3N5H3Td6a2+3l/a74UMd3u82BiGC5yQyYmdOIETP/nQ==", + "version": "2.88.1-postman.33", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", + "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", "dev": true, "requires": { "@postman/form-data": "~3.1.1", + "@postman/tough-cookie": "~4.1.3-postman.1", "@postman/tunnel-agent": "^0.6.3", "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "brotli": "~1.3.2", + "aws4": "^1.12.0", + "brotli": "^1.3.3", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", @@ -11148,14 +11618,13 @@ "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", + "mime-types": "^2.1.35", "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.5.3", "safe-buffer": "^5.1.2", "stream-length": "^1.0.2", - "tough-cookie": "~2.5.0", - "uuid": "^3.3.2" + "uuid": "^8.3.2" }, "dependencies": { "qs": { @@ -11164,67 +11633,66 @@ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true } } }, "postman-runtime": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.29.0.tgz", - "integrity": "sha512-eXxHREE/fUpohkGPRgBY1YccSGx9cyW3mtGiPyIE4zD5fYzasgBHqW6kbEND3Xrd3yf/uht/YI1H8O7J1+A1+w==", + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.33.0.tgz", + "integrity": "sha512-cYCb+5Y12FwZU/T3gOj2SKiOz38pisVLc0tdppb+ZlG7iqn5aLgxghJwhjG62pZCV6uixKiQX1hNdLSk9a9Xtw==", "dev": true, "requires": { - "async": "3.2.3", - "aws4": "1.11.0", - "handlebars": "4.7.7", - "httpntlm": "1.7.7", + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "aws4": "1.12.0", + "handlebars": "4.7.8", + "httpntlm": "1.8.13", + "jose": "4.14.4", "js-sha512": "0.8.0", "lodash": "4.17.21", - "mime-types": "2.1.34", + "mime-types": "2.1.35", "node-oauth1": "1.3.0", "performance-now": "2.1.0", - "postman-collection": "4.1.1", - "postman-request": "2.88.1-postman.31", - "postman-sandbox": "4.0.6", + "postman-collection": "4.2.0", + "postman-request": "2.88.1-postman.33", + "postman-sandbox": "4.2.7", "postman-url-encoder": "3.0.5", "serialised-error": "1.1.3", - "tough-cookie": "3.0.1", + "strip-json-comments": "3.1.1", "uuid": "8.3.2" }, "dependencies": { - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", "dev": true, "requires": { - "mime-db": "1.51.0" + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" } }, "uuid": { @@ -11236,14 +11704,51 @@ } }, "postman-sandbox": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.0.6.tgz", - "integrity": "sha512-PPRanSNEE4zy3kO7CeSBHmAfJnGdD9ecHY/Mjh26CQuZZarGkNO8c0U/n+xX3+5M1BRNc82UYq6YCtdsSDqcng==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.2.7.tgz", + "integrity": "sha512-/EcCrKnb/o+9iLS4u+H76E0kBomJFjPptVjoDiq1uZ7Es/4aTv0MAX+0aoDxdDO+0h9sl8vy65uKQwyjN7AOaw==", "dev": true, "requires": { "lodash": "4.17.21", + "postman-collection": "4.2.0", "teleport-javascript": "1.0.0", - "uvm": "2.0.2" + "uvm": "2.1.1" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", + "dev": true, + "requires": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "postman-url-encoder": { @@ -11315,12 +11820,23 @@ "side-channel": "^1.0.4" } }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -11415,6 +11931,12 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -11475,15 +11997,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, "semaphore": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", @@ -11491,9 +12004,9 @@ "dev": true }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -11605,20 +12118,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "requires": { - "semver": "~7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } + "semver": "^7.5.3" } }, "sinon": { @@ -11719,6 +12224,16 @@ "bluebird": "^2.6.2" } }, + "streamx": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.17.0.tgz", + "integrity": "sha512-mzRXEeafEA0skX5XLiDht/zdIqEVs4kgayUTFHDoMjiaZ2kC7DoFsQDJVXRILI2Qme/kWXxLpuU6P0B+xcXpFA==", + "requires": { + "bare-events": "^2.2.0", + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -11786,29 +12301,13 @@ } }, "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - } + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, "teleport-javascript": { @@ -11857,26 +12356,15 @@ } } }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "optional": true }, "tweetnacl": { @@ -11949,6 +12437,12 @@ "util-deprecate": "^1.0.2" } }, + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -11969,6 +12463,16 @@ "integrity": "sha512-8pMuAn4KacYdGMkFaoQARicp4HSw24/DHOVKWqVRJ8LhhAwPPFpdGvdL9184JVmUwe7vz7Z9n6IqI6t5n2ELdg==", "dev": true }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -11985,18 +12489,18 @@ "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "uvm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.0.2.tgz", - "integrity": "sha512-Ra+aPiS5GXAbwXmyNExqdS42sTqmmx4XWEDF8uJlsTfOkKf9Rd9xNgav1Yckv4HfVEZg4iOFODWHFYuJ+9Fzfg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", + "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", "dev": true, "requires": { - "flatted": "3.1.1" + "flatted": "3.2.6" }, "dependencies": { "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true } } @@ -12058,9 +12562,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wordwrap": { diff --git a/package.json b/package.json index 57b5ea4..f1cf1d6 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,15 @@ { "name": "backend", "private": true, - "version": "2.2.0", + "version": "3.0.0", "description": "", "main": "index.js", "scripts": { "test": "NODE_ENV=test ./node_modules/.bin/mocha ./tests/index.js", "test:helper": "NODE_ENV=test ./node_modules/.bin/mocha ./tests/helper/index.js", "test:newman": "newman run postman.json", - "dev": "./node_modules/.bin/nodemon -w . -w .env index.js", + "dev": "./node_modules/.bin/nodemon -i plugins -w . -w .env index.js", + "dev:plugin": "./node_modules/.bin/nodemon -w plugins -w . -w .env index.js", "lint": "./node_modules/.bin/eslint .", "lint:fix": "./node_modules/.bin/eslint --fix .", "mocha": "./node_modules/.bin/mocha ./tests/index.js", @@ -22,7 +23,7 @@ "publish": "grunt publish" }, "engines": { - "node": ">=0.16.0" + "node": ">=18.0.0" }, "author": "Marc Stirner ", "license": "ISC", @@ -38,6 +39,8 @@ "jsonwebtoken": "^9.0.0", "mongodb": "^4.11.0", "mqtt-packet": "^8.1.2", + "semver": "^7.5.4", + "tar-stream": "^3.1.7", "uuid": "^9.0.0", "ws": "^8.10.0" }, @@ -48,11 +51,12 @@ "grunt-contrib-uglify": "^5.0.1", "grunt-env": "^1.0.1", "grunt-run": "^0.8.1", + "husky": "^8.0.3", "minimist": "^1.2.6", "mocha": "^9.2.2", "mocha.parallel": "^0.15.6", - "newman": "^5.3.2", - "nodemon": "^2.0.19", + "newman": "^6.0.0", + "nodemon": "^3.0.1", "sinon": "^14.0.2" } -} \ No newline at end of file +} diff --git a/postman.json b/postman.json index 56b667a..73ca0b8 100644 --- a/postman.json +++ b/postman.json @@ -1,9 +1,10 @@ { "info": { - "_postman_id": "7c990139-b42a-4603-9c76-841a6cda01aa", + "_postman_id": "af00c0a1-994e-4e2c-aac9-422c102b70f1", "name": "OpenHaus", "description": "SmartHome/IoT application", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "6522444" }, "item": [ { @@ -28,37 +29,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -69,7 +40,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Livingroom\"\n}", + "raw": "{\n \"_id\": \"65818753e275da05046aaa78\",\n \"name\": \"Livingroom\",\n \"labels\": [\n \"foo=bar\",\n \"baz=true\"\n ]\n}", "options": { "raw": { "language": "json" @@ -107,16 +78,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"The response has all properties\", () => {", - " let json = pm.response.json();", - " pm.expect(json).to.have.lengthOf(json.length);", - "});", - "", - "pm.test(\"Status code is 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "console.log(\"Fooo\")" + "" ], "type": "text/javascript" } @@ -183,7 +145,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/rooms/{{_id}}", + "raw": "http://{{HOST}}:{{PORT}}/api/rooms/65818753e275da05046aaa78", "protocol": "http", "host": [ "{{HOST}}" @@ -192,7 +154,7 @@ "path": [ "api", "rooms", - "{{_id}}" + "65818753e275da05046aaa78" ] } }, @@ -205,29 +167,7 @@ "listen": "prerequest", "script": { "exec": [ - "const HOST = pm.collectionVariables.get(\"HOST\");", - "const PORT = pm.collectionVariables.get(\"PORT\");", - "", - "//console.log(pm.request.url.toString())", - "", - "pm.sendRequest({", - " url: `http://${HOST}:${PORT}/api/rooms/`,", - " method: 'GET',", - "}, function (err, res) {", - " if(err){", - "", - " consle.error(err);", - "", - " }else {", - "", - " let data = res.json();", - " let key = Math.floor(Math.random()*data.length);", - " let item = data[key];", - "", - " pm.variables.set(\"_id\", item._id);", - "", - " }", - "});" + "" ], "type": "text/javascript" } @@ -246,7 +186,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/rooms/63bf017582fa29f44cf8dfd6", + "raw": "http://{{HOST}}:{{PORT}}/api/rooms/65818753e275da05046aaa78", "protocol": "http", "host": [ "{{HOST}}" @@ -255,7 +195,7 @@ "path": [ "api", "rooms", - "63bf017582fa29f44cf8dfd6" + "65818753e275da05046aaa78" ] } }, @@ -268,7 +208,7 @@ "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" + "" ], "type": "text/javascript" } @@ -277,11 +217,7 @@ "listen": "test", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } @@ -291,7 +227,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/rooms/63bf017582fa29f44cf8dfd6", + "raw": "http://{{HOST}}:{{PORT}}/api/rooms/65818753e275da05046aaa78", "protocol": "http", "host": [ "{{HOST}}" @@ -300,7 +236,7 @@ "path": [ "api", "rooms", - "63bf017582fa29f44cf8dfd6" + "65818753e275da05046aaa78" ] } }, @@ -347,37 +283,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -388,7 +294,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Evening\",\n \"makros\": [{\n \"type\": \"command\",\n \"endpoint\": \"63a0ce5b33d59ec69d8ffe18\",\n \"command\": \"63a0ce5b33d59ec69d8ffe19\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426bf\",\n \"command\": \"63a1753f44427ef1a83426c0\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426af\",\n \"command\": \"63a1753f44427ef1a83426b0\"\n }]\n}", + "raw": "{\n \"_id\": \"658187db41c59ef57eb25df8\",\n \"name\": \"Evening\",\n \"makros\": [{\n \"type\": \"command\",\n \"endpoint\": \"63a0ce5b33d59ec69d8ffe18\",\n \"command\": \"63a0ce5b33d59ec69d8ffe19\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426bf\",\n \"command\": \"63a1753f44427ef1a83426c0\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426af\",\n \"command\": \"63a1753f44427ef1a83426b0\"\n }]\n}", "options": { "raw": { "language": "json" @@ -426,16 +332,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"The response has all properties\", () => {", - " let json = pm.response.json();", - " pm.expect(json).to.have.lengthOf(json.length);", - "});", - "", - "pm.test(\"Status code is 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "console.log(\"Fooo\")" + "" ], "type": "text/javascript" } @@ -498,7 +395,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6403506b0b4fe3536f0ba8d5", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8", "protocol": "http", "host": [ "{{HOST}}" @@ -507,39 +404,19 @@ "path": [ "api", "scenes", - "6403506b0b4fe3536f0ba8d5" + "658187db41c59ef57eb25df8" ] } }, "response": [] }, { - "name": "Update existing scene", - "event": [ - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], + "name": "Get scene state", "request": { - "method": "PATCH", + "method": "GET", "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"name\": \"Evening\",\n \"makros\": [{\n \"type\": \"command\",\n \"endpoint\": \"63a0ce5b33d59ec69d8ffe18\",\n \"command\": \"63a0ce5b33d59ec69d8ffe19\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426bf\",\n \"command\": \"63a1753f44427ef1a83426c0\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426af\",\n \"command\": \"63a1753f44427ef1a83426b0\"\n }]\n}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6406218c7f1a9f7c3f2b92e2", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8/state", "protocol": "http", "host": [ "{{HOST}}" @@ -548,43 +425,40 @@ "path": [ "api", "scenes", - "6406218c7f1a9f7c3f2b92e2" + "658187db41c59ef57eb25df8", + "state" ] } }, "response": [] }, { - "name": "Delete exisiting scene", + "name": "Update existing scene", "event": [ { "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" - ], - "type": "text/javascript" - } - }, - { - "listen": "test", - "script": { - "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } } ], "request": { - "method": "DELETE", + "method": "PATCH", "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Evening\",\n \"makros\": [{\n \"type\": \"command\",\n \"endpoint\": \"63a0ce5b33d59ec69d8ffe18\",\n \"command\": \"63a0ce5b33d59ec69d8ffe19\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426bf\",\n \"command\": \"63a1753f44427ef1a83426c0\"\n }, {\n \"type\": \"timer\",\n \"value\": \"3000\"\n }, {\n \"type\": \"command\",\n \"endpoint\": \"63a1753f44427ef1a83426af\",\n \"command\": \"63a1753f44427ef1a83426b0\"\n }]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6403506b0b4fe3536f0ba8d5", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8", "protocol": "http", "host": [ "{{HOST}}" @@ -593,7 +467,7 @@ "path": [ "api", "scenes", - "6403506b0b4fe3536f0ba8d5" + "658187db41c59ef57eb25df8" ] } }, @@ -605,7 +479,7 @@ "method": "POST", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6403506b0b4fe3536f0ba8d5/trigger", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8/trigger", "protocol": "http", "host": [ "{{HOST}}" @@ -614,7 +488,7 @@ "path": [ "api", "scenes", - "6403506b0b4fe3536f0ba8d5", + "658187db41c59ef57eb25df8", "trigger" ] } @@ -627,7 +501,7 @@ "method": "POST", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6403506b0b4fe3536f0ba8d5/abort", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8/abort", "protocol": "http", "host": [ "{{HOST}}" @@ -636,7 +510,7 @@ "path": [ "api", "scenes", - "6403506b0b4fe3536f0ba8d5", + "658187db41c59ef57eb25df8", "abort" ] } @@ -644,12 +518,32 @@ "response": [] }, { - "name": "Get scene state", + "name": "Delete exisiting scene", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], "request": { - "method": "GET", + "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/scenes/6403506b0b4fe3536f0ba8d5/state", + "raw": "http://{{HOST}}:{{PORT}}/api/scenes/658187db41c59ef57eb25df8", "protocol": "http", "host": [ "{{HOST}}" @@ -658,8 +552,7 @@ "path": [ "api", "scenes", - "6403506b0b4fe3536f0ba8d5", - "state" + "658187db41c59ef57eb25df8" ] } }, @@ -706,37 +599,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -747,7 +610,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"shelly*.local\",\n \"type\": \"A\"\n}", + "raw": "{\n \"_id\": \"658188273df500c8cd1524cc\",\n \"name\": \"shelly*.local\",\n \"type\": \"A\"\n}", "options": { "raw": { "language": "json" @@ -785,16 +648,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"The response has all properties\", () => {", - " let json = pm.response.json();", - " pm.expect(json).to.have.lengthOf(json.length);", - "});", - "", - "pm.test(\"Status code is 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "console.log(\"Fooo\")" + "" ], "type": "text/javascript" } @@ -851,7 +705,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mdns/63e7f7ba26b161df7f3af1d6", + "raw": "http://{{HOST}}:{{PORT}}/api/mdns/658188273df500c8cd1524cc", "protocol": "http", "host": [ "{{HOST}}" @@ -860,7 +714,7 @@ "path": [ "api", "mdns", - "63e7f7ba26b161df7f3af1d6" + "658188273df500c8cd1524cc" ] } }, @@ -873,29 +727,7 @@ "listen": "prerequest", "script": { "exec": [ - "const HOST = pm.collectionVariables.get(\"HOST\");", - "const PORT = pm.collectionVariables.get(\"PORT\");", - "", - "//console.log(pm.request.url.toString())", - "", - "pm.sendRequest({", - " url: `http://${HOST}:${PORT}/api/rooms/`,", - " method: 'GET',", - "}, function (err, res) {", - " if(err){", - "", - " consle.error(err);", - "", - " }else {", - "", - " let data = res.json();", - " let key = Math.floor(Math.random()*data.length);", - " let item = data[key];", - "", - " pm.variables.set(\"_id\", item._id);", - "", - " }", - "});" + "" ], "type": "text/javascript" } @@ -914,7 +746,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mdns/63e7f7ba26b161df7f3af1d6", + "raw": "http://{{HOST}}:{{PORT}}/api/mdns/658188273df500c8cd1524cc", "protocol": "http", "host": [ "{{HOST}}" @@ -923,7 +755,7 @@ "path": [ "api", "mdns", - "63e7f7ba26b161df7f3af1d6" + "658188273df500c8cd1524cc" ] } }, @@ -936,7 +768,7 @@ "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" + "" ], "type": "text/javascript" } @@ -945,11 +777,7 @@ "listen": "test", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } @@ -959,7 +787,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mdns/63e7f7ba26b161df7f3af1d6", + "raw": "http://{{HOST}}:{{PORT}}/api/mdns/658188273df500c8cd1524cc", "protocol": "http", "host": [ "{{HOST}}" @@ -968,7 +796,7 @@ "path": [ "api", "mdns", - "63e7f7ba26b161df7f3af1d6" + "658188273df500c8cd1524cc" ] } }, @@ -1015,37 +843,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -1056,7 +854,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"topic\": \"air-sensor/sensor/particulate_matter_25m_concentration\"\n}", + "raw": "{\n \"_id\": \"65818856464bebcf19ebec4c\",\n \"topic\": \"air-sensor/sensor/particulate_matter_25m_concentration\",\n \"labels\": [\n \"manufacturer=custom\",\n \"esp8266=true\"\n ]\n}", "options": { "raw": { "language": "json" @@ -1094,16 +892,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"The response has all properties\", () => {", - " let json = pm.response.json();", - " pm.expect(json).to.have.lengthOf(json.length);", - "});", - "", - "pm.test(\"Status code is 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "console.log(\"Fooo\")" + "" ], "type": "text/javascript" } @@ -1160,7 +949,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/63e8f7d2ab413a9760e9b08c", + "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/65818856464bebcf19ebec4c", "protocol": "http", "host": [ "{{HOST}}" @@ -1169,7 +958,7 @@ "path": [ "api", "mqtt", - "63e8f7d2ab413a9760e9b08c" + "65818856464bebcf19ebec4c" ] } }, @@ -1182,29 +971,7 @@ "listen": "prerequest", "script": { "exec": [ - "const HOST = pm.collectionVariables.get(\"HOST\");", - "const PORT = pm.collectionVariables.get(\"PORT\");", - "", - "//console.log(pm.request.url.toString())", - "", - "pm.sendRequest({", - " url: `http://${HOST}:${PORT}/api/rooms/`,", - " method: 'GET',", - "}, function (err, res) {", - " if(err){", - "", - " consle.error(err);", - "", - " }else {", - "", - " let data = res.json();", - " let key = Math.floor(Math.random()*data.length);", - " let item = data[key];", - "", - " pm.variables.set(\"_id\", item._id);", - "", - " }", - "});" + "" ], "type": "text/javascript" } @@ -1215,7 +982,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"description\": \"Ikea VINDRIKTNING MQTT modd\"\n}", + "raw": "{\n \"description\": \"Ikea VINDRIKTNING MQTT mod\",\n \"labels\": [\n \"manufacturer=Ikea\",\n \"model=VINDRIKTNING\",\n \"esp8266=true\"\n ]\n}", "options": { "raw": { "language": "json" @@ -1223,7 +990,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/63e8f7d2ab413a9760e9b08c", + "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/65818856464bebcf19ebec4c", "protocol": "http", "host": [ "{{HOST}}" @@ -1232,7 +999,7 @@ "path": [ "api", "mqtt", - "63e8f7d2ab413a9760e9b08c" + "65818856464bebcf19ebec4c" ] } }, @@ -1245,7 +1012,7 @@ "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" + "" ], "type": "text/javascript" } @@ -1254,11 +1021,7 @@ "listen": "test", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } @@ -1268,7 +1031,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/63e8f7d2ab413a9760e9b08c", + "raw": "http://{{HOST}}:{{PORT}}/api/mqtt/65818856464bebcf19ebec4c", "protocol": "http", "host": [ "{{HOST}}" @@ -1277,7 +1040,7 @@ "path": [ "api", "mqtt", - "63e8f7d2ab413a9760e9b08c" + "65818856464bebcf19ebec4c" ] } }, @@ -1324,37 +1087,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -1365,7 +1098,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"nt\": \"urn:schemas-upnp-org:device:sensor:1\",\n \"description\": null,\n \"usn\": null\n}", + "raw": "{\n \"_id\": \"65818876deb8cb80755ade02\",\n \"nt\": \"urn:schemas-upnp-org:device:sensor:1\"\n}", "options": { "raw": { "language": "json" @@ -1403,16 +1136,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"The response has all properties\", () => {", - " let json = pm.response.json();", - " pm.expect(json).to.have.lengthOf(json.length);", - "});", - "", - "pm.test(\"Status code is 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "console.log(\"Fooo\")" + "" ], "type": "text/javascript" } @@ -1469,7 +1193,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/63cbcdb1f2c46434242de489", + "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/65818876deb8cb80755ade02", "protocol": "http", "host": [ "{{HOST}}" @@ -1478,7 +1202,7 @@ "path": [ "api", "ssdp", - "63cbcdb1f2c46434242de489" + "65818876deb8cb80755ade02" ] } }, @@ -1510,7 +1234,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/63cbcdb1f2c46434242de489", + "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/65818876deb8cb80755ade02", "protocol": "http", "host": [ "{{HOST}}" @@ -1519,7 +1243,7 @@ "path": [ "api", "ssdp", - "63cbcdb1f2c46434242de489" + "65818876deb8cb80755ade02" ] } }, @@ -1532,7 +1256,7 @@ "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" + "" ], "type": "text/javascript" } @@ -1541,11 +1265,7 @@ "listen": "test", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } @@ -1555,7 +1275,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/63cbcdb1f2c46434242de489", + "raw": "http://{{HOST}}:{{PORT}}/api/ssdp/65818876deb8cb80755ade02", "protocol": "http", "host": [ "{{HOST}}" @@ -1564,7 +1284,7 @@ "path": [ "api", "ssdp", - "63cbcdb1f2c46434242de489" + "65818876deb8cb80755ade02" ] } }, @@ -1611,37 +1331,7 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Check room name: input = output\", () => {", - "", - " let res = pm.response.json();", - " let req = JSON.parse(pm.request.body);", - "", - " pm.expect(res.name).to.eql(req.name);", - "", - "});", - "", - "pm.test(\"Check properties\", () => {", - "", - " let res = pm.response.json();", - "", - " let props = [", - " \"name\", \"timestamps\", \"_id\",", - " \"number\", \"floor\", \"icon\"", - " ];", - "", - " Object.keys(res).forEach((key) => {", - " pm.expect(props.includes(key)).to.be.true;", - " });", - "", - " props.forEach((item) => {", - " pm.expect(Object.prototype.hasOwnProperty.call(res, item)).to.be.true;", - " });", - "", - "})" + "" ], "type": "text/javascript" } @@ -1652,7 +1342,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Hans Hubert #3\",\n \"email\": \"hans.hubert3@example.com\",\n \"password\": \"Pa$$w0rd\"\n}", + "raw": "{\n \"_id\": \"658188a7aadfcc026a0e0131\",\n \"name\": \"Hans Hubert #3\",\n \"email\": \"hans.hubert3@example.com\",\n \"password\": \"Pa$$w0rd\",\n \"labels\": [\n \"expires=29991231\"\n ]\n}", "options": { "raw": { "language": "json" @@ -1752,7 +1442,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/users/6288b67b1f3bc42774ce0ec1", + "raw": "http://{{HOST}}:{{PORT}}/api/users/658188a7aadfcc026a0e0131", "protocol": "http", "host": [ "{{HOST}}" @@ -1761,7 +1451,7 @@ "path": [ "api", "users", - "6288b67b1f3bc42774ce0ec1" + "658188a7aadfcc026a0e0131" ] } }, @@ -1774,29 +1464,7 @@ "listen": "prerequest", "script": { "exec": [ - "const HOST = pm.collectionVariables.get(\"HOST\");", - "const PORT = pm.collectionVariables.get(\"PORT\");", - "", - "//console.log(pm.request.url.toString())", - "", - "pm.sendRequest({", - " url: `http://${HOST}:${PORT}/api/rooms/`,", - " method: 'GET',", - "}, function (err, res) {", - " if(err){", - "", - " consle.error(err);", - "", - " }else {", - "", - " let data = res.json();", - " let key = Math.floor(Math.random()*data.length);", - " let item = data[key];", - "", - " pm.variables.set(\"_id\", item._id);", - "", - " }", - "});" + "" ], "type": "text/javascript" } @@ -1815,7 +1483,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/users/6288b67b1f3bc42774ce0ec1", + "raw": "http://{{HOST}}:{{PORT}}/api/users/658188a7aadfcc026a0e0131", "protocol": "http", "host": [ "{{HOST}}" @@ -1824,7 +1492,7 @@ "path": [ "api", "users", - "6288b67b1f3bc42774ce0ec1" + "658188a7aadfcc026a0e0131" ] } }, @@ -1837,7 +1505,7 @@ "listen": "prerequest", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));" + "" ], "type": "text/javascript" } @@ -1846,11 +1514,7 @@ "listen": "test", "script": { "exec": [ - "console.log(\"_id varaible\", pm.variables.get(\"_id\"));", - "", - "pm.test(\"status code: 200\", () => {", - " pm.response.to.have.status(200);", - "});" + "" ], "type": "text/javascript" } @@ -1860,7 +1524,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/users/6288b67b1f3bc42774ce0ec1", + "raw": "http://{{HOST}}:{{PORT}}/api/users/658188a7aadfcc026a0e0131", "protocol": "http", "host": [ "{{HOST}}" @@ -1869,7 +1533,7 @@ "path": [ "api", "users", - "6288b67b1f3bc42774ce0ec1" + "658188a7aadfcc026a0e0131" ] } }, @@ -1907,7 +1571,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Phoscon Gateway\",\n \"enabled\": true,\n \"version\": 1,\n \"intents\": [\n \"devices\", \n \"endpoints\", \n \"ssdp\", \n \"vault\", \n \"store\"\n ]\n}", + "raw": "{\n \"_id\": \"658188e93cde9987c3228806\",\n \"name\": \"Plugin Boilerplate Demo\",\n \"uuid\": \"6951dee2-8541-4a69-bd3e-629fdadf093a\",\n \"enabled\": true,\n \"version\": \"1.0.0\",\n \"intents\": [\n \"devices\",\n \"endpoints\",\n \"plugins\",\n \"rooms\",\n \"ssdp\",\n \"store\",\n \"users\",\n \"vault\"\n ]\n}", "options": { "raw": { "language": "json" @@ -1931,18 +1595,12 @@ "response": [] }, { - "name": "Upload plugin *.tgz content", + "name": "Get all plugins", "request": { - "method": "PUT", + "method": "GET", "header": [], - "body": { - "mode": "file", - "file": { - "src": "" - } - }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/63a17284ba003ca7440f97e3/files", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins", "protocol": "http", "host": [ "{{HOST}}" @@ -1950,27 +1608,19 @@ "port": "{{PORT}}", "path": [ "api", - "plugins", - "63a17284ba003ca7440f97e3", - "files" + "plugins" ] } }, "response": [] }, { - "name": "Delete plugin *.tgz content", + "name": "Get sinlge plugin", "request": { - "method": "DELETE", + "method": "GET", "header": [], - "body": { - "mode": "file", - "file": { - "src": "/home/marc/projects/playground/oh-plg-dummy/oh-plg-dummy-v1.0.0.tgz" - } - }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/639efd69e42746a787a02455/files", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806", "protocol": "http", "host": [ "{{HOST}}" @@ -1979,20 +1629,28 @@ "path": [ "api", "plugins", - "639efd69e42746a787a02455", - "files" + "658188e93cde9987c3228806" ] } }, "response": [] }, { - "name": "Get all plugins", + "name": "Update existing plugins", "request": { - "method": "GET", + "method": "PATCH", "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"New updated\",\n \"enabled\": true,\n \"autostart\": false,\n \"version\": \"9.2.5\",\n \"labels\": [\n \"worker_thread=false\",\n \"my_custom_label={\\\"json\\\":true, \\\"number\\\":0815420}\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806", "protocol": "http", "host": [ "{{HOST}}" @@ -2000,19 +1658,48 @@ "port": "{{PORT}}", "path": [ "api", - "plugins" + "plugins", + "658188e93cde9987c3228806" ] } }, "response": [] }, { - "name": "Get sinlge plugin", + "name": "Upload plugin *.tgz content", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], "request": { - "method": "GET", + "method": "PUT", "header": [], + "body": { + "mode": "file", + "file": { + "src": "/home/marc/projects/OpenHaus/plugins/plugin-boilerplate/dist/oh-plg-plugin-boilerplate.tgz" + } + }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806/files?install=true", "protocol": "http", "host": [ "{{HOST}}" @@ -2021,28 +1708,27 @@ "path": [ "api", "plugins", - "" + "658188e93cde9987c3228806", + "files" + ], + "query": [ + { + "key": "install", + "value": "true", + "description": "Install npm dependenys" + } ] } }, "response": [] }, { - "name": "Update existing plugins", + "name": "Start plugin", "request": { - "method": "PATCH", + "method": "POST", "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"enabled\": true,\n \"autostart\": false\n}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/61103781f897a74ae9ca89c7", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806/start", "protocol": "http", "host": [ "{{HOST}}" @@ -2051,19 +1737,26 @@ "path": [ "api", "plugins", - "61103781f897a74ae9ca89c7" + "658188e93cde9987c3228806", + "start" ] } }, "response": [] }, { - "name": "Delete exisiting plugins", + "name": "Delete plugin *.tgz content", "request": { "method": "DELETE", "header": [], + "body": { + "mode": "file", + "file": { + "src": "/home/marc/projects/playground/oh-plg-dummy/oh-plg-dummy-v1.0.0.tgz" + } + }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/62868c7e9af74130e98863c1", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806/files", "protocol": "http", "host": [ "{{HOST}}" @@ -2072,19 +1765,20 @@ "path": [ "api", "plugins", - "62868c7e9af74130e98863c1" + "658188e93cde9987c3228806", + "files" ] } }, "response": [] }, { - "name": "Start plugin", + "name": "Delete exisiting plugins", "request": { - "method": "POST", + "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/plugins/63f500ea2b40698e90e63beb/start", + "raw": "http://{{HOST}}:{{PORT}}/api/plugins/658188e93cde9987c3228806", "protocol": "http", "host": [ "{{HOST}}" @@ -2093,8 +1787,7 @@ "path": [ "api", "plugins", - "63f500ea2b40698e90e63beb", - "start" + "658188e93cde9987c3228806" ] } }, @@ -2112,7 +1805,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"SmartMeter\",\n \"interfaces\": [{\n \"type\": \"ETHERNET\",\n \"description\": \"WebSocket API\",\n \"settings\": {\n \"host\": \"192.168.2.155\",\n \"port\": 8080\n },\n \"adapter\": [\"raw\"]\n }],\n \"room\": \"62a4bc8bd9256b5e8d6988a0\",\n \"icon\": \"fa-solid fa-gauge-high\"\n}", + "raw": "{\n \"_id\": \"65818918d32dad8dab53e433\",\n \"name\": \"SmartMeter\",\n \"interfaces\": [{\n \"_id\": \"6581c55abc21a0a3122b9998\",\n \"type\": \"ETHERNET\",\n \"description\": \"WebSocket API\",\n \"settings\": {\n \"host\": \"192.168.2.155\",\n \"port\": 8080\n },\n \"adapter\": [\"raw\"]\n }],\n \"room\": \"62a4bc8bd9256b5e8d6988a0\",\n \"icon\": \"fa-solid fa-gauge-high\",\n \"labels\": [\n \"test=true\",\n \"protected=false\", \n \"foo=bar\"\n ]\n}", "options": { "raw": { "language": "json" @@ -2160,7 +1853,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/devices/6042785432c51e3e98e7acc0", + "raw": "http://{{HOST}}:{{PORT}}/api/devices/65818918d32dad8dab53e433", "protocol": "http", "host": [ "{{HOST}}" @@ -2169,7 +1862,7 @@ "path": [ "api", "devices", - "6042785432c51e3e98e7acc0" + "65818918d32dad8dab53e433" ] } }, @@ -2182,7 +1875,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"enabled\": true,\n \"name\": \"SaMsUnG FrIdGe\"\n}", + "raw": "{\n \"enabled\": true,\n \"name\": \"SaMsUnG FrIdGe\",\n \"labels\": [\n \"test=true\",\n \"protected=true\", \n \"foo=bar\"\n ]\n}", "options": { "raw": { "language": "json" @@ -2190,7 +1883,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/devices/63bf020e82fa29f44cf8dfd8", + "raw": "http://{{HOST}}:{{PORT}}/api/devices/65818918d32dad8dab53e433", "protocol": "http", "host": [ "{{HOST}}" @@ -2199,7 +1892,7 @@ "path": [ "api", "devices", - "63bf020e82fa29f44cf8dfd8" + "65818918d32dad8dab53e433" ] } }, @@ -2211,7 +1904,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/devices/61103caa50139f51160ae790", + "raw": "http://{{HOST}}:{{PORT}}/api/devices/65818918d32dad8dab53e433", "protocol": "http", "host": [ "{{HOST}}" @@ -2220,7 +1913,7 @@ "path": [ "api", "devices", - "61103caa50139f51160ae790" + "65818918d32dad8dab53e433" ] } }, @@ -2238,7 +1931,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"Dummy Endpoint\",\n \"device\": \"6398ae590dce390161f7fc2f\",\n \"states\": [\n {\n \"name\": \"Total Power\",\n \"alias\": \"POWER_TOTAL\",\n \"type\": \"number\"\n },\n {\n \"name\": \"Powerd on?\",\n \"alias\": \"POWERD_ON\",\n \"type\": \"boolean\"\n }\n ],\n \"commands\": [\n {\n \"name\": \"Switch to Input 03\",\n \"payload\": {\n \"type\": \"Buffer\",\n \"data\": [\n 115,\n 119,\n 32,\n 105,\n 48,\n 51,\n 13,\n 10\n ]\n },\n \"alias\": \"INPUT_03\",\n \"interface\": \"6398ae590dce390161f7fc30\"\n },\n {\n \"name\": \"Command as String\",\n \"payload\": \"foobar\",\n \"alias\": \"STRING_CMD\",\n \"interface\": \"6398ae590dce390161f7fc30\"\n }\n ]\n}\n", + "raw": "{\n \"_id\": \"658189336fa19198939caa21\",\n \"name\": \"Dummy Endpoint\",\n \"device\": \"6398ae590dce390161f7fc2f\",\n \"states\": [\n {\n \"_id\": \"658190d232fe653a07638863\",\n \"name\": \"Total Power\",\n \"alias\": \"POWER_TOTAL\",\n \"type\": \"number\"\n },\n {\n \"_id\": \"658190de4a1369d179c3387f\",\n \"name\": \"Powerd on?\",\n \"alias\": \"POWERD_ON\",\n \"type\": \"boolean\"\n }\n ],\n \"commands\": [\n {\n \"_id\": \"658190acbccb180491c2672c\",\n \"name\": \"Switch to Input 03\",\n \"payload\": {\n \"type\": \"Buffer\",\n \"data\": [\n 115,\n 119,\n 32,\n 105,\n 48,\n 51,\n 13,\n 10\n ]\n },\n \"alias\": \"INPUT_03\",\n \"interface\": \"6581c55abc21a0a3122b9998\"\n },\n {\n \"_id\": \"658190ec0e09c0d5d22c59f0\",\n \"name\": \"Command as String\",\n \"payload\": \"foobar\",\n \"alias\": \"STRING_CMD\",\n \"interface\": \"6581c55abc21a0a3122b9998\"\n }\n ]\n}\n", "options": { "raw": { "language": "json" @@ -2286,7 +1979,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/604a75e6eb5de037846df24f", + "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/658189336fa19198939caa21", "protocol": "http", "host": [ "{{HOST}}" @@ -2295,7 +1988,7 @@ "path": [ "api", "endpoints", - "604a75e6eb5de037846df24f" + "658189336fa19198939caa21" ] } }, @@ -2303,12 +1996,23 @@ }, { "name": "Update existing endpoint", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [], "body": { "mode": "raw", - "raw": " {\n \"_id\": \"63a5a4c2bd5fe7cb165960d0\",\n \"name\": \"Fernseher\",\n \"device\": \"63a5a4c2bd5fe7cb165960cd\",\n \"commands\": [\n {\n \"payload\": \"KEY_0\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_0\",\n \"name\": \"KEY_0\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d1\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_1\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_1\",\n \"name\": \"KEY_1\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d2\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_2\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_2\",\n \"name\": \"KEY_2\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d3\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_3\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_3\",\n \"name\": \"KEY_3\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d4\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_4\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_4\",\n \"name\": \"KEY_4\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d5\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_5\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_5\",\n \"name\": \"KEY_5\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d6\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_6\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_6\",\n \"name\": \"KEY_6\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d7\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_7\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_7\",\n \"name\": \"KEY_7\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d8\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_8\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_8\",\n \"name\": \"KEY_8\",\n \"_id\": \"63a5a4c2bd5fe7cb165960d9\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_9\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_9\",\n \"name\": \"KEY_9\",\n \"_id\": \"63a5a4c2bd5fe7cb165960da\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_10\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_10\",\n \"name\": \"KEY_10\",\n \"_id\": \"63a5a4c2bd5fe7cb165960db\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_11\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_11\",\n \"name\": \"KEY_11\",\n \"_id\": \"63a5a4c2bd5fe7cb165960dc\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_12\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_12\",\n \"name\": \"KEY_12\",\n \"_id\": \"63a5a4c2bd5fe7cb165960dd\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_CHDOWN\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_CHDOWN\",\n \"name\": \"KEY_CHDOWN\",\n \"_id\": \"63a5a4c2bd5fe7cb165960de\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_CHUP\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_CHUP\",\n \"name\": \"KEY_CHUP\",\n \"_id\": \"63a5a4c2bd5fe7cb165960df\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_VOLDOWN\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_VOLDOWN\",\n \"name\": \"KEY_VOLDOWN\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e0\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_VOLUP\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_VOLUP\",\n \"name\": \"KEY_VOLUP\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e1\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_MUTE\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_MUTE\",\n \"name\": \"KEY_MUTE\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e2\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_SOURCE\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_SOURCE\",\n \"name\": \"KEY_SOURCE\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e3\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_LEFT\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_LEFT\",\n \"name\": \"KEY_LEFT\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e4\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_RIGHT\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_RIGHT\",\n \"name\": \"KEY_RIGHT\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e5\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_UP\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_UP\",\n \"name\": \"KEY_UP\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e6\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_DOWN\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_DOWN\",\n \"name\": \"KEY_DOWN\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e7\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_ENTER\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_ENTER\",\n \"name\": \"KEY_ENTER\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e8\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_MENU\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_MENU\",\n \"name\": \"KEY_MENU\",\n \"_id\": \"63a5a4c2bd5fe7cb165960e9\",\n \"identifier\": null,\n \"description\": null\n },\n {\n \"payload\": \"KEY_EXIT\",\n \"interface\": \"63a5a4c2bd5fe7cb165960ce\",\n \"alias\": \"KEY_EXIT\",\n \"name\": \"KEY_EXIT\",\n \"_id\": \"63a5a4c2bd5fe7cb165960ea\",\n \"identifier\": null,\n \"description\": null\n }\n ],\n \"timestamps\": {\n \"created\": 1671800002321,\n \"updated\": null\n },\n \"enabled\": true,\n \"room\": \"62a4bbf0d9256b5e8d69889c\",\n \"states\": [],\n \"identifier\": null,\n \"icon\": \"fa-solid fa-tv\"\n }", + "raw": "{\n \"name\": \"Dummy Endpoint (name changed)\",\n \"device\": \"6398ae590dce390161f7fc2f\",\n \"commands\": [{\n \"_id\": \"6581fc8ac20cb522e02868ff\",\n \"name\": \"new command\",\n \"payload\": \"new_command\",\n \"alias\": \"new_cmd\",\n \"interface\": \"6398ae590dce390161f7fc30\"\n }]\n}\n", "options": { "raw": { "language": "json" @@ -2316,7 +2020,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/63a5a4c2bd5fe7cb165960d0", + "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/658189336fa19198939caa21", "protocol": "http", "host": [ "{{HOST}}" @@ -2325,19 +2029,28 @@ "path": [ "api", "endpoints", - "63a5a4c2bd5fe7cb165960d0" + "658189336fa19198939caa21" ] } }, "response": [] }, { - "name": "Delete exisiting endpoint", + "name": "Set endpoint state", "request": { - "method": "DELETE", + "method": "POST", "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"value\": 54\n}", + "options": { + "raw": { + "language": "json" + } + } + }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/61103caa50139f51160ae790", + "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/658189336fa19198939caa21/states/658190d232fe653a07638863", "protocol": "http", "host": [ "{{HOST}}" @@ -2346,9 +2059,12 @@ "path": [ "api", "endpoints", - "61103caa50139f51160ae790" + "658189336fa19198939caa21", + "states", + "658190d232fe653a07638863" ] - } + }, + "description": "TODO!" }, "response": [] }, @@ -2367,7 +2083,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/610e865a0c7edd636843a409/commands/610e865a0c7edd636843a406", + "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/658189336fa19198939caa21/commands/6581fc8ac20cb522e02868ff", "protocol": "http", "host": [ "{{HOST}}" @@ -2376,30 +2092,21 @@ "path": [ "api", "endpoints", - "610e865a0c7edd636843a409", + "658189336fa19198939caa21", "commands", - "610e865a0c7edd636843a406" + "6581fc8ac20cb522e02868ff" ] } }, "response": [] }, { - "name": "Set endpoint state", + "name": "Delete exisiting endpoint", "request": { - "method": "POST", + "method": "DELETE", "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"value\": 54\n}", - "options": { - "raw": { - "language": "json" - } - } - }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/6398b0bcf8a893ef43e283d5/states/6398b0bcf8a893ef43e283d8", + "raw": "http://{{HOST}}:{{PORT}}/api/endpoints/658189336fa19198939caa21", "protocol": "http", "host": [ "{{HOST}}" @@ -2408,12 +2115,9 @@ "path": [ "api", "endpoints", - "6398b0bcf8a893ef43e283d5", - "states", - "6398b0bcf8a893ef43e283d8" + "658189336fa19198939caa21" ] - }, - "description": "TODO!" + } }, "response": [] } @@ -2429,7 +2133,7 @@ "listen": "prerequest", "script": { "exec": [ - "pm.request.payload = JSON.parse(pm.request.body.raw);" + "" ], "type": "text/javascript" } @@ -2438,16 +2142,7 @@ "listen": "test", "script": { "exec": [ - "", - "", - "", - "console.log(pm.request.payload)", - "", - "pm.test(\"Input = Output name\", () => {", - "", - " ", - "", - "});" + "" ], "type": "text/javascript" } @@ -2458,7 +2153,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"FritzBox\",\n \"identifier\": \"FRITZBOX\",\n \"secrets\": [{\n \"key\": \"USERNAME\",\n \"name\": \"Username\",\n \"value\": \"username@example.com\"\n }, {\n \"key\": \"PASSWORD\",\n \"name\": \"Password\",\n \"value\": \"Pa$$w0rd\"\n }]\n}", + "raw": "{\n \"_id\": \"6581896929ae93ba734cc72a\",\n \"name\": \"FritzBox\",\n \"identifier\": \"FRITZBOX\",\n \"secrets\": [{\n \"_id\": \"65818cb27c731f3cba187149\",\n \"key\": \"USERNAME\",\n \"name\": \"Username\",\n \"value\": \"username@example.com\"\n }, {\n \"_id\": \"65818cbdb9302888a0b6ca35\",\n \"key\": \"PASSWORD\",\n \"name\": \"Password\",\n \"value\": \"Pa$$w0rd\"\n }]\n}", "options": { "raw": { "language": "json" @@ -2506,7 +2201,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/63a5a4c2bd5fe7cb165960eb", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a", "protocol": "http", "host": [ "{{HOST}}" @@ -2515,7 +2210,7 @@ "path": [ "api", "vault", - "63a5a4c2bd5fe7cb165960eb" + "6581896929ae93ba734cc72a" ] } }, @@ -2527,7 +2222,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/639c9562cece5101bdccdeb1/secrets", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a/secrets", "protocol": "http", "host": [ "{{HOST}}" @@ -2536,7 +2231,7 @@ "path": [ "api", "vault", - "639c9562cece5101bdccdeb1", + "6581896929ae93ba734cc72a", "secrets" ] } @@ -2558,7 +2253,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/637a5f290a21379bf30c62be/secrets/637a614b0a21379bf30c62c2/encrypt", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a/secrets/65818cb27c731f3cba187149/encrypt", "protocol": "http", "host": [ "{{HOST}}" @@ -2567,9 +2262,9 @@ "path": [ "api", "vault", - "637a5f290a21379bf30c62be", + "6581896929ae93ba734cc72a", "secrets", - "637a614b0a21379bf30c62c2", + "65818cb27c731f3cba187149", "encrypt" ] } @@ -2583,7 +2278,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"PASSWORD\": \"Pa$$w0rd\",\n \"USERNAME\": \"user-1@example.com\"\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -2591,7 +2286,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/637a5f290a21379bf30c62be/secrets/637a614b0a21379bf30c62c2/decrypt", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a/secrets/65818cb27c731f3cba187149/decrypt", "protocol": "http", "host": [ "{{HOST}}" @@ -2600,9 +2295,9 @@ "path": [ "api", "vault", - "637a5f290a21379bf30c62be", + "6581896929ae93ba734cc72a", "secrets", - "637a614b0a21379bf30c62c2", + "65818cb27c731f3cba187149", "decrypt" ] } @@ -2624,7 +2319,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/61a15b436d63a6517e1385ed", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a", "protocol": "http", "host": [ "{{HOST}}" @@ -2633,7 +2328,7 @@ "path": [ "api", "vault", - "61a15b436d63a6517e1385ed" + "6581896929ae93ba734cc72a" ] } }, @@ -2645,7 +2340,7 @@ "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/vault/", + "raw": "http://{{HOST}}:{{PORT}}/api/vault/6581896929ae93ba734cc72a", "protocol": "http", "host": [ "{{HOST}}" @@ -2654,7 +2349,7 @@ "path": [ "api", "vault", - "" + "6581896929ae93ba734cc72a" ] } }, @@ -2672,7 +2367,7 @@ "listen": "prerequest", "script": { "exec": [ - "pm.request.payload = JSON.parse(pm.request.body.raw);" + "" ], "type": "text/javascript" } @@ -2681,16 +2376,7 @@ "listen": "test", "script": { "exec": [ - "", - "", - "", - "console.log(pm.request.payload)", - "", - "pm.test(\"Input = Output name\", () => {", - "", - " ", - "", - "});" + "" ], "type": "text/javascript" } @@ -2701,7 +2387,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"config\": [{\n \"key\": \"pairing\",\n \"type\": \"boolean\",\n \"value\": false,\n \"description\": \"Is the Gateway ready for pairing?\"\n }, {\n \"key\": \"interval\",\n \"type\": \"number\",\n \"value\": 3000,\n \"description\": \"Sync intervall for Endpoints\"\n }]\n}", + "raw": "{\n \"_id\": \"65818986ca5133d8de2bb4a1\",\n \"name\": \"Store name\",\n \"config\": [{\n \"_id\": \"6581a14f1c6d01f32129dabc\",\n \"name\": \"Device Pairing\",\n \"key\": \"pairing\",\n \"type\": \"boolean\",\n \"value\": false,\n \"description\": \"Is the Gateway ready for pairing?\"\n }, {\n \"_id\": \"6581a1520bcb15659d48b207\",\n \"name\": \"Polling interval\",\n \"key\": \"interval\",\n \"type\": \"number\",\n \"value\": 3000,\n \"description\": \"Sync intervall for Endpoints\"\n }]\n}", "options": { "raw": { "language": "json" @@ -2724,7 +2410,7 @@ "response": [] }, { - "name": "Get all config items", + "name": "Get all config stores", "request": { "method": "GET", "header": [], @@ -2744,12 +2430,12 @@ "response": [] }, { - "name": "Get single store item", + "name": "Get single store", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/626cf0d940cbe8290f0b4e3f", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1", "protocol": "http", "host": [ "{{HOST}}" @@ -2758,7 +2444,7 @@ "path": [ "api", "store", - "626cf0d940cbe8290f0b4e3f" + "65818986ca5133d8de2bb4a1" ] } }, @@ -2770,7 +2456,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/6377697882393a47683cc76c/config", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1/config", "protocol": "http", "host": [ "{{HOST}}" @@ -2779,7 +2465,7 @@ "path": [ "api", "store", - "6377697882393a47683cc76c", + "65818986ca5133d8de2bb4a1", "config" ] } @@ -2792,7 +2478,7 @@ "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/6377697882393a47683cc76c/config/6377697882393a47683cc76e", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1/config/6581a14f1c6d01f32129dabc", "protocol": "http", "host": [ "{{HOST}}" @@ -2801,9 +2487,9 @@ "path": [ "api", "store", - "6377697882393a47683cc76c", + "65818986ca5133d8de2bb4a1", "config", - "6377697882393a47683cc76e" + "6581a14f1c6d01f32129dabc" ] } }, @@ -2824,7 +2510,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/63a035ceb3add4c2c7b79d05/config/63a035ceb3add4c2c7b79d06", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1/config/6581a14f1c6d01f32129dabc", "protocol": "http", "host": [ "{{HOST}}" @@ -2833,9 +2519,9 @@ "path": [ "api", "store", - "63a035ceb3add4c2c7b79d05", + "65818986ca5133d8de2bb4a1", "config", - "63a035ceb3add4c2c7b79d06" + "6581a14f1c6d01f32129dabc" ] } }, @@ -2848,7 +2534,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"item\": \"6375343d0b555ccd42460a2e\"\n}", + "raw": "{\n \"labels\": [\n \"device=65818918d32dad8dab53e433\",\n \"endpoint=658189336fa19198939caa21\"\n ]\n}", "options": { "raw": { "language": "json" @@ -2856,7 +2542,7 @@ } }, "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/6375352db0c7df8ecab9e7ad", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1", "protocol": "http", "host": [ "{{HOST}}" @@ -2865,19 +2551,19 @@ "path": [ "api", "store", - "6375352db0c7df8ecab9e7ad" + "65818986ca5133d8de2bb4a1" ] } }, "response": [] }, { - "name": "Delete config entry", + "name": "Delete config store", "request": { "method": "DELETE", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/store/63a035ceb3add4c2c7b79d05", + "raw": "http://{{HOST}}:{{PORT}}/api/store/65818986ca5133d8de2bb4a1", "protocol": "http", "host": [ "{{HOST}}" @@ -2886,217 +2572,893 @@ "path": [ "api", "store", - "63a035ceb3add4c2c7b79d05" + "65818986ca5133d8de2bb4a1" ] } }, "response": [] } ] - } - ], - "auth": { - "type": "noauth" - }, - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "console.log(\"compoents pre request script\")", - "", - "", - "/*", - "", - " console.log(\"Name3\", name)", - "", - " let HOST = pm.collectionVariables.get(\"HOST\");", - " let PORT = pm.collectionVariables.get(\"PORT\");", - "", - " pm.sendRequest({", - " url: `http://${HOST}:${PORT}/api/${name}/`,", - " method: 'GET',", - " }, (err, res) => {", - " if(err){", - "", - " console.log(\"err\", err)", - "", - " consle.error(err);", - " done(err);", - "", - " }else {", - "", - " console.log(\"Callback\")", - "", - " let data = res.json();", - " let key = Math.floor(Math.random()*data.length);", - " let item = data[key];", - "", - " pm.variables.set(\"_id\", item._id);", - "", - " done(null, item._id);", - "", - " }", - " });", - "*/" - ] - } }, { - "listen": "test", + "name": "Webhooks", + "item": [ + { + "name": "Create new webhook", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"_id\": \"647c29cb62ad0449380f0abe\",\n \"name\": \"Test Webhook as trigger for scenes\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks" + ] + } + }, + "response": [] + }, + { + "name": "Get all webhooks", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "x-auth-token", + "value": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImhhbnMuaHViZXJ0QGV4YW1wbGUuY29tIiwidXVpZCI6ImM3N2E3NjJkLWM4ODYtNGQ2My1iNGM1LWU0MDJhZGNmYTdiZSIsImlhdCI6MTY1NDI2ODI4NX0.w4mkvTuJ-OXzTcmvWhwIT84oOmo2399hSEfWGbA-9SUWndMWUiHvly1A7-kSV93e", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks" + ] + } + }, + "response": [] + }, + { + "name": "Get sinlge webhook", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks/647c29cb62ad0449380f0abe", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks", + "647c29cb62ad0449380f0abe" + ] + } + }, + "response": [] + }, + { + "name": "Update existing webhook", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"name\": \"Trigger scene \"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks/647c29cb62ad0449380f0abe", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks", + "647c29cb62ad0449380f0abe" + ] + } + }, + "response": [] + }, + { + "name": "Update existing webhook", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks/647c29cb62ad0449380f0abe/trigger", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks", + "647c29cb62ad0449380f0abe", + "trigger" + ] + } + }, + "response": [] + }, + { + "name": "Delete exisiting room", + "event": [ + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + }, + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/webhooks/647c29cb62ad0449380f0abe", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "webhooks", + "647c29cb62ad0449380f0abe" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "auth": { + "type": "noauth" + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", "script": { "type": "text/javascript", "exec": [ - "pm.test(\"application/content = json\", () => {", - " pm.response.to.be.json", - "});", - "", - "pm.test(\"Response has no error field\", () => {", - " let json = pm.response.json();", - " pm.expect(!json.error);", - "});" + "" ] } } ] }, { - "name": "Logfiles", + "name": "Authentication", "item": [ { - "name": "Get logfile entrys", + "name": "Login", + "request": { + "method": "POST", + "header": [ + { + "key": "x-auth-token", + "value": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImhhbnMuaHViZXJ0QGV4YW1wbGUuY29tIiwidXVpZCI6ImM3N2E3NjJkLWM4ODYtNGQ2My1iNGM1LWU0MDJhZGNmYTdiZSIsImlhdCI6MTY1MzUyMDM1Mn0.10H4v6IhiI2mlaiSAcbTp2m4QUSueA1l4c2CPGV8L7WltZfXia8pLCnbYC243LPz", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"email\": \"hans.hubert@example.com\",\n \"password\": \"Pa$$w0rd\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/auth/login", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "auth", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Logout", + "request": { + "method": "POST", + "header": [ + { + "key": "x-auth-token", + "value": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImhhbnMuaHViZXJ0QGV4YW1wbGUuY29tIiwidXVpZCI6ImM3N2E3NjJkLWM4ODYtNGQ2My1iNGM1LWU0MDJhZGNmYTdiZSIsImlhdCI6MTY1MzUxOTUwNH0.5iByWpBxCHVj0c1mHEv0Skz47SSGps7BbfDOPVFppSFWwJfLwa09jx8MSBrJTC_E", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/auth/logout", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "auth", + "logout" + ] + } + }, + "response": [] + }, + { + "name": "Check if auth is required", "request": { "method": "GET", "header": [], "url": { - "raw": "http://{{HOST}}:{{PORT}}/api/logs/?offset=0&limit=3", + "raw": "http://{{HOST}}:{{PORT}}/auth", "protocol": "http", "host": [ "{{HOST}}" ], "port": "{{PORT}}", "path": [ - "api", - "logs", - "" - ], - "query": [ - { - "key": "offset", - "value": "0" + "auth" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "System", + "item": [ + { + "name": "Notifications", + "item": [ + { + "name": "Create notification", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"title\": \"Title\",\n \"message\": \"Hello World\",\n \"type\": \"error\",\n \"uuid\": \"83d2087a-d901-4eb5-ac05-f7980893df64\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/notifications?publish=false", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "notifications" + ], + "query": [ + { + "key": "publish", + "value": "false", + "description": "Publish notifications instantly?" + } + ] + } + }, + "response": [] + }, + { + "name": "Get notifications", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"title\": \"Title\",\n \"message\": \"Hello World\",\n \"type\": \"error\",\n \"uuid\": \"83d2087a-d901-4eb5-ac05-f7980893df64\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/notifications", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "notifications" + ] + } + }, + "response": [] + }, + { + "name": "Publish notification", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/notifications/83d2087a-d901-4eb5-ac05-f7980893df64/publish", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "notifications", + "83d2087a-d901-4eb5-ac05-f7980893df64", + "publish" + ] + } + }, + "response": [] + }, + { + "name": "Delete notification", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"title\": \"Title\",\n \"message\": \"Hello World\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/notifications/83d2087a-d901-4eb5-ac05-f7980893df64", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "notifications", + "83d2087a-d901-4eb5-ac05-f7980893df64" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Logging", + "item": [ + { + "name": "Get log entrys", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/logs?offset=0&limit=10", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "logs" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "10" + } + ] + } + }, + "response": [] + }, + { + "name": "Create log entry", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"message\": \"Hello World\", \n \"level\": \"error\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/logs", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "logs" + ] + } + }, + "response": [] + }, + { + "name": "Delete/Truncate logs", + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } }, - { - "key": "limit", - "value": "3" + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/logs?delete=false", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "logs" + ], + "query": [ + { + "key": "delete", + "value": "false", + "description": "Delete files or just truncate them?" + } + ] } - ] + }, + "response": [] + }, + { + "name": "Export (Download) logfiles as tar.gz", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/logs/export", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "logs", + "export" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "New Request", - "request": { - "method": "GET", - "header": [], - "url": null - }, - "response": [] - } - ] - }, - { - "name": "Authentication", - "item": [ - { - "name": "Login", - "request": { - "method": "POST", - "header": [ - { - "key": "x-auth-token", - "value": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImhhbnMuaHViZXJ0QGV4YW1wbGUuY29tIiwidXVpZCI6ImM3N2E3NjJkLWM4ODYtNGQ2My1iNGM1LWU0MDJhZGNmYTdiZSIsImlhdCI6MTY1MzUyMDM1Mn0.10H4v6IhiI2mlaiSAcbTp2m4QUSueA1l4c2CPGV8L7WltZfXia8pLCnbYC243LPz", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"email\": \"hans.hubert@example.com\",\n \"password\": \"Pa$$w0rd\"\n}", - "options": { - "raw": { - "language": "json" + "name": "Information", + "item": [ + { + "name": "Software versions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/info/versions", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "info", + "versions" + ] } - } + }, + "response": [] }, - "url": { - "raw": "http://{{HOST}}:{{PORT}}/auth/login", - "protocol": "http", - "host": [ - "{{HOST}}" - ], - "port": "{{PORT}}", - "path": [ - "auth", - "login" - ] + { + "name": "System usage", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/info/usage", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "info", + "usage" + ] + } + }, + "response": [] } - }, - "response": [] + ] }, { - "name": "Logout", - "request": { - "method": "POST", - "header": [ - { - "key": "x-auth-token", - "value": "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImhhbnMuaHViZXJ0QGV4YW1wbGUuY29tIiwidXVpZCI6ImM3N2E3NjJkLWM4ODYtNGQ2My1iNGM1LWU0MDJhZGNmYTdiZSIsImlhdCI6MTY1MzUxOTUwNH0.5iByWpBxCHVj0c1mHEv0Skz47SSGps7BbfDOPVFppSFWwJfLwa09jx8MSBrJTC_E", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" + "name": "Backup", + "item": [ + { + "name": "Export Backup", + "request": { + "method": "POST", + "header": [], + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/backup/export", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "backup", + "export" + ], + "query": [ + { + "key": "encrypt", + "value": "false", + "description": "Should the .tgz (.tar.gz) file be encrypted?", + "disabled": true + }, + { + "key": "includes[]", + "value": "database", + "description": "Should include database dump?", + "disabled": true + }, + { + "key": "includes[]", + "value": "plugins", + "description": "Should include plugins folder?", + "disabled": true + }, + { + "key": "includes[]", + "value": "env", + "description": "Should indlude .env file?", + "disabled": true + }, + { + "key": "encode", + "value": "false", + "description": "Encode .env values as base64? (makes them not human readable, do this at least when you dont encrypt the backup)", + "disabled": true + } + ] } - } + }, + "response": [] }, - "url": { - "raw": "http://{{HOST}}:{{PORT}}/auth/logout", - "protocol": "http", - "host": [ - "{{HOST}}" - ], - "port": "{{PORT}}", - "path": [ - "auth", - "logout" - ] + { + "name": "Import Backup", + "request": { + "method": "POST", + "header": [ + { + "key": "X-ENCRYPTION-KEY", + "value": "1e3665f8a687da2d0869ff524c10e64ee1cb600df8228c6dfcc37fbec3359846", + "description": "Header value from export (If backup is encrpyted)", + "type": "text" + }, + { + "key": "X-ENCRYPTION-IV", + "value": "186cfe92205c578a7f7199d3c973b8bd", + "description": "Header value from export (If backup is encrpyted)", + "type": "text" + } + ], + "body": { + "mode": "file", + "file": { + "src": "/home/marc/projects/OpenHaus/tmp/backup-staging.tgz" + } + }, + "url": { + "raw": "http://{{HOST}}:{{PORT}}/api/system/backup/import?truncate=true", + "protocol": "http", + "host": [ + "{{HOST}}" + ], + "port": "{{PORT}}", + "path": [ + "api", + "system", + "backup", + "import" + ], + "query": [ + { + "key": "encrypt", + "value": "true", + "description": "Is the uploading file encrypted?", + "disabled": true + }, + { + "key": "skipDuplicates", + "value": "true", + "description": "Skip same databse _id items", + "disabled": true + }, + { + "key": "truncate", + "value": "true", + "description": "Truncate/clear database & plugin folder before restore" + }, + { + "key": "decode", + "value": "true", + "description": "Decode base64 .env values", + "disabled": true + } + ] + } + }, + "response": [] } - }, - "response": [] + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "postman.setNextRequest()" + ] + } }, { - "name": "Check if auth is required", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://{{HOST}}:{{PORT}}/auth", - "protocol": "http", - "host": [ - "{{HOST}}" - ], - "port": "{{PORT}}", - "path": [ - "auth" - ] - } - }, - "response": [] + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } } ] } @@ -3107,7 +3469,12 @@ "script": { "type": "text/javascript", "exec": [ - "" + "console.log(\"Check if /system route\", pm.request.url.toString().includes(\"/system\"), pm.request.url.toString().includes(\"/auth\"))", + "", + "if(pm.request.url.toString().includes(\"/system\") || pm.request.url.toString().includes(\"/auth\")){", + " postman.setNextRequest(null);", + " return;", + "}" ] } }, @@ -3116,7 +3483,73 @@ "script": { "type": "text/javascript", "exec": [ - "" + "let IGNORE = {", + " \"PUT\": [", + " \"/api/plugins/658188e93cde9987c3228806/files\"", + " ],", + " \"POST\": [", + " \"/api/plugins/658188e93cde9987c3228806/start\",", + " \"/api/endpoints/658189336fa19198939caa21/commands/6581fc8ac20cb522e02868ff\"", + " ],", + " \"GET\": [", + " \"/auth\"", + " ]", + "};", + "", + "let URLS = [", + " \"auth\",", + " \"system\"", + "]", + "", + "console.log(\"Check ignore object\", pm.request.method, pm.request.url.toString());", + "", + "", + "if(Object.prototype.hasOwnProperty.call(IGNORE, pm.request.method)){", + "", + " let skip1 = IGNORE[pm.request.method].some((url) => {", + " return pm.request.url.toString().includes(url);", + " });", + "", + " let skip2 = URLS.some((url) => {", + " return pm.request.url.toString().includes(url);", + " });", + "", + "", + " console.log(\"Ignore\", pm.request.url.toString(), skip1 || skip2);", + "", + " if(skip1 || skip2){", + " return;", + " }", + "", + "}", + "", + "", + "pm.test(\"Status code 200 || 202\", () => {", + " pm.expect(pm.response.code).to.be.oneOf([", + " 200,", + " 202", + " ]);", + "});", + "", + "", + "pm.test(\"content-type = application/json\", () => {", + " pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');", + "});", + "", + "", + "pm.test(\"Response has no error field\", () => {", + "", + " let length = pm.response.headers.get(\"content-length\");", + "", + " // ignore empty response/no body", + " if(!length || Number(length) === 0){", + " return;", + " }", + "", + " let json = pm.response.json();", + " pm.expect(!json.error, true);", + "", + "});" ] } } diff --git a/routes/auth-handler.js b/routes/auth-handler.js index 008fdda..449799f 100644 --- a/routes/auth-handler.js +++ b/routes/auth-handler.js @@ -108,7 +108,7 @@ module.exports = (C_USERS, router) => { return; } - console.log("User request:", req.user, req.authenticated, process.env.API_AUTH_ENABLED, req.ip, req.socket.remoteAddress, req.method, req.url, req.headers); + //console.log("User request:", req.user, req.authenticated, process.env.API_AUTH_ENABLED, req.ip, req.socket.remoteAddress, req.method, req.url, req.headers); next(); diff --git a/routes/index.js b/routes/index.js index b95a861..9af604e 100644 --- a/routes/index.js +++ b/routes/index.js @@ -18,6 +18,10 @@ const C_MDNS = require("../components/mdns"); //const { encode } = require("../helper/sanitize"); //const iterate = require("../helper/iterate"); +// add logger for http, fix #409 +const logger = require("../system/logger/index.js"); +const log = logger.create("http"); + // copied from https://github.com/vkarpov15/mongo-sanitize function sanitize(v) { if (v instanceof Object) { @@ -32,186 +36,214 @@ function sanitize(v) { return v; } -module.exports = (server) => { - const app = express(); - const auth = express.Router(); - const api = express.Router(); - const logs = express.Router(); - const about = express.Router(); +const app = express(); +const auth = express.Router(); +const api = express.Router(); +const logs = express.Router(); +const about = express.Router(); +//const system = express.Router(); + +// https://expressjs.com/en/guide/behind-proxies.html +app.set("trust proxy", [ + "loopback", + "linklocal", + "uniquelocal" +]); + +// fix #409 +// add logging for http requests +app.use((req, res, next) => { + + // log basic http requests, do not reveal any senstive information + // thats why "req.path" is used instead of "req.url" + log.debug(`${req.ip} - [${req.method}] ${req.path}`); + + // log verbose requests + // this may reveal senstive informations like tokens or cookies + log.verbose(JSON.stringify({ + query: req.query, + params: req.params, + headers: req.headers + })); - // https://expressjs.com/en/guide/behind-proxies.html - app.set("trust proxy", [ - "loopback", - "linklocal", - "uniquelocal" - ]); + next(); - app.use(bodyParser.json({ - limit: (Number(process.env.API_LIMIT_SIZE) * 1024) // default to 25, (=25mb) - })); +}); - // mount api router - app.use("/api", api); +app.use(bodyParser.json({ + limit: (Number(process.env.API_LIMIT_SIZE) * 1024) // default to 25, (=25mb) +})); - // mount auth router - app.use("/auth", auth); - require("./router.auth.js")(app, auth); +// mount api router +app.use("/api", api); - // mount logs router under /api - api.use("/logs", logs); - require("./router.api.logs.js")(app, logs); +// mount auth router +app.use("/auth", auth); +require("./router.auth.js")(app, auth); - // mount logs router under /api - api.use("/about", about); - require("./router.api.about.js")(app, about); +// mount logs router under /api +// TODO move to /system/logs +api.use("/logs", logs); +require("./router.api.logs.js")(app, logs); - // /api routes - (() => { +// mount logs router under /api +// TODO remove +api.use("/about", about); +require("./router.api.about.js")(app, about); - // ensure that all requests to /api are authenticated - // req.user = User item from component user - require("./auth-handler.js")(C_USERS, api); +// mount /system under /api +//app.use("/system", system); +//require("./router.system.js")(api); +//require("./router.system.notifications.js")(app, system); - // serailize api input fields - api.use((req, res, next) => { +[/*"events",*/ "about", "logs"].forEach((route) => { + logger.warn(`http://${process.env.HTTP_ADDRESS}:${process.env.HTTP_PORT}/api/${route} is derpecated and will be removed in v4`); +}); - /* - // HTTP header should be set only for PUT and POST requests. So it can be ignored completly?! - if (!req.headers["content-type"]?.includes("application/json")) { - return res.status(415).end(); - } - */ +// ensure that all requests to /api are authenticated +// req.user = User item from component user +require("./auth-handler.js")(C_USERS, api); - // strip out any keys that start with "$" - req.body = sanitize(req.body); +// serailize api input fields +api.use((req, res, next) => { - // sanitze api input fields? - /* - // removed, breaks endpoints command payload - // see #273 - if (!(process.env.API_SANITIZE_INPUT === "true" && req.body)) { - return next(); - } - */ - - // patch/override sanitized object - /* - // removed, breaks endpoints command payload - // see #273 - req.body = iterate(req.body, (key, value, type) => { - // ignore device key in settings - // see #127, currently i have no petter idea - // be sure that we only ignore the device properety in the settings object - if (type === "string" && !(key === "device" && req.body?.interfaces?.some(o => o?.settings?.device === value))) { - return encode(value); - } else { - return value; - } - }); - */ - - next(); - - }); - - - // https://learning.postman.com/docs/writing-scripts/test-scripts/ - - - // define sub router for api/component routes - const pluginsRouter = express.Router(); - const roomsRouter = express.Router(); - const devicesRouter = express.Router(); - const endpointsRouter = express.Router(); - const vaultRouter = express.Router(); - const scenesRouter = express.Router(); - const eventsRouter = express.Router(); - const ssdpRouter = express.Router(); - const storeRouter = express.Router(); - const usersRouter = express.Router(); - const webhooksRouter = express.Router(); - const mqttRouter = express.Router(); - const mdnsRouter = express.Router(); - - // http://127.0.0.1/api/plugins - api.use("/plugins", pluginsRouter); - require("./rest-handler.js")(C_PLUGINS, pluginsRouter); - require("./router.api.plugins.js")(app, pluginsRouter); - - // http://127.0.0.1/api/rooms - api.use("/rooms", roomsRouter); - require("./rest-handler.js")(C_ROOMS, roomsRouter); - - // http://127.0.0.1/api/devices - api.use("/devices", devicesRouter); - require("./rest-handler.js")(C_DEVICES, devicesRouter); - require("./router.api.devices.js")(app, devicesRouter); - - // http://127.0.0.1/api/endpoints - api.use("/endpoints", endpointsRouter); - require("./rest-handler.js")(C_ENDPOINTS, endpointsRouter); - require("./router.api.endpoints.js")(app, endpointsRouter); - - // http://127.0.0.1/api/vaults - api.use("/vault", vaultRouter); - require("./rest-handler.js")(C_VAULT, vaultRouter); - require("./router.api.vault.js")(app, vaultRouter); - - // http://127.0.0.1/api/scenes - api.use("/scenes", scenesRouter); - require("./rest-handler.js")(C_SCENES, scenesRouter); - require("./router.api.scenes.js")(app, scenesRouter); - - // http://127.0.0.1/api/events - api.use("/events", eventsRouter); - require("./router.api.events.js")(app, eventsRouter); - - // http://127.0.0.1/api/ssdp - api.use("/ssdp", ssdpRouter); - require("./router.api.ssdp.js")(app, ssdpRouter); - require("./rest-handler.js")(C_SSDP, ssdpRouter); - - // http://127.0.0.1/api/store - api.use("/store", storeRouter); - require("./rest-handler.js")(C_STORE, storeRouter); - require("./router.api.store.js")(app, storeRouter); - - // http://127.0.0.1/api/users - api.use("/users", usersRouter); - require("./rest-handler.js")(C_USERS, usersRouter); - //require("./router.api.users.js")(app, vaultRouter); - - // http://127.0.0.1/api/webhooks - api.use("/webhooks", webhooksRouter); - require("./router.api.webhooks.js")(app, webhooksRouter); - require("./rest-handler.js")(C_WEBHOOKS, webhooksRouter); - - // http://127.0.0.1/api/mqtt - api.use("/mqtt", mqttRouter); - require("./router.api.mqtt.js")(app, mqttRouter); - require("./rest-handler.js")(C_MQTT, mqttRouter); - - // http://127.0.0.1/api/mdns - api.use("/mdns", mdnsRouter); - require("./router.api.mdns.js")(app, mdnsRouter); - require("./rest-handler.js")(C_MDNS, mdnsRouter); - - // NOTE: Drop this?! - api.use((req, res) => { - res.status(404).end(); - /* - res.status(404).json({ - error: "Hmm... :/ This looks not right.", - message: `Url/endpoint "${req.url}" not found"` - }); - */ - }); - - - })(); - - // use express request handler - server.on("request", app); - -}; \ No newline at end of file + /* + // HTTP header should be set only for PUT and POST requests. So it can be ignored completly?! + if (!req.headers["content-type"]?.includes("application/json")) { + return res.status(415).end(); + } + */ + + // strip out any keys that start with "$" + req.body = sanitize(req.body); + + // sanitze api input fields? + /* + // removed, breaks endpoints command payload + // see #273 + if (!(process.env.API_SANITIZE_INPUT === "true" && req.body)) { + return next(); + } + */ + + // patch/override sanitized object + /* + // removed, breaks endpoints command payload + // see #273 + req.body = iterate(req.body, (key, value, type) => { + // ignore device key in settings + // see #127, currently i have no petter idea + // be sure that we only ignore the device properety in the settings object + if (type === "string" && !(key === "device" && req.body?.interfaces?.some(o => o?.settings?.device === value))) { + return encode(value); + } else { + return value; + } + }); + */ + + next(); + +}); + + +// https://learning.postman.com/docs/writing-scripts/test-scripts/ + + +// define sub router for api/component routes +const pluginsRouter = express.Router(); +const roomsRouter = express.Router(); +const devicesRouter = express.Router(); +const endpointsRouter = express.Router(); +const vaultRouter = express.Router(); +const scenesRouter = express.Router(); +const eventsRouter = express.Router(); +const ssdpRouter = express.Router(); +const storeRouter = express.Router(); +const usersRouter = express.Router(); +const webhooksRouter = express.Router(); +const mqttRouter = express.Router(); +const mdnsRouter = express.Router(); +const systemRouter = express.Router(); + +// http://127.0.0.1/api/plugins +api.use("/plugins", pluginsRouter); +require("./rest-handler.js")(C_PLUGINS, pluginsRouter); +require("./router.api.plugins.js")(app, pluginsRouter); + +// http://127.0.0.1/api/rooms +api.use("/rooms", roomsRouter); +require("./rest-handler.js")(C_ROOMS, roomsRouter); + +// http://127.0.0.1/api/devices +api.use("/devices", devicesRouter); +require("./rest-handler.js")(C_DEVICES, devicesRouter); +require("./router.api.devices.js")(app, devicesRouter); + +// http://127.0.0.1/api/endpoints +api.use("/endpoints", endpointsRouter); +require("./rest-handler.js")(C_ENDPOINTS, endpointsRouter); +require("./router.api.endpoints.js")(app, endpointsRouter); + +// http://127.0.0.1/api/vaults +api.use("/vault", vaultRouter); +require("./rest-handler.js")(C_VAULT, vaultRouter); +require("./router.api.vault.js")(app, vaultRouter); + +// http://127.0.0.1/api/scenes +api.use("/scenes", scenesRouter); +require("./rest-handler.js")(C_SCENES, scenesRouter); +require("./router.api.scenes.js")(app, scenesRouter); + +// http://127.0.0.1/api/events +api.use("/events", eventsRouter); +require("./router.api.events.js")(app, eventsRouter); + +// http://127.0.0.1/api/ssdp +api.use("/ssdp", ssdpRouter); +require("./router.api.ssdp.js")(app, ssdpRouter); +require("./rest-handler.js")(C_SSDP, ssdpRouter); + +// http://127.0.0.1/api/store +api.use("/store", storeRouter); +require("./rest-handler.js")(C_STORE, storeRouter); +require("./router.api.store.js")(app, storeRouter); + +// http://127.0.0.1/api/users +api.use("/users", usersRouter); +require("./rest-handler.js")(C_USERS, usersRouter); +//require("./router.api.users.js")(app, vaultRouter); + +// http://127.0.0.1/api/webhooks +api.use("/webhooks", webhooksRouter); +require("./router.api.webhooks.js")(app, webhooksRouter); +require("./rest-handler.js")(C_WEBHOOKS, webhooksRouter); + +// http://127.0.0.1/api/mqtt +api.use("/mqtt", mqttRouter); +require("./router.api.mqtt.js")(app, mqttRouter); +require("./rest-handler.js")(C_MQTT, mqttRouter); + +// http://127.0.0.1/api/mdns +api.use("/mdns", mdnsRouter); +require("./router.api.mdns.js")(app, mdnsRouter); +require("./rest-handler.js")(C_MDNS, mdnsRouter); + +// http://127.0.0.1/api/system +api.use("/system", systemRouter); +require("./router.system.js")(systemRouter); + +// NOTE: Drop this?! +api.use((req, res) => { + res.status(404).end(); + /* + res.status(404).json({ + error: "Hmm... :/ This looks not right.", + message: `Url/endpoint "${req.url}" not found"` + }); + */ +}); + + +module.exports = app; \ No newline at end of file diff --git a/routes/router.api.devices.js b/routes/router.api.devices.js index 9b66b31..1bf2f11 100644 --- a/routes/router.api.devices.js +++ b/routes/router.api.devices.js @@ -1,5 +1,6 @@ const WebSocket = require("ws"); const { finished } = require("stream"); +const C_DEVICES = require("../components/devices"); //const iface_locked = new Map(); @@ -21,11 +22,12 @@ module.exports = (app, router) => { return String(iface._id) === String(req.params._iid); }); - if (!iface) { + if (!iface && !req.query?.socket) { return res.status(404).end(); } - if (iface.upstream) { + // allow multipel connections to new connection handling below + if (iface.upstream && !req.query?.socket) { return res.status(423).end(); } @@ -37,7 +39,12 @@ module.exports = (app, router) => { } else { - + // TODO: This should be moved into the device component + // A websocket server should be created in the class.interface.js file + // Static method can return them e.g. Interface.servers() = returns array of wss + // Goal should be: + // - to eliminate the need of "shared.js" + // - handle in router.get only ws handshake: "wss.handleUpgrade(...)" if (!interfaceServer.has(req.params._iid)) { let wss = new WebSocket.Server({ @@ -48,41 +55,50 @@ module.exports = (app, router) => { // listen only once to connectoin event // gets fired every time websocket client hit this url/route - wss.on("connection", (ws) => { + wss.on("connection", (ws, req) => { + if (req.query?.uuid && req.query?.socket === "true" && req.query?.type === "response") { - // set connection to "alive" - // see #148 - ws.isAlive = true; + // new bridge/connector practice + // see https://github.com/OpenHausIO/backend/issues/460 - let upstream = WebSocket.createWebSocketStream(ws); + let stream = WebSocket.createWebSocketStream(ws); - // Cleanup: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#streamfinishedstream-options-callback - let cleanup = finished(upstream, () => { - iface.detach(() => { - cleanup(); + C_DEVICES.events.emit("socket", { + uuid: req.query.uuid, + type: "response", + socket: true, + stream }); - }); + } else { - iface.attach(upstream); + // old/legacy connection mechanism + // TODO: Remove this in future versions + let upstream = WebSocket.createWebSocketStream(ws); - //https://github.com/websockets/ws#how-to-detect-and-close-broken-connections - ["close", "error"].forEach((event) => { - upstream.once(event, () => { + // Cleanup: https://nodejs.org/dist/latest-v16.x/docs/api/stream.html#streamfinishedstream-options-callback + let cleanup = finished(upstream, () => { + iface.detach(() => { + cleanup(); + }); + }); - upstream.destroy(); - iface.detach(); - }); - }); + iface.attach(upstream); - // detect broken connection - ws.on("pong", () => { - //console.log("pong", Date.now(), "\r\n\r\n") - ws.isAlive = true; - }); + //https://github.com/websockets/ws#how-to-detect-and-close-broken-connections + ["close", "error"].forEach((event) => { + upstream.once(event, () => { + + upstream.destroy(); + iface.detach(); + + }); + }); + + } }); @@ -114,7 +130,15 @@ module.exports = (app, router) => { wss.handleUpgrade(req, req.socket, req.headers, (ws) => { + + ws.isAlive = true; + + ws.on("pong", () => { + ws.isAlive = true; + }); + wss.emit("connection", ws, req); + }); } diff --git a/routes/router.api.endpoints.js b/routes/router.api.endpoints.js index e1a54c0..ad0217d 100644 --- a/routes/router.api.endpoints.js +++ b/routes/router.api.endpoints.js @@ -39,12 +39,26 @@ module.exports = (app, router) => { router.post("/:_id/commands/:_cid", (req, res) => { if (req.cmd) { - req.cmd.trigger(req.body, (success) => { + req.cmd.trigger(req.body, (err, success) => { + if (err) { + + if (err.code === "NO_INTERFACE") { + res.status(424).json({ + error: err.message + }); + } else { + res.status(500).json({ + error: err.message + }); + } - res.json({ - success - }); + } else { + res.json({ + success + }); + + } }); } else { diff --git a/routes/router.api.events.js b/routes/router.api.events.js index c99af5f..83c0494 100644 --- a/routes/router.api.events.js +++ b/routes/router.api.events.js @@ -1,4 +1,6 @@ const WebSocket = require("ws"); +const path = require("path"); +const fs = require("fs"); module.exports = (app, router) => { @@ -25,7 +27,7 @@ module.exports = (app, router) => { clearInterval(interval); }); - + /* const componentNames = [ "devices", "endpoints", @@ -35,6 +37,10 @@ module.exports = (app, router) => { "store", "vault" ]; + */ + + // fix #403 "Add missing components" + let componentNames = fs.readdirSync(path.resolve(process.cwd(), "components")); function reemit(event, component) { @@ -48,9 +54,20 @@ module.exports = (app, router) => { }); wss.clients.forEach((client) => { - if (client.readyState === WebSocket.OPEN) { + // fix #403 "Implement named subscriptions" + // added component name intents + /* + if (client.intents.includes(event) /*&& client.components.includes(component)* && client.readyState === WebSocket.OPEN) { client.send(obj); } + */ + + let { readyState, filter } = client; + + if (readyState === WebSocket.OPEN && filter.events.includes(event) && filter.components.includes(component)) { + client.send(obj); + } + }); }; @@ -72,6 +89,9 @@ module.exports = (app, router) => { component.events.on(method, reemit(method, name)); }); + // NOTE: handle also custom events like "socket" & ssdp/mqtt events? + //component.events.on("socket", reemit("socket", name)); + } catch (err) { console.error("Failure in events http api", err); @@ -99,6 +119,31 @@ module.exports = (app, router) => { ws.isAlive = true; }); + // monkey patch intents for "named subscriptions" + // see #403; get default everyhting + // NOTE: remove the "default everything" part? + /* + ws.intents = req.query?.intents || [ + "add", + "get", + "update", + "remove" + ]; + + // return all components on default + //ws.components = req.query?.components || componentNames; + */ + + ws.filter = { + events: req.query.events || req.query.intents || [ + "add", + "get", + "update", + "remove" + ], + components: req.query.components || componentNames + }; + wss.emit("connection", ws, req); }); diff --git a/routes/router.api.mdns.js b/routes/router.api.mdns.js index a5895d3..93411be 100644 --- a/routes/router.api.mdns.js +++ b/routes/router.api.mdns.js @@ -12,6 +12,17 @@ module.exports = (app, router) => { noServer: true }); + + /* + C_MDNS.events.on("query", (query) => { + wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(query); + } + }); + }); + */ + // detect broken connections let interval = setInterval(() => { wss.clients.forEach((ws) => { @@ -35,58 +46,53 @@ module.exports = (app, router) => { }); - // http route handler - router.get("/", (req, res, next) => { - - console.log("Request to /api/mdns"); + // listen for websockt clients + // keep sending new log entrys to client + wss.once("connection", (ws) => { - // check if connection is a simple get request or ws client - if ((!req.headers["upgrade"] || !req.headers["connection"])) { - //return res.status(403).end(); - next(); // let the rest-handler.js do its job - return; - } + C_MDNS.events.emit("connected", ws); - // listen for websockt clients - // keep sending new log entrys to client - wss.once("connection", (ws) => { + ws.on("message", (msg) => { + C_MDNS.events.emit("message", decode(msg), msg); + }); - console.log("Clien connected to mdns"); - C_MDNS.events.emit("connected", ws); + // QUERY LOCAL DNS + // TODO: Move this into the mdns component + /* + setInterval(() => { - ws.on("message", (msg) => { - C_MDNS.events.emit("message", decode(msg), msg); - }); + console.log("Query for HTTP Server"); - ws.on("close", () => { - console.log("Client disconnected disolaskjdflaskjfdasdf"); + let msg = encode({ + type: "query", + id: 1, + flags: RECURSION_DESIRED, + questions: [{ + type: "A", + //name: '_http._tcp.local' + name: "*" + }] }); + ws.send(msg); - // QUERY LOCAL DNS - /* - setInterval(() => { + }, 30_000); + */ - console.log("Query for HTTP Server"); - - let msg = encode({ - type: "query", - id: 1, - flags: RECURSION_DESIRED, - questions: [{ - type: "A", - //name: '_http._tcp.local' - name: "*" - }] - }); + }); - ws.send(msg); - }, 30_000); - */ + // http route handler + // TODO: Reformat to match router.api.mdns.js code style/if-else + router.get("/", (req, res, next) => { - }); + // check if connection is a simple get request or ws client + if ((!req.headers["upgrade"] || !req.headers["connection"])) { + //return res.status(403).end(); + next(); // let the rest-handler.js do its job + return; + } // handle request as websocket // perform websocket handshake diff --git a/routes/router.api.mqtt.js b/routes/router.api.mqtt.js index 20a46a6..da3323a 100644 --- a/routes/router.api.mqtt.js +++ b/routes/router.api.mqtt.js @@ -33,11 +33,26 @@ module.exports = (app, router) => { }); + // listen for websockt clients + // forward messages between component & ws client + wss.once("connection", (ws) => { + + C_MQTT.events.emit("connected", ws); + + ws.on("message", (msg) => { + C_MQTT.events.emit("message", msg); + }); + + ws.on("close", () => { + C_MQTT.events.emit("disconnected", ws); + }); + + }); + + // http route handler router.get("/", (req, res, next) => { - console.log("Request to /ai/mqtt"); - // check if connection is a simple get request or ws client if ((!req.headers["upgrade"] || !req.headers["connection"])) { //return res.status(403).end(); @@ -45,23 +60,6 @@ module.exports = (app, router) => { return; } - // listen for websockt clients - // keep sending new log entrys to client - wss.once("connection", (ws) => { - - C_MQTT.events.emit("connected", ws); - - ws.on("message", (msg) => { - C_MQTT.events.emit("message", msg); - }); - - ws.on("close", () => { - console.log("MQTT Client disconnected disolaskjdflaskjfdasdf"); - C_MQTT.events.emit("disconnected", ws); - }); - - }); - // handle request as websocket // perform websocket handshake wss.handleUpgrade(req, req.socket, req.headers, (ws) => { diff --git a/routes/router.api.plugins.js b/routes/router.api.plugins.js index 2b5c653..434b65a 100644 --- a/routes/router.api.plugins.js +++ b/routes/router.api.plugins.js @@ -1,51 +1,156 @@ const path = require("path"); const { pipeline } = require("stream"); const { exec } = require("child_process"); +const process = require("process"); const fs = require("fs/promises"); -const readline = require("readline"); +const { statSync } = require("fs"); + +//const C_PLUGINS = require("../components/plugins"); module.exports = (app, router) => { - router.put("/:_id/files", (req, res) => { + // this router gets executed before the rest-handler.js params handler + // but why when this middleware is defined after the rest-handler stuff?! + // execution order: + // 1) the router middleware wehre `req.install` & `req.folder` are set below + // 2) rest-handler.js req.prams("_id") middleware + // 3) router handler below like "/start", "/<_id>/files" + // Outcommented, see issue #444: https://github.com/OpenHausIO/backend/issues/444#issuecomment-2094341348 + // > looks like its not possible to archive the functionality above with a middleware function on all routes + /* + router.use((req, res, next) => { - let p = path.resolve(process.cwd(), "plugins", req.item.uuid); - let tar = exec(`tar vzxf - -C ${p}`); + console.log("2) plugin middleware", C_PLUGINS.items, req.item, req.params); - let rl = readline.createInterface({ - input: tar.stdout, - //output: process.stdout - }); + req.install = req.params?.install === "true" || false; + req.folder = path.join(process.cwd(), "plugins", req.item?.uuid || ""); - if (process.env.NODE_ENV === "development") { - rl.on("line", (line) => { + console.log("Install:", req.install); + console.log("Folder", req.folder); + + next(); + + }); + */ + + const variables = (req, res, next) => { + + req.install = req.query?.install === "true" || false; + req.folder = path.join(process.cwd(), "plugins", req.item.uuid); + + next(); + + }; - console.log("Extract file:", line); - //console.log("Extract file:", path.join(p, line)); + router.put("/:_id/files", variables, (req, res) => { + if (Number(req.headers["content-length"]) <= 0) { + return res.status(400).json({ + error: "Invalid upload size." }); } - pipeline(req, tar.stdin, (err) => { + //let p = path.resolve(process.cwd(), "plugins", req.item.uuid); + let tar = exec(`tar vzxf - -C ${req.folder}`); + + tar.once("exit", (code) => { + + if (code > 0) { + if (!res.headersSent) { - if (err) { - res.status(500).end(err.message); + res.status(400).json({ + error: "tar could not read input file. Upload failed/client failer?", + details: `tar exit code ${code}` + }); + + } } else { - res.json(req.item); + + // skip installation step below + if (!req.install) { + res.json(req.item); + return; + } + + try { + + // check if package.json exists before executing npm + // otherwise it walks the directorys up till a package.json is found + // in the "worst case" this is the one from backend + statSync(path.join(req.folder, "package.json")); + + } catch (err) { + + if (err.code === "ENOENT") { + res.json(req.item); + } else { + res.status(500).json({ + error: err.message + }); + } + + return; + + } + + let npm = exec(`npm install --omit=dev`, { + env: { + ...process.env, + NODE_ENV: "production", + }, + cwd: req.folder + }); + + if (process.env.NODE_ENV === "development") { + npm.stdout.pipe(process.stdout); + npm.stderr.pipe(process.stderr); + } + + npm.once("exit", (code) => { + if (code === 0 || code === 254) { + + res.json(req.item); + + } else { + + res.status(400).json({ + error: "npm could not install dependencies", + details: `npm exit code ${code}` + }); + + } + }); + } - rl.close(); + // trigger closing pipeline below + tar.stdin.end(); }); + if (process.env.NODE_ENV === "development") { + tar.stdout.pipe(process.stdout); + tar.stderr.pipe(process.stderr); + } + + pipeline(req, tar.stdin, (err) => { + if (err && !res.headersSent) { + + res.status(500).json({ + error: err.message + }); + + } + }); + }); - router.delete("/:_id/files", async (req, res) => { + router.delete("/:_id/files", variables, async (req, res) => { try { - let p = path.resolve(process.cwd(), "plugins", req.item.uuid); - - for (let file of await fs.readdir(p)) { - await fs.rm(path.join(p, file), { + //let p = path.resolve(process.cwd(), "plugins", req.item.uuid); + for (let file of await fs.readdir(req.folder)) { + await fs.rm(path.join(req.folder, file), { recursive: true }); } @@ -54,7 +159,10 @@ module.exports = (app, router) => { } catch (err) { - res.status(500).end(err.message); + res.status(500).json({ + error: err.message, + stack: err.stack + }); } }); @@ -67,7 +175,10 @@ module.exports = (app, router) => { } catch (err) { - res.status(500).end(err); + res.status(500).json({ + error: err.message, + stack: err.stack + }); } }); diff --git a/routes/router.api.scenes.js b/routes/router.api.scenes.js index 18ee2d1..10a3bda 100644 --- a/routes/router.api.scenes.js +++ b/routes/router.api.scenes.js @@ -3,13 +3,13 @@ module.exports = (app, router) => { router.post("/:_id/trigger", (req, res) => { console.log("Trigger scene", req.item); req.item.trigger(); - res.status(202).end(); + res.status(202).json(req.item); }); router.post("/:_id/abort", (req, res) => { console.log("Abort scene", req.item); req.item.abort(); - res.end(); + res.json(req.item); }); router.get("/:_id/state", ({ item: { diff --git a/routes/router.api.ssdp.js b/routes/router.api.ssdp.js index f0f5ee7..d0406d1 100644 --- a/routes/router.api.ssdp.js +++ b/routes/router.api.ssdp.js @@ -15,6 +15,9 @@ const C_SSDP = require("../components/ssdp"); // Error: unknown ssdp message type cache-control: max-age=100 // Seems like the line handling works not perfect +// simple ssdp monitor +// nc -ulvv 239.255.255.250 1900 + async function parseMessage(msg) { diff --git a/routes/router.api.store.js b/routes/router.api.store.js index 7fbf1f1..a4954ea 100644 --- a/routes/router.api.store.js +++ b/routes/router.api.store.js @@ -7,7 +7,7 @@ module.exports = (app, router) => { }); if (!req.config) { - return res.status(404); + return res.status(404).end(); } next(); diff --git a/routes/router.api.webhooks.js b/routes/router.api.webhooks.js index a60171a..06a752d 100644 --- a/routes/router.api.webhooks.js +++ b/routes/router.api.webhooks.js @@ -1,8 +1,10 @@ const C_WEBHOOKS = require("../components/webhooks"); - +const C_SCENES = require("../components/scenes"); module.exports = (app, router) => { + // NOTE: Why is this needed? + // if _id is found, `req.item` should be allready set router.param("_id", (req, res, next, _id) => { C_WEBHOOKS.get(_id, (err, obj) => { if (err) { @@ -27,11 +29,27 @@ module.exports = (app, router) => { router.all("/:_id/trigger", (req, res) => { - //res.end(`Hello from webhook: ${req.method}, ${JSON.stringify(req.item)}`); + let trigger = C_SCENES.items.map(({ triggers }) => { + return triggers; + }).flat().find(({ type, params }) => { + + let found = 1; + + found &= type === "webhook"; + found &= params?._id === req.params._id; + found &= req.item._handler.length === 0; + + return found; + + }); - req.item._trigger(req.body, req.query); + if (trigger) { + trigger.fire(); + } else { + req.item._trigger(req.body, req.query, req); + } - res.status(202).end(); + res.status(202).json(req.item); }); diff --git a/routes/router.auth.js b/routes/router.auth.js index e9d9cce..6c3f485 100644 --- a/routes/router.auth.js +++ b/routes/router.auth.js @@ -4,9 +4,6 @@ const C_USERS = require("../components/users"); module.exports = (app, router) => { router.get("/", (req, res) => { - - console.log("/auth request from:", req.ip); - if (process.env.API_AUTH_ENABLED === "true") { // override header header token with query token @@ -41,7 +38,6 @@ module.exports = (app, router) => { res.status(200).end(); } - }); router.post("/login", (req, res) => { diff --git a/routes/router.system.backup.js b/routes/router.system.backup.js new file mode 100644 index 0000000..dad9b84 --- /dev/null +++ b/routes/router.system.backup.js @@ -0,0 +1,283 @@ +const crypto = require("crypto"); +const zlib = require("zlib"); +const path = require("path"); +const fs = require("fs"); +const { Writable, pipeline } = require("stream"); +const { createInterface } = require("readline"); +const { EOL } = require("os"); + +const { client } = require("mongodb"); +const tar = require("tar-stream"); + + +const BASE_PATH = path.join(process.cwd(), "./plugins"); +const ALGORITHM = "aes-256-cbc"; + + +module.exports = (router) => { + + router.post("/export", async (req, res) => { + + const pack = tar.pack(); + + // NOTE: add error listener here? + + res.setHeader("content-type", "application/tar+gzip"); + res.setHeader("content-disposition", `attachment; filename="backend-${Date.now()}.tgz"`); + + if (req.query.encrypt == "true") { + + const key = crypto.randomBytes(32); + const iv = crypto.randomBytes(16); + + res.setHeader("X-ENCRYPTION-KEY", key.toString("hex")); + res.setHeader("X-ENCRYPTION-IV", iv.toString("hex")); + + const cipher = crypto.createCipheriv(ALGORITHM, key, iv); + pack.pipe(zlib.createGzip()).pipe(cipher).pipe(res); + + } else { + + pack.pipe(zlib.createGzip()).pipe(res); + + } + + + if ((req.query?.includes?.includes("database") || (!req.query?.includes && true))) { + for await (let collection of client.listCollections()) { + + // TODO: check/handle binary (serialized buffer objects) + // > endpoint commands payload + // > _id's should be mongodb object id's + let data = (await client.collection(collection.name).find().toArray()); + pack.entry({ name: `database/${collection.name}.json` }, JSON.stringify(data)); + + } + } + + if ((req.query?.includes?.includes("plugins") || (!req.query?.includes && true))) { + fs.readdirSync(BASE_PATH, { + recursive: true + }).filter((entry) => { + + // TODO: ignore .gitkeep file + return !fs.statSync(path.join(BASE_PATH, entry)).isDirectory(); + + }).map((entry) => { + + return [entry, fs.readFileSync(path.join(BASE_PATH, entry), "utf8")]; + + }).forEach(([file, content]) => { + + pack.entry({ name: `plugins/${file}` }, content); + + }); + } + + + if ((req.query?.includes?.includes("env") || (!req.query?.includes && true))) { + + // encode .env value as base64, so the are not human readable + let content = fs.readFileSync(path.join(process.cwd(), ".env"), "utf8").split(EOL).map((line) => { + + if (req.query?.encode !== "true") { + return line; + } + + let [key, value] = line.split("="); + + if (!value) { + return line; + } + + return `${key}=${Buffer.from(value).toString("base64")}`; + + }); + + pack.entry({ name: `.env` }, content.join(EOL)); + + } + + pack.finalize(); + + }); + + + router.post("/import", async (req, res) => { + + const extract = tar.extract(); + + // NOTE: switch to `.once`? + extract.on("error", (err) => { + + res.status(500).json({ + error: err.message, + details: err, + success: false + }); + + console.log("Terrible error", err); + //process.exit(1); + + }); + + + // NOTE: switch to `.once`? + extract.on("finish", () => { + + console.log("tar-stream finished"); + + res.json({ + success: true, + message: "Restart to apply changes!" + }); + + }); + + + if (req.query.encrypt == "true") { + + const key = Buffer.from(req.headers["x-encryption-key"], "hex"); + const iv = Buffer.from(req.headers["x-encryption-iv"], "hex"); + const decipher = crypto.createDecipheriv(ALGORITHM, key, iv); + + pipeline(req, decipher, zlib.createGunzip(), extract, (err) => { + if (err) { + + console.error("encrypted", err); + + } + }); + + } else { + + pipeline(req, zlib.createGunzip(), extract, (err) => { + if (err) { + + console.error("uncrypted", err); + + } + }); + + } + + + extract.on("entry", async (header, stream, next) => { + if (header.name.startsWith("database/")) { + + console.log("restartoe database collection", header); + + let chunks = []; + let name = header.name.replace("database/", ""); + + let writeable = new Writable({ + write(chunk, enc, cb) { + chunks.push(chunk); + cb(null); + } + }); + + stream.pipe(writeable).on("close", async () => { + + // TODO: check/handle binary (serialized buffer objects) + // > endpoint commands payload + // > _id's should be mongodb object id's + let documents = JSON.parse(Buffer.concat(chunks).toString()); + + // prevents bulk write error + // MongoInvalidArgumentError: Invalid BulkOperation, Batch cannot be empty + if (documents.length === 0) { + next(); + return; + } + + console.log("collection name", path.basename(name, ".json")); + + let collection = client.collection(path.basename(name, ".json")); + + if (req.query?.truncate === "true") { + await collection.deleteMany({}); + } + + collection.insertMany(documents).catch((err) => { + if (err?.code === 11000 && req.query?.skipDuplicates === "true") { + next(); + } else { + next(err); + } + }).then(() => { + next(); + }); + + }); + + } else if (header.name.startsWith("plugins/")) { + + console.log("restroe plugin file", header); + + // NOTE: this also deletes .gitkeep + if (req.query?.truncate === "true") { + for (let file of await fs.promises.readdir(BASE_PATH)) { + await fs.promises.rm(path.join(BASE_PATH, file), { + recursive: true, + force: true + }); + } + } + + let name = header.name.replace("plugins/", ""); + + fs.mkdirSync(path.dirname(path.join(BASE_PATH, name)), { + recursive: true + }); + + stream.pipe(fs.createWriteStream(path.join(BASE_PATH, name))).once("error", (err) => { + next(err); + }).once("close", () => { + next(); + }); + + } else if (header.name === ".env") { + + if (req.query?.truncate === "true") { + fs.truncateSync(path.join(process.cwd(), ".env")); + } + + let rl = createInterface({ + input: stream + }); + + rl.once("error", (err) => { + next(err); + }); + + rl.once("close", () => { + next(); + }); + + rl.on("line", (line) => { + + let [key, value] = line.split("="); + + if (!key || !value || req.query?.decode !== "true") { + return fs.appendFileSync(path.join(process.cwd(), ".env"), line + EOL); + } + + line = `${key}=${Buffer.from(value, "base64").toString()}`; + fs.appendFileSync(path.join(process.cwd(), ".env"), line + EOL); + + }); + + } else { + + console.log("unknown file prefix/name", header); + + } + }); + + + + + }); + +}; \ No newline at end of file diff --git a/routes/router.system.connector.js b/routes/router.system.connector.js new file mode 100644 index 0000000..3dad200 --- /dev/null +++ b/routes/router.system.connector.js @@ -0,0 +1,72 @@ +const C_DEVICES = require("../components/devices"); + +// external modules +const WebSocket = require("ws"); + +module.exports = (router) => { + + // websocket server + let wss = new WebSocket.Server({ + noServer: true + }); + + // detect broken connections + let interval = setInterval(() => { + wss.clients.forEach((ws) => { + + if (!ws.isAlive) { + ws.terminate(); + return; + } + + ws.isAlive = false; + ws.ping(); + + }); + }, Number(process.env.API_WEBSOCKET_TIMEOUT)); + + + // if the server closes + // clear the interval + wss.on("close", () => { + clearInterval(interval); + }); + + + C_DEVICES.events.on("socket", (obj) => { + if (obj.type === "request") { + wss.clients.forEach((ws) => { + ws.send(JSON.stringify(obj)); + }); + } + }); + + + // http route handler + // TODO: Reformat to match router.api.mdns.js code style/if-else + router.get("/", (req, res, next) => { + + // check if connection is a simple get request or ws client + if ((!req.headers["upgrade"] || !req.headers["connection"])) { + //return res.status(403).end(); + next(); // let the rest-handler.js do its job + return; + } + + // handle request as websocket + // perform websocket handshake + wss.handleUpgrade(req, req.socket, req.headers, (ws) => { + + ws.isAlive = true; + + ws.on("pong", () => { + ws.isAlive = true; + }); + + wss.emit("connection", ws, req); + + }); + + }); + +}; \ No newline at end of file diff --git a/routes/router.system.events.js b/routes/router.system.events.js new file mode 100644 index 0000000..58d103b --- /dev/null +++ b/routes/router.system.events.js @@ -0,0 +1,9 @@ +module.exports = (router) => { + + // NOTE: this is for compatibility reasons + // NOTICE: This would break reactiviness of user (non admin) UIs + // When a new device is added, a user would not see before refreshing the UI + // in v4 the content from router.api.events.js is moved here + require("./router.api.events.js")(null, router); + +}; \ No newline at end of file diff --git a/routes/router.system.info.js b/routes/router.system.info.js new file mode 100644 index 0000000..14d03a6 --- /dev/null +++ b/routes/router.system.info.js @@ -0,0 +1,184 @@ +const process = require("process"); +const { exec } = require("child_process"); +const os = require("os"); +//const mongodb = require("mongodb"); + +module.exports = (router) => { + + router.get(["/versions", "/"], (req, res) => { + Promise.all([ + + // get npm version + new Promise((resolve, reject) => { + exec("npm -v", (err, stdout, stderr) => { + if (err || stderr) { + + reject(err || stderr); + + } else { + + resolve(stdout); + + } + }); + }), + + // get tar version + // TODO: use explicit path to binary + // see: https://github.com/OpenHausIO/backend/issues/432 "Add config for bin pathes" + new Promise((resolve, reject) => { + exec("tar --version", (err, stdout, stderr) => { + if (err || stderr) { + + reject(err || stdout); + + } else { + + // extract version number from output + // `tar (GNU tar) 1.34` + let matches = stdout.match(/(\d+\.\d+)/); + resolve(matches && matches[0] || "undefined"); + + } + }); + }), + + // get mongodb version + // TODO: before enable this, check if this works with authentication + /* + new Promise((resolve, reject) => { + + let db = mongodb.client.admin(); + + db.serverStatus((err, info) => { + if (err) { + reject(err); + } else { + resolve(info.version); + } + }); + + }), + */ + + // calculate cpu usage + new Promise((resolve, reject) => { + try { + + const perc = os.cpus().map(cpu => cpu.times).reduce((acc, times) => { + const totalCPUTime = Object.values(times).reduce((total, time) => total + time, 0); + const idleCPUTime = times.idle; + const cpuUsagePercentage = ((totalCPUTime - idleCPUTime) / totalCPUTime) * 100; + return acc + cpuUsagePercentage; + }, 0) / os.cpus().length; + + resolve(perc.toFixed(2)); + + } catch (err) { + reject(err); + } + }), + + // calculate ram usage + new Promise((resolve, reject) => { + try { + + let totalMemory = os.totalmem(); + let usedMemory = totalMemory - os.freemem(); + let perc = (usedMemory / totalMemory) * 100; + + process.nextTick(() => { + resolve(perc.toFixed(2)); + }); + + } catch (err) { + reject(err); + } + }) + + ]).then((results) => { + + // remove whitespaces & convert to string + let [npm, tar, /*mongodb,*/ cpu, ram] = results.map((result) => { + return String(result).trim(); + }); + + res.json({ + versions: { + node: process.versions.node, + npm, + tar, + //mongodb + }, + // ore move this into a /usage route? + usage: { + cpu, + ram + } + }); + + }).catch((err) => { + + res.status(500).json({ + error: err + }); + + }); + }); + + + router.get("/usage", (req, res) => { + + Promise.all([ + + // calculate cpu usage + new Promise((resolve, reject) => { + try { + + const perc = os.cpus().map(cpu => cpu.times).reduce((acc, times) => { + const totalCPUTime = Object.values(times).reduce((total, time) => total + time, 0); + const idleCPUTime = times.idle; + const cpuUsagePercentage = ((totalCPUTime - idleCPUTime) / totalCPUTime) * 100; + return acc + cpuUsagePercentage; + }, 0) / os.cpus().length; + + resolve(perc.toFixed(2)); + + } catch (err) { + reject(err); + } + }), + + // calculate ram usage + new Promise((resolve, reject) => { + try { + + let totalMemory = os.totalmem(); + let usedMemory = totalMemory - os.freemem(); + let perc = (usedMemory / totalMemory) * 100; + + process.nextTick(() => { + resolve(perc.toFixed(2)); + }); + + } catch (err) { + reject(err); + } + }) + ]).then(([cpu, ram]) => { + + res.json({ + cpu, + ram + }); + + }).catch((err) => { + + res.status(500).json({ + error: err + }); + + }); + }); + +}; \ No newline at end of file diff --git a/routes/router.system.js b/routes/router.system.js new file mode 100644 index 0000000..a7f2fbc --- /dev/null +++ b/routes/router.system.js @@ -0,0 +1,51 @@ +const { Router } = require("express"); + +module.exports = (router) => { + + // protect system route(r|s) + router.use((req, res, next) => { + + // protect system routes here + // - could check here if a user is admin + // - src ip = whitelisted + // - etc. pp. + // if(!req.user.admin){ return res.status(403).end(); } + + next(); + + }); + + // create sub router + let infoRouter = Router(); + let eventsRouter = Router(); + let notificationsRouter = Router(); + let logsRouter = Router(); + let connectorRouter = Router(); + let backupRouter = Router(); + + // http://127.0.0.1/api/system/info + // FIXME: what does this work with "eventsRouter/notificationsRouter"?! + router.use("/info", infoRouter); + require("./router.system.info.js")(infoRouter); + + // http://127.0.0.1/api/system/events + router.use("/events", eventsRouter); + require("./router.system.events.js")(eventsRouter); + + // http://127.0.0.1/api/system/notifications + router.use("/notifications", notificationsRouter); + require("./router.system.notifications.js")(notificationsRouter); + + // http://127.0.0.1/api/system/logs + router.use("/logs", logsRouter); + require("./router.system.logs.js")(logsRouter); + + // http://127.0.0.1/api/system/connector + router.use("/connector", connectorRouter); + require("./router.system.connector.js")(connectorRouter); + + // http://127.0.0.1/api/system/backup + router.use("/backup", backupRouter); + require("./router.system.backup.js")(backupRouter); + +}; \ No newline at end of file diff --git a/routes/router.system.logs.js b/routes/router.system.logs.js new file mode 100644 index 0000000..76f2cf3 --- /dev/null +++ b/routes/router.system.logs.js @@ -0,0 +1,279 @@ +const path = require("path"); +const fs = require("fs"); +const { exec } = require("child_process"); +const { WebSocket } = require("ws"); +const { PassThrough } = require("stream"); +const { createInterface } = require("readline"); + +const { + LOG_PATH +} = process.env; + +const LOGFILE = path.resolve(LOG_PATH, "combined.log"); + +const logger = require("../system/logger/index.js"); +const Logger = require("../system/logger/class.logger.js"); +const exporter = Logger.exporter(); + + +/* +// works like charm with netcat +// `nc open-haus.lan 8123` +const { createServer } = require("net"); +const server = createServer(); + +server.listen(8123, "0.0.0.0", () => { + + console.log("Logfile tcp socket listening on tcp://0.0.0.0:8123") + + server.on("connection", (socket) => { + + console.log("net socket conneceted") + exporter.pipe(socket); + + socket.once("close", () => { + console.log("net socket closed"); + exporter.unpipe(socket); + }); + + }); + +}); +*/ + + + + +// websocket server +const wss = new WebSocket.Server({ + noServer: true +}); + +// detect broken connections +const interval = setInterval(() => { + wss.clients.forEach((ws) => { + + if (!ws.isAlive) { + ws.terminate(); + return; + } + + ws.isAlive = false; + ws.ping(); + + }); +}, Number(process.env.API_WEBSOCKET_TIMEOUT)); + + +// if the server closes +// clear the interval +wss.on("close", () => { + clearInterval(interval); +}); + + +module.exports = (router) => { + + // NOTE: this is for compatibility reasons + // in v4 the content from router.api.logs.js is moved here + //require("./router.api.logs.js")(null, router); + + router.get("/", (req, res) => { + if ((!req.headers["upgrade"] || !req.headers["connection"])) { + + let { + limit = 0, + offset = 0 + } = req.query; + + let output = []; + let lines = 0; + + let readable = fs.createReadStream(LOGFILE); + let rl = createInterface({ + input: readable + }); + + rl.on("line", (line) => { + + // count lines + lines += 1; + + if (output.length >= limit && limit > 0) { + rl.close(); + return; + } + + if (offset < lines) { + output.push(JSON.parse(line)); + } + + }); + + rl.on("close", () => { + res.json(output); + }); + + + } else { + + // listen for websockt clients + // keep sending new log entrys to client + // NOTE: This websocket/stream/readline logging reporter is buggy + // when the exporter stream was directly used input, it worked only 5 min + // today using the intermediate stream, works like expected (like above over a tcp socket) + // when changing back to directly use "exporter" stream, the problem was not reproducable... + wss.once("connection", (ws) => { + + // a intermediate stream is needed, for cleanup and pipeing + // directly in createrInterface({input}) does not work + // jams up the output, event emitter leak + let input = new PassThrough(); + exporter.pipe(input); + + let rl = createInterface({ + input, + terminal: false + }); + + ws.once("close", () => { + + // prevent memeory/event emitter leak + // wihtout unpipe, after 10 connections a memeory leak warning is printed + exporter.unpipe(input); + + rl.close(); + + }); + + rl.on("line", (line) => { + ws.send(line); + }); + + }); + + + // handle request as websocket + // perform websocket handshake + wss.handleUpgrade(req, req.socket, req.headers, (ws) => { + + ws.isAlive = true; + + ws.on("pong", () => { + ws.isAlive = true; + }); + + wss.emit("connection", ws, req); + + }); + + } + }); + + router.put("/", (req, res) => { + + let { + level = "debug", + message = "Hello World" + } = req.body; + + if (Object.hasOwnProperty.call(logger, level)) { + + logger[level](message); + res.status(200).end(); + + } else { + + // wrong logger level + res.status(400).end(); + + } + + }); + + router.delete("/", (req, res) => { + fs.readdir(LOG_PATH, { + recursive: true + }, (err, files) => { + if (err) { + + res.status(500).json({ + error: err + }); + + } else { + try { + + // build absolute paths + let logfiles = files.filter((name) => { + return name !== ".gitkeep"; + }).map((name) => { + return path.join(LOG_PATH, name); + }).filter((file) => { + return !fs.statSync(file).isDirectory(); + }); + + for (let file of logfiles) { + if (req.query.delete === "true") { + fs.rmSync(file); + } else { + fs.truncateSync(file); + } + } + + // feedback + logger.warn(`Logfiles ${req.query.delete === "true" ? "deleted" : "truncated"}!`); + + res.json(logfiles); + + } catch (err) { + + res.status(500).json({ + error: err + }); + + } + } + }); + }); + + // NOTE: switch to GET method? + router.post("/export", (req, res) => { + try { + + // TODO: Ensure that only admins can download logs + // a logfile may contain sensitive information! + + // TODO: use absolute path to tar + // see: https://github.com/OpenHausIO/backend/issues/432 + let tar = exec(`tar -czv *`, { + cwd: LOG_PATH, + encoding: "buffer" + }); + + if (process.env.NODE_ENV === "development") { + tar.stderr.pipe(process.stderr); + } + + res.setHeader("content-type", "application/tar+gzip"); + res.setHeader("Content-Disposition", 'attachment; filename="logfiles.tgz"'); + + tar.once("exit", (code) => { + console.log("exit code", code); + res.end(); + }); + + tar.stdout.pipe(res); + + } catch (err) { + + console.log(err); + + res.status(500).json({ + error: err + }); + + } + }); + +}; \ No newline at end of file diff --git a/routes/router.system.notifications.js b/routes/router.system.notifications.js new file mode 100644 index 0000000..4f2e6ac --- /dev/null +++ b/routes/router.system.notifications.js @@ -0,0 +1,113 @@ +const WebSocket = require("ws"); + +const { Notification } = require("../system/notifications/index.js"); +const events = Notification.events(); + +module.exports = (router) => { + + // websocket server + let wss = new WebSocket.Server({ + noServer: true + }); + + // detect broken connections + let interval = setInterval(() => { + wss.clients.forEach((ws) => { + + if (!ws.isAlive) { + ws.terminate(); + return; + } + + ws.isAlive = false; + ws.ping(); + + }); + }, Number(process.env.API_WEBSOCKET_TIMEOUT)); + + + // if the server closes + // clear the interval + wss.on("close", () => { + clearInterval(interval); + }); + + + events.on("publish", (event) => { + wss.clients.forEach((ws) => { + ws.send(JSON.stringify(event)); + }); + }); + + + router.param("uuid", (req, res, next, uid) => { + + let notifications = Notification.notifications(); + + let notification = notifications.find(({ uuid }) => { + return uuid === uid; + }); + + if (!notification) { + return res.status(404).end(); + } + + req.item = notification; + + next(); + + }); + + + router.get("/", (req, res) => { + if ((!req.headers["upgrade"] || !req.headers["connection"])) { + + res.json(Notification.notifications()); + + } else { + wss.handleUpgrade(req, req.socket, req.headers, (ws) => { + + ws.isAlive = true; + + ws.on("pong", () => { + ws.isAlive = true; + }); + + wss.emit("connection", ws, req); + + }); + } + }); + + + router.put("/", (req, res) => { + + let notification = new Notification(req.body); + + if (req.query?.publish === "true") { + notification.publish(); + } + + res.json(notification); + + }); + + + router.post("/:uuid/publish", (req, res) => { + + req.item.publish(); + res.json(req.item); + + }); + + + router.delete("/:uuid", (req, res) => { + + req.item.detain(); + res.json(req.item); + + }); + + return router; + +}; \ No newline at end of file diff --git a/scripts/hooks/applypatch-msg.sample b/scripts/hooks/applypatch-msg.sample deleted file mode 100755 index a5d7b84..0000000 --- a/scripts/hooks/applypatch-msg.sample +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message taken by -# applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. The hook is -# allowed to edit the commit message file. -# -# To enable this hook, rename this file to "applypatch-msg". - -. git-sh-setup -commitmsg="$(git rev-parse --git-path hooks/commit-msg)" -test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} -: diff --git a/scripts/hooks/commit-msg.sample b/scripts/hooks/commit-msg.sample deleted file mode 100755 index b58d118..0000000 --- a/scripts/hooks/commit-msg.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to check the commit log message. -# Called by "git commit" with one argument, the name of the file -# that has the commit message. The hook should exit with non-zero -# status after issuing an appropriate message if it wants to stop the -# commit. The hook is allowed to edit the commit message file. -# -# To enable this hook, rename this file to "commit-msg". - -# Uncomment the below to add a Signed-off-by line to the message. -# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -# hook is more suited to it. -# -# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" - -# This example catches duplicate Signed-off-by lines. - -test "" = "$(grep '^Signed-off-by: ' "$1" | - sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { - echo >&2 Duplicate Signed-off-by lines. - exit 1 -} diff --git a/scripts/hooks/fsmonitor-watchman.sample b/scripts/hooks/fsmonitor-watchman.sample deleted file mode 100755 index e673bb3..0000000 --- a/scripts/hooks/fsmonitor-watchman.sample +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; -use IPC::Open2; - -# An example hook script to integrate Watchman -# (https://facebook.github.io/watchman/) with git to speed up detecting -# new and modified files. -# -# The hook is passed a version (currently 1) and a time in nanoseconds -# formatted as a string and outputs to stdout all files that have been -# modified since the given time. Paths must be relative to the root of -# the working tree and separated by a single NUL. -# -# To enable this hook, rename this file to "query-watchman" and set -# 'git config core.fsmonitor .git/hooks/query-watchman' -# -my ($version, $time) = @ARGV; - -# Check the hook interface version - -if ($version == 1) { - # convert nanoseconds to seconds - $time = int $time / 1000000000; -} else { - die "Unsupported query-fsmonitor hook version '$version'.\n" . - "Falling back to scanning...\n"; -} - -my $git_work_tree; -if ($^O =~ 'msys' || $^O =~ 'cygwin') { - $git_work_tree = Win32::GetCwd(); - $git_work_tree =~ tr/\\/\//; -} else { - require Cwd; - $git_work_tree = Cwd::cwd(); -} - -my $retry = 1; - -launch_watchman(); - -sub launch_watchman { - - my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') - or die "open2() failed: $!\n" . - "Falling back to scanning...\n"; - - # In the query expression below we're asking for names of files that - # changed since $time but were not transient (ie created after - # $time but no longer exist). - # - # To accomplish this, we're using the "since" generator to use the - # recency index to select candidate nodes and "fields" to limit the - # output to file names only. Then we're using the "expression" term to - # further constrain the results. - # - # The category of transient files that we want to ignore will have a - # creation clock (cclock) newer than $time_t value and will also not - # currently exist. - - my $query = <<" END"; - ["query", "$git_work_tree", { - "since": $time, - "fields": ["name"], - "expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]] - }] - END - - print CHLD_IN $query; - close CHLD_IN; - my $response = do {local $/; }; - - die "Watchman: command returned no output.\n" . - "Falling back to scanning...\n" if $response eq ""; - die "Watchman: command returned invalid output: $response\n" . - "Falling back to scanning...\n" unless $response =~ /^\{/; - - my $json_pkg; - eval { - require JSON::XS; - $json_pkg = "JSON::XS"; - 1; - } or do { - require JSON::PP; - $json_pkg = "JSON::PP"; - }; - - my $o = $json_pkg->new->utf8->decode($response); - - if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) { - print STDERR "Adding '$git_work_tree' to watchman's watch list.\n"; - $retry--; - qx/watchman watch "$git_work_tree"/; - die "Failed to make watchman watch '$git_work_tree'.\n" . - "Falling back to scanning...\n" if $? != 0; - - # Watchman will always return all files on the first query so - # return the fast "everything is dirty" flag to git and do the - # Watchman query just to get it over with now so we won't pay - # the cost in git to look up each individual file. - print "/\0"; - eval { launch_watchman() }; - exit 0; - } - - die "Watchman: $o->{error}.\n" . - "Falling back to scanning...\n" if $o->{error}; - - binmode STDOUT, ":utf8"; - local $, = "\0"; - print @{$o->{files}}; -} diff --git a/scripts/hooks/post-update.sample b/scripts/hooks/post-update.sample deleted file mode 100755 index ec17ec1..0000000 --- a/scripts/hooks/post-update.sample +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare a packed repository for use over -# dumb transports. -# -# To enable this hook, rename this file to "post-update". - -exec git update-server-info diff --git a/scripts/hooks/pre-applypatch.sample b/scripts/hooks/pre-applypatch.sample deleted file mode 100755 index 4142082..0000000 --- a/scripts/hooks/pre-applypatch.sample +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed -# by applypatch from an e-mail message. -# -# The hook should exit with non-zero status after issuing an -# appropriate message if it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-applypatch". - -. git-sh-setup -precommit="$(git rev-parse --git-path hooks/pre-commit)" -test -x "$precommit" && exec "$precommit" ${1+"$@"} -: diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit deleted file mode 100755 index 5ea1285..0000000 --- a/scripts/hooks/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -# ensure linting -npm run lint \ No newline at end of file diff --git a/scripts/hooks/pre-commit.sample b/scripts/hooks/pre-commit.sample deleted file mode 100755 index 68d62d5..0000000 --- a/scripts/hooks/pre-commit.sample +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -# If you want to allow non-ASCII filenames set this variable to true. -allownonascii=$(git config --bool hooks.allownonascii) - -# Redirect output to stderr. -exec 1>&2 - -# Cross platform projects tend to avoid non-ASCII filenames; prevent -# them from being added to the repository. We exploit the fact that the -# printable range starts at the space character and ends with tilde. -if [ "$allownonascii" != "true" ] && - # Note that the use of brackets around a tr range is ok here, (it's - # even required, for portability to Solaris 10's /usr/bin/tr), since - # the square bracket bytes happen to fall in the designated range. - test $(git diff --cached --name-only --diff-filter=A -z $against | - LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 -then - cat <<\EOF -Error: Attempt to add a non-ASCII file name. - -This can cause problems if you want to work with people on other platforms. - -To be portable it is advisable to rename the file. - -If you know what you are doing you can disable this check using: - - git config hooks.allownonascii true -EOF - exit 1 -fi - -# If there are whitespace errors, print the offending file names and fail. -exec git diff-index --check --cached $against -- diff --git a/scripts/hooks/pre-push.sample b/scripts/hooks/pre-push.sample deleted file mode 100755 index 6187dbf..0000000 --- a/scripts/hooks/pre-push.sample +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# An example hook script to verify what is about to be pushed. Called by "git -# push" after it has checked the remote status, but before anything has been -# pushed. If this script exits with a non-zero status nothing will be pushed. -# -# This hook is called with the following parameters: -# -# $1 -- Name of the remote to which the push is being done -# $2 -- URL to which the push is being done -# -# If pushing without using a named remote those arguments will be equal. -# -# Information about the commits which are being pushed is supplied as lines to -# the standard input in the form: -# -# -# -# This sample shows how to prevent push of commits where the log message starts -# with "WIP" (work in progress). - -remote="$1" -url="$2" - -z40=0000000000000000000000000000000000000000 - -while read local_ref local_sha remote_ref remote_sha -do - if [ "$local_sha" = $z40 ] - then - # Handle delete - : - else - if [ "$remote_sha" = $z40 ] - then - # New branch, examine all commits - range="$local_sha" - else - # Update to existing branch, examine new commits - range="$remote_sha..$local_sha" - fi - - # Check for WIP commit - commit=`git rev-list -n 1 --grep '^WIP' "$range"` - if [ -n "$commit" ] - then - echo >&2 "Found WIP commit in $local_ref, not pushing" - exit 1 - fi - fi -done - -exit 0 diff --git a/scripts/hooks/pre-rebase.sample b/scripts/hooks/pre-rebase.sample deleted file mode 100755 index 6cbef5c..0000000 --- a/scripts/hooks/pre-rebase.sample +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006, 2008 Junio C Hamano -# -# The "pre-rebase" hook is run just before "git rebase" starts doing -# its job, and can prevent the command from running by exiting with -# non-zero status. -# -# The hook is called with the following parameters: -# -# $1 -- the upstream the series was forked from. -# $2 -- the branch being rebased (or empty when rebasing the current branch). -# -# This sample shows how to prevent topic branches that are already -# merged to 'next' branch from getting rebased, because allowing it -# would result in rebasing already published history. - -publish=next -basebranch="$1" -if test "$#" = 2 -then - topic="refs/heads/$2" -else - topic=`git symbolic-ref HEAD` || - exit 0 ;# we do not interrupt rebasing detached HEAD -fi - -case "$topic" in -refs/heads/??/*) - ;; -*) - exit 0 ;# we do not interrupt others. - ;; -esac - -# Now we are dealing with a topic branch being rebased -# on top of master. Is it OK to rebase it? - -# Does the topic really exist? -git show-ref -q "$topic" || { - echo >&2 "No such branch $topic" - exit 1 -} - -# Is topic fully merged to master? -not_in_master=`git rev-list --pretty=oneline ^master "$topic"` -if test -z "$not_in_master" -then - echo >&2 "$topic is fully merged to master; better remove it." - exit 1 ;# we could allow it, but there is no point. -fi - -# Is topic ever merged to next? If so you should not be rebasing it. -only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` -only_next_2=`git rev-list ^master ${publish} | sort` -if test "$only_next_1" = "$only_next_2" -then - not_in_topic=`git rev-list "^$topic" master` - if test -z "$not_in_topic" - then - echo >&2 "$topic is already up to date with master" - exit 1 ;# we could allow it, but there is no point. - else - exit 0 - fi -else - not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` - /usr/bin/perl -e ' - my $topic = $ARGV[0]; - my $msg = "* $topic has commits already merged to public branch:\n"; - my (%not_in_next) = map { - /^([0-9a-f]+) /; - ($1 => 1); - } split(/\n/, $ARGV[1]); - for my $elem (map { - /^([0-9a-f]+) (.*)$/; - [$1 => $2]; - } split(/\n/, $ARGV[2])) { - if (!exists $not_in_next{$elem->[0]}) { - if ($msg) { - print STDERR $msg; - undef $msg; - } - print STDERR " $elem->[1]\n"; - } - } - ' "$topic" "$not_in_next" "$not_in_master" - exit 1 -fi - -<<\DOC_END - -This sample hook safeguards topic branches that have been -published from being rewound. - -The workflow assumed here is: - - * Once a topic branch forks from "master", "master" is never - merged into it again (either directly or indirectly). - - * Once a topic branch is fully cooked and merged into "master", - it is deleted. If you need to build on top of it to correct - earlier mistakes, a new topic branch is created by forking at - the tip of the "master". This is not strictly necessary, but - it makes it easier to keep your history simple. - - * Whenever you need to test or publish your changes to topic - branches, merge them into "next" branch. - -The script, being an example, hardcodes the publish branch name -to be "next", but it is trivial to make it configurable via -$GIT_DIR/config mechanism. - -With this workflow, you would want to know: - -(1) ... if a topic branch has ever been merged to "next". Young - topic branches can have stupid mistakes you would rather - clean up before publishing, and things that have not been - merged into other branches can be easily rebased without - affecting other people. But once it is published, you would - not want to rewind it. - -(2) ... if a topic branch has been fully merged to "master". - Then you can delete it. More importantly, you should not - build on top of it -- other people may already want to - change things related to the topic as patches against your - "master", so if you need further changes, it is better to - fork the topic (perhaps with the same name) afresh from the - tip of "master". - -Let's look at this example: - - o---o---o---o---o---o---o---o---o---o "next" - / / / / - / a---a---b A / / - / / / / - / / c---c---c---c B / - / / / \ / - / / / b---b C \ / - / / / / \ / - ---o---o---o---o---o---o---o---o---o---o---o "master" - - -A, B and C are topic branches. - - * A has one fix since it was merged up to "next". - - * B has finished. It has been fully merged up to "master" and "next", - and is ready to be deleted. - - * C has not merged to "next" at all. - -We would want to allow C to be rebased, refuse A, and encourage -B to be deleted. - -To compute (1): - - git rev-list ^master ^topic next - git rev-list ^master next - - if these match, topic has not merged in next at all. - -To compute (2): - - git rev-list master..topic - - if this is empty, it is fully merged to "master". - -DOC_END diff --git a/scripts/hooks/pre-receive.sample b/scripts/hooks/pre-receive.sample deleted file mode 100755 index a1fd29e..0000000 --- a/scripts/hooks/pre-receive.sample +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# -# An example hook script to make use of push options. -# The example simply echoes all push options that start with 'echoback=' -# and rejects all pushes when the "reject" push option is used. -# -# To enable this hook, rename this file to "pre-receive". - -if test -n "$GIT_PUSH_OPTION_COUNT" -then - i=0 - while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" - do - eval "value=\$GIT_PUSH_OPTION_$i" - case "$value" in - echoback=*) - echo "echo from the pre-receive-hook: ${value#*=}" >&2 - ;; - reject) - exit 1 - esac - i=$((i + 1)) - done -fi diff --git a/scripts/hooks/prepare-commit-msg.sample b/scripts/hooks/prepare-commit-msg.sample deleted file mode 100755 index 10fa14c..0000000 --- a/scripts/hooks/prepare-commit-msg.sample +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -# -# An example hook script to prepare the commit log message. -# Called by "git commit" with the name of the file that has the -# commit message, followed by the description of the commit -# message's source. The hook's purpose is to edit the commit -# message file. If the hook fails with a non-zero status, -# the commit is aborted. -# -# To enable this hook, rename this file to "prepare-commit-msg". - -# This hook includes three examples. The first one removes the -# "# Please enter the commit message..." help message. -# -# The second includes the output of "git diff --name-status -r" -# into the message, just before the "git status" output. It is -# commented because it doesn't cope with --amend or with squashed -# commits. -# -# The third example adds a Signed-off-by line to the message, that can -# still be edited. This is rarely a good idea. - -COMMIT_MSG_FILE=$1 -COMMIT_SOURCE=$2 -SHA1=$3 - -/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" - -# case "$COMMIT_SOURCE,$SHA1" in -# ,|template,) -# /usr/bin/perl -i.bak -pe ' -# print "\n" . `git diff --cached --name-status -r` -# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; -# *) ;; -# esac - -# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" -# if test -z "$COMMIT_SOURCE" -# then -# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" -# fi diff --git a/scripts/hooks/update.sample b/scripts/hooks/update.sample deleted file mode 100755 index 80ba941..0000000 --- a/scripts/hooks/update.sample +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/sh -# -# An example hook script to block unannotated tags from entering. -# Called by "git receive-pack" with arguments: refname sha1-old sha1-new -# -# To enable this hook, rename this file to "update". -# -# Config -# ------ -# hooks.allowunannotated -# This boolean sets whether unannotated tags will be allowed into the -# repository. By default they won't be. -# hooks.allowdeletetag -# This boolean sets whether deleting tags will be allowed in the -# repository. By default they won't be. -# hooks.allowmodifytag -# This boolean sets whether a tag may be modified after creation. By default -# it won't be. -# hooks.allowdeletebranch -# This boolean sets whether deleting branches will be allowed in the -# repository. By default they won't be. -# hooks.denycreatebranch -# This boolean sets whether remotely creating branches will be denied -# in the repository. By default this is allowed. -# - -# --- Command line -refname="$1" -oldrev="$2" -newrev="$3" - -# --- Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# --- Config -allowunannotated=$(git config --bool hooks.allowunannotated) -allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -denycreatebranch=$(git config --bool hooks.denycreatebranch) -allowdeletetag=$(git config --bool hooks.allowdeletetag) -allowmodifytag=$(git config --bool hooks.allowmodifytag) - -# check for no description -projectdesc=$(sed -e '1q' "$GIT_DIR/description") -case "$projectdesc" in -"Unnamed repository"* | "") - echo "*** Project description file hasn't been set" >&2 - exit 1 - ;; -esac - -# --- Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero="0000000000000000000000000000000000000000" -if [ "$newrev" = "$zero" ]; then - newrev_type=delete -else - newrev_type=$(git cat-file -t $newrev) -fi - -case "$refname","$newrev_type" in - refs/tags/*,commit) - # un-annotated tag - short_refname=${refname##refs/tags/} - if [ "$allowunannotated" != "true" ]; then - echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 - echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 - exit 1 - fi - ;; - refs/tags/*,delete) - # delete tag - if [ "$allowdeletetag" != "true" ]; then - echo "*** Deleting a tag is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/tags/*,tag) - # annotated tag - if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 - then - echo "*** Tag '$refname' already exists." >&2 - echo "*** Modifying a tag is not allowed in this repository." >&2 - exit 1 - fi - ;; - refs/heads/*,commit) - # branch - if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then - echo "*** Creating a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/heads/*,delete) - # delete branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - refs/remotes/*,commit) - # tracking branch - ;; - refs/remotes/*,delete) - # delete tracking branch - if [ "$allowdeletebranch" != "true" ]; then - echo "*** Deleting a tracking branch is not allowed in this repository" >&2 - exit 1 - fi - ;; - *) - # Anything else (is there anything else?) - echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 - exit 1 - ;; -esac - -# --- Finished -exit 0 diff --git a/scripts/post-install.sh b/scripts/post-install.sh index c954c7e..821f5c3 100755 --- a/scripts/post-install.sh +++ b/scripts/post-install.sh @@ -1,11 +1,24 @@ -#!/bin/bash - -pwd=$(pwd); +#!/usr/bin/env sh #echo $pwd/scripts/hooks/; # rm -rf $pwd/.git/hooks # https://rjzaworski.com/2018/01/keeping-git-hooks-in-sync -if [[ ! -d $pwd/.git/hooks ]] -then - ln -s $pwd/scripts/hooks/ $pwd/.git/ +#rm -rf $(pwd)/.git/hooks +#ln -s $(pwd)/scripts/hooks $(pwd)/.git/ + +if [ "$NODE_ENV" = "production" ]; then + + # production installation + # sudo cp ../backend.service /usr/lib/systemd/system/ + # sudo systemctl daemon-reload + + # the true is needed, because a empty if/else block + # throw in the shell a error + true + +else + + # test/development installation + npx husky install + fi \ No newline at end of file diff --git a/system/component/class.component.js b/system/component/class.component.js index 5abc169..d6359c4 100644 --- a/system/component/class.component.js +++ b/system/component/class.component.js @@ -1,10 +1,11 @@ const mongodb = require("mongodb"); -const Joi = require("joi"); +//const Joi = require("joi"); const _extend = require("../../helper/extend"); const _merge = require("../../helper/merge"); const COMMON = require("./class.common.js"); +const Item = require("./class.item.js"); const PENDING_CHANGE_EVENTS = new Set(); @@ -47,7 +48,7 @@ module.exports = class COMPONENT extends COMMON { constructor(name, schema, parent) { if (parent) { - require("../prevent_cross_load")(parent); + //require("../prevent_cross_load")(parent); } super(require("../../system/logger").create(name)); @@ -94,12 +95,29 @@ module.exports = class COMPONENT extends COMMON { }); this.collection = mongodb.client.collection(name); + this.schema = Item.schema().concat(schema); - this.schema = Joi.object({ - ...schema, + /* + let baseSchema = Joi.object({ //labels: Joi.array().items(Joi.string().regex(/^[a-zA-Z0-9]+=[a-zA-Z0-9]+$/)).default([]) //labels: Joi.array().items(Joi.string().regex(/^[a-z0-9\.]+=[a-z0-9]+$/)).default([]), - labels: Joi.array().items(Joi.string().regex(/^[a-z0-9]+=[a-z0-9]+$/)).default([]), + //labels: Joi.array().items(Joi.string().regex(/^.+?=.+|.+=.+$/i)).default([]), + labels: Joi.array().items(Joi.alternatives().try( + Joi.string().regex(/^.+?=.+|.+=.+$/i), + Joi.object().custom((value, helpers) => { + if (value instanceof Label) { + + // convert to string + // otherwise the serialized object is saved into the database + return value.toString(); + + } else { + + return helpers.error("any.custom"); + + } + }, "Instance of class.label.js") + )).default([]), timestamps: Joi.object({ ...schema?.timestamps, created: Joi.number().allow(null).default(null), @@ -107,6 +125,10 @@ module.exports = class COMPONENT extends COMMON { }) }); + // concat base schema with component specific + this.schema = baseSchema.concat(schema); + */ + if (process.env.DATABASE_WATCH_CHANGES === "true") { try { @@ -318,8 +340,17 @@ module.exports = class COMPONENT extends COMMON { let item = this.items.find((item) => { + // NOTE: rename value to key return Object.keys(err.keyValue).every((value) => { + + // fixing "Duplicate unique key/index in database, but no matching item" + // see #367 + if (err.keyValue[value] instanceof mongodb.ObjectId) { + return item[value] === err.keyValue[value].toString(); + } + return item[value] === err.keyValue[value]; + }); /* @@ -605,6 +636,12 @@ module.exports = class COMPONENT extends COMMON { let loop = (target, filter) => { return Object.keys(filter).every((key) => { + if (key === "labels" && Array.isArray(filter[key])) { + return filter[key].every((label) => { + return item.labels.includes(label); + }); + } + if (target[key] instanceof Object) { return loop(target[key], filter[key]); } else { @@ -654,6 +691,20 @@ module.exports = class COMPONENT extends COMMON { let loop = (filter, target) => { for (let key in filter) { + // fix for #351 + // NOTE: use later labels method to match more "effecive". e.g. for wildcards + if (key === "labels" && Array.isArray(filter[key]) && Array.isArray(target[key])) { + + found = filter[key].every((label) => { + // fix #381 + // target[key] is a instance if class.labels.js and not of plain string. + // convert it to a array wiht plain strings, so that .includes works. + return target[key]?.toString().includes(label); + }); + + return; + } + if (typeof filter[key] === "object") { loop(filter[key], target[key]); return; @@ -725,7 +776,7 @@ module.exports = class COMPONENT extends COMMON { handler(filter, item); }; - // TODO: Ensure to no create a memory leak + // TODO: Ensure to not create a memory leak // E.g. When used in ssdp with "update" event // And the announcement timestamp gets updated // the function is triggerd again. How to prevent that? @@ -745,7 +796,7 @@ module.exports = class COMPONENT extends COMMON { /** * @function _labels - * Checks if filter array contains matching labels + * Checks if filter array contains matching labels on items.labels array * * @param {Array} arr Array with item labels to check with filter * @param {Array} filter Filter array @@ -754,7 +805,13 @@ module.exports = class COMPONENT extends COMMON { */ _labels(arr, filter) { return filter.every((filter) => { - if (arr.includes(filter)) { + if (arr.map((label) => { + + // convert back to string array + // so the .include can do its job + return label.toString(); + + }).includes(filter)) { return true; @@ -764,14 +821,12 @@ module.exports = class COMPONENT extends COMMON { return arr.some((label) => { - let [k, v] = label.split("="); - if (value === "*") { - return key === k; + return key === label.key; } if (key === "*") { - return value === v; + return value === label.value; } return false; diff --git a/system/component/class.item.js b/system/component/class.item.js new file mode 100644 index 0000000..65b9258 --- /dev/null +++ b/system/component/class.item.js @@ -0,0 +1,85 @@ +const Joi = require("joi"); + +const Labels = require("./class.labels.js"); +const Label = require("./class.label.js"); + +module.exports = class Item { + + constructor(obj) { + + Object.assign(this, obj); + + // override properties + this._id = String(obj._id); + + // create here class.label.js instance + // see issue https://github.com/OpenHausIO/backend/issues/352 + // this.labels = obj.labels.map(...); + + obj.labels?.forEach((txt, i, arr) => { + if (!(txt instanceof Label)) { + arr[i] = new Label(txt); + } + }); + + let labels = new Labels(...obj.labels || []); + + Object.defineProperty(this, "labels", { + get() { + + //console.log("get called"); + return labels; + + }, + set(value) { + + // clear array + // needed when new array has fewer items than old one + // otherwise it contains old items & has wrong size + labels.splice(0, labels.length); + + value.forEach((txt, i) => { + if (!(txt instanceof Label)) { + labels[i] = new Label(txt); + } else { + labels[i] = txt; + } + }); + + }, + enumerable: true, + configurable: false + }); + + } + + static schema() { + return Joi.object({ + labels: Joi.array().items(Joi.alternatives().try( + Joi.string().regex(/^.+?=.+|.+=.+$/i), + Joi.object().custom((value, helpers) => { + if (value instanceof Label) { + + // convert to string + // otherwise the serialized object is saved into the database + return value.toString(); + + } else { + + return helpers.error("any.custom"); + + } + }, "Instance of class.label.js") + )).default([]), + timestamps: Joi.object({ + created: Joi.number().allow(null).default(null), + updated: Joi.number().allow(null).default(null) + }) + }); + } + + static validate(data) { + return Item.schema().validate(data); + } + +}; \ No newline at end of file diff --git a/system/component/class.label.js b/system/component/class.label.js new file mode 100644 index 0000000..cedc28e --- /dev/null +++ b/system/component/class.label.js @@ -0,0 +1,52 @@ +module.exports = class Label { + + constructor(label) { + + let [key, value] = label.split("="); + + Object.defineProperty(this, "key", { + set(val) { + key = val; + label = `${key}=${value}`; + }, + get() { + return key; + }, + enumerable: true + }); + + Object.defineProperty(this, "value", { + set(val) { + value = val; + label = `${key}=${value}`; + }, + get() { + return value; + }, + enumerable: true + }); + + Object.defineProperty(this, "label", { + set(val) { + let { k, v } = label.split("="); + label = val; + key = k; + value = v; + }, + get() { + return label; + }, + enumerable: true + }); + + } + + toJSON() { + return `${this.key}=${this.value}`; + } + + toString() { + return `${this.key}=${this.value}`; + } + +}; \ No newline at end of file diff --git a/system/component/class.labels.js b/system/component/class.labels.js new file mode 100644 index 0000000..697d5e5 --- /dev/null +++ b/system/component/class.labels.js @@ -0,0 +1,55 @@ +module.exports = class Labels extends Array { + + constructor(...args) { + super(...args); + } + + value(key) { + return this.find((label) => { + return label.key === key; + })?.value; + } + + key(value) { + return this.find((label) => { + return label.value === value; + })?.key; + } + + has(key) { + return !!this.find((label) => { + return label.key === key; + }); + } + + filter(query) { + + let [k, v] = query.split("="); + + return Array.prototype.filter.call(this, (label) => { + + if (k !== "*") { + return label.key === k; + } + + if (v !== "*") { + return label.value === v; + } + + return label.key === k && label.value === v; + + }); + + } + + toJSON() { + return this.map(({ key, value }) => { + return `${key}=${value}`; + }); + } + + includes(str) { + return Array.prototype.includes.call(this.toJSON(), str); + } + +}; \ No newline at end of file diff --git a/system/cronjob/class.cron.js b/system/cronjob/class.cron.js new file mode 100644 index 0000000..9d7d1fd --- /dev/null +++ b/system/cronjob/class.cron.js @@ -0,0 +1,151 @@ +const Job = require("./class.job.js"); + +module.exports = class Cron { + + // based on https://gist.github.com/shimondoodkin/1926749 + + /** + * @class Cron + * @description + * + * @param {Boolean} [autostart=true] Start automaticly processing jobs + * + * @property {Array} jobs + * @property {Number|null} timer + * @property {Number} interval + * @property {Boolean} autostart + */ + constructor(autostart = true) { + + this.jobs = []; + this.timer = null; + this.interval = 60 * 1000; + this.autostart = autostart; + + if (this.autostart) { + this.start(); + } + + } + + + /** + * @function match + * Checks if time/date matches with job + * + * @param {String} a + * @param {String} b + * + * @returns {Boolean} + */ + match(a, b) { + + for (let c, b0, i = 0; i < a.length; i++) { + + c = a[i]; + + if (c[0] === -1 || (b >= c[0] && b <= c[1])) { + + b0 = b - c[0]; + + if (c[2] === -1 || b0 === 0 || b0 % c[2] === 0) { + return true; + } + + } + + } + + return false; + + } + + + /** + * @function process + * Procces jobs + * + * @internal + */ + process() { + + let now = new Date(); + + this.jobs.forEach(({ minute, hour, date, month, day, fnc }) => { + + let run = 1; + + run &= this.match(minute, now.getMinutes()); + run &= this.match(hour, now.getHours()); + run &= this.match(date, now.getDate()); + run &= this.match(month, now.getMonth()); + run &= this.match(day, now.getDay()); + + if (run) { + fnc(); + } + + }); + + } + + + /** + * @function add + * Add new job + * + * @param {String} cron Time declaration + * @param {Function} fnc Function to exectute + * + * @returns {Number} Index of the job in the jobs array + */ + add(cron, fnc) { + return this.jobs.push(new Job(cron, fnc)) - 1; + } + + + /** + * @function remove + * Removes a job from being executed + * + * @param {Number} i Index of the job + * + * @returns {Object} The removed job object + */ + remove(i) { + return this.jobs.splice(i, 1)[0]; + } + + + /** + * @function start + * Start executing jobs + */ + start() { + if (!this.timer) { + + this.timer = setInterval(() => { + this.process(); + }, this.interval); + + // do not wait for the interl to exit node + // if this is not done, the unit tests never finish + // https://nodejs.org/api/timers.html#timers_timeout_unref + // https://bilaldurrani.com/post/2018/02/21/mocha-tests-hanging-with-timers/ + this.timer.unref(); + + } + } + + + /** + * @function stop + * Stop executing jobs + */ + stop() { + clearInterval(this.timer); + this.timer = null; + } + + +}; \ No newline at end of file diff --git a/system/cronjob/class.job.js b/system/cronjob/class.job.js new file mode 100644 index 0000000..e7c9df3 --- /dev/null +++ b/system/cronjob/class.job.js @@ -0,0 +1,72 @@ +/** + * @description + * Job that represents a cronjob job.
+ * Note: Non-standard predefined scheduling definitions, like `@weekly`, are not supported! + * + * @class Job + * + * @param {String} cron String that reprentes when the job should be run + * @param {Function} fnc Callback function to execute, gets called when its time to run job + * + * @property {Array} minute + * @property {Array} hour + * @property {Array} date + * @property {Array} month + * @property {Array} day + * @property {Function} fnc Callback that gets called when its time to run job + * + * @link https://en.wikipedia.org/wiki/Cron#Overview + * @link https://crontab.guru/ + */ +module.exports = class Job { + + constructor(cron, fnc) { + + // TODO (mstirner) fix eslint rule + // eslint-disable-next-line no-useless-escape + let parts = cron.match(/^([0-9,\-\/]+|\*{1}|\*{1}\/[0-9]+)\s+([0-9,\-\/]+|\*{1}|\*{1}\/[0-9]+)\s+([0-9,\-\/]+|\*{1}|\*{1}\/[0-9]+)\s+([0-9,\-\/]+|\*{1}|\*{1}\/[0-9]+)\s+([0-9,\-\/]+|\*{1}|\*{1}\/[0-9]+)\s*$/); + + this.minute = this.parse(parts[1]); + this.hour = this.parse(parts[2]); + this.date = this.parse(parts[3]); + this.month = this.parse(parts[4]); + this.day = this.parse(parts[5]); + + this.fnc = fnc; + + } + + /** + * @function parse + * Parse a time expression + * + * @param {String} a + * + * @returns {Array} + */ + parse(a) { + return a.split(",").map((i) => { + + let z = i.split("/"); + let x = z[0].split("-"); + + if (x[0] == "*") { + x[0] = -1; + } + + if (x.length == 1) { + x.push(x[0]); + } + + x[2] = z.length === 1 ? -1 : z[1]; + // parsed array structure: + x[0] = parseInt(x[0]); // 0 - from + x[1] = parseInt(x[1]); // 1 - to + x[2] = parseInt(x[2]); // 2 modulus + + return x; + + }); + } + +}; \ No newline at end of file diff --git a/system/cronjob/index.js b/system/cronjob/index.js new file mode 100644 index 0000000..30a1c59 --- /dev/null +++ b/system/cronjob/index.js @@ -0,0 +1,77 @@ +const Cron = require("./class.cron.js"); +const Job = require("./class.job.js"); + +/** + * @description + * This describes the component staff in the system folder.
+ * Every component depends on this classes and inherits all properties/methods. + * + * The `index.js` file is just a shortcut to the class files: + * + * + * @example + * ```js +const Cron = require("./class.cron.js"); +const Job = require("./class.job.js"); + +module.exports = { + Cron, + Job +}; + * ``` + */ +module.exports = { + Cron, + Job +}; + +/* +const cron = new Cron(); + +cron.add("* * * * *", () => { + console.log('cron job 1 just ran - every minute'); +}); + + +// *2 = *\/2 = \/ = / +cron.add("*2 * * * *", () => { + console.log('cron job 1.5 just ran - every 2 minute'); +}); + +cron.add("5 * * * *", () => { + console.log('cron job 2 just ran - every hour on minute 5') +}); + +cron.add("15 * * * *", () => { + console.log('cron job 3 just ran') +}); + +cron.add("30 * * * *", () => { + console.log('cron job 4 just ran') +}); + +cron.start(); + +// Cron already running, but we can add more jobs, no problem +cron.add("0 * * * *", () => { + console.log('cron job 5 just ran') +}); + +cron.add("7 9 * * 1,2,3,4,5", () => { + console.log('at 9:07 of every morning from sunday to thursday') +}); + + +let i = cron.add("* * * * *", () => { + console.log("Manuall created job: * * * * *") +}); + + +console.log(cron.jobs.length, i); + +setTimeout(() => { + console.log("Remove: Manuall created job"); + cron.remove(i); + cron.remove(0); +}, 1000 * 60 * 3); +*/ \ No newline at end of file diff --git a/system/dispatcher.js b/system/dispatcher.js index 5a2ce93..0148aa7 100644 --- a/system/dispatcher.js +++ b/system/dispatcher.js @@ -28,7 +28,27 @@ module.exports = function dispatch({ component, item, method, args }) { let C_COMPONENT = require(`../components/${component}`); return C_COMPONENT.get(item).then((item) => { - return Reflect.apply(item[method], item, args); + if (item && item[method] && item[method] instanceof Function) { + + let result = Reflect.apply(item[method], item, args); + + /* + // draft for component/scene + // "example" for trigger that allow to check when a scene is executed + this.emit(component, { + item, + method, + args + }); + */ + + return result; + + } else { + + return Promise.resolve(); + + } }).catch((err) => { return Promise.reject(err); }); diff --git a/system/eventbus/class.bus.js b/system/eventbus/class.bus.js new file mode 100644 index 0000000..2095239 --- /dev/null +++ b/system/eventbus/class.bus.js @@ -0,0 +1,74 @@ +const RPC = require("./class.rpc.js"); +const Topic = require("./class.topic.js"); + +module.exports = class Bus { + + /** + * @class Eventbus + * Eventbus class that allow to subscribe topics and call remote functions.
+ * + * @property {RPC} _rpc RPC class instance, for internal use! + * @property {Topic} _topic Topic class instance, for internal use! + * @property {RPC} RPC RPC class + * @property {Topic} Topic Topic class + */ + constructor() { + this._rpc = new RPC(); + this._topic = new Topic(); + } + + static RPC = RPC; + static Topic = Topic; + + /** + * @function call + * Calls a remote registered function.
+ * Wrapper for `_rpc.call();` + * + * @param {...any} args + * @returns + */ + call(...args) { + return Reflect.apply(this._rpc.call, this._rpc, args); + } + + + /** + * @function register + * Register a remote callable function.
+ * Wrapper for `_rpc.register();` + * + * @param {...any} args + * @returns + */ + register(...args) { + return Reflect.apply(this._rpc.register, this._rpc, args); + } + + + /** + * @function subscribe + * Subscribe to a topic.
+ * Wrapper for `_topic.subscribe();` + * + * @param {...any} args + * @returns + */ + subscribe(...args) { + return Reflect.apply(this._topic.subscribe, this._topic, args); + } + + + /** + * @function publish + * Publish a value for a topic.
+ * Warpper for `_topic.publish();` + * + * @param {...any} args + * @returns + */ + publish(...args) { + return Reflect.apply(this._topic.publish, this._topic, args); + } + +}; \ No newline at end of file diff --git a/system/eventbus/class.rpc.js b/system/eventbus/class.rpc.js new file mode 100644 index 0000000..f732918 --- /dev/null +++ b/system/eventbus/class.rpc.js @@ -0,0 +1,122 @@ +const { randomUUID } = require("crypto"); +const { EventEmitter } = require("events"); + +module.exports = class RPC extends EventEmitter { + + constructor() { + super(); + this._rpcs = {}; + this._pending = {}; + } + + /** + * @function register + * Register a RPC method that can be called + * + * @param {String} uri + * @param {Function} cb + */ + register(uri, cb) { + this._rpcs[uri] = cb; + return cb; + } + + + /** + * @function call + * Calls a rpc function + * + * @param {String} uri + * @param {Array} [args=[]] + * @param {Function} [cb=()=> {}] + */ + call(uri, args = [], cb) { + if (this._rpcs[uri]) { + + let id = randomUUID(); + this._pending[id] = cb; + + // TODO: Check if last arg is a function? + //if(args[args.length - 1] instanceof Function && !cb){ + // this._pending[id] = args.pop(); + //} + + try { + + let ret = Reflect.apply(this._rpcs[uri], null, args); + + if (ret instanceof Promise) { + + ret.then((val) => { + Reflect.apply(this._pending[id], null, [null, val]); + }).catch((err) => { + Reflect.apply(this._pending[id], null, [err]); + }).finally(() => { + delete this._pending[id]; + }); + + } else { + + Reflect.apply(this._pending[id], null, [null, ret]); + delete this._pending[id]; + + } + + } catch (err) { + + Reflect.apply(this._pending[id], null, [err]); + delete this._pending[id]; + + } + + if (!cb) { + return new Promise((resolve) => { + this._pending[id] = resolve; + }); + } + + } else { + + throw new Error(`RPC ${uri} not found`); + + } + } + + /* + regrpc(uri, rpc) { + console.log("Registering " + uri); + this._rpcs[uri] = rpc; + this.emit('RPCRegistered', [uri]) + }; + + unregrpc(uri) { + console.log("Unregistering " + uri); + delete this._rpcs[uri]; + this.emit('RPCUnregistered', [uri]); + }; + + callrpc(uri, args, callback) { + if (typeof this._rpcs[uri] !== 'undefined') { + + let invId = randomUUID(); + this._pending[invId] = callback; + this._rpcs[uri].apply(this, [invId, args]); + + return true; + + } else { + + return false; + + } + }; + + resrpc(invId, err, args) { + if (typeof _pending[invId] !== 'undefined') { + this._pending[invId].apply(this, [err, args]); + delete _pending[invId]; + } + }; + */ + +}; \ No newline at end of file diff --git a/system/eventbus/class.topic.js b/system/eventbus/class.topic.js new file mode 100644 index 0000000..82ede28 --- /dev/null +++ b/system/eventbus/class.topic.js @@ -0,0 +1,74 @@ +const { EventEmitter } = require("events"); + + +module.exports = class Topic extends EventEmitter { + + constructor() { + super(); + this._topics = {}; + } + + + subscribe(uri, cb) { + + console.log(this); + + if (!this._topics[uri]) { + this._topics[uri] = []; + } + + this._topics[uri].push(cb); + + } + + + publish(uri, val) { + if (this._topics[uri]) { + + this._topics[uri].forEach((cb) => { + cb(val); + }); + + } else { + + // do nothing? + //throw new Error(`Topic ${uri} not found`); + + } + } + + + /* + substopic(topicUri, subscriptionId, callback) { + console.log("Registering topic " + topicUri + " subsc id " + subscriptionId); + if (typeof this._topics[topicUri] === 'undefined') { + this._topics[topicUri] = {}; + } + this._topics[topicUri][subscriptionId] = callback; + this.emit('Subscribe', topicUri); + }; + + unsubstopic(topicUri, subscriptionId) { + console.log("Unregistering topic " + topicUri + " subsc id " + subscriptionId); + delete this._topics[topicUri][subscriptionId]; + this.emit('Unsubscribe', topicUri); + }; + + publish(topicUri, publicationId, args, kwargs) { + console.log("Publish " + topicUri + " " + publicationId); + this.emit('Publish', topicUri, args, kwargs); + if (typeof this._topics[topicUri] !== 'undefined') { + for (var key in this._topics[topicUri]) { + if (typeof this._topics[topicUri][key] !== 'undefined') { + this._topics[topicUri][key].apply(this, [publicationId, args, kwargs]); + } + } + return true; + } else { + console.log("Undefined topic "); + return false; + } + }; + */ + +}; \ No newline at end of file diff --git a/system/eventbus/index.js b/system/eventbus/index.js new file mode 100644 index 0000000..23b2713 --- /dev/null +++ b/system/eventbus/index.js @@ -0,0 +1,68 @@ +const RPC = require("./class.rpc.js"); +const Topic = require("./class.topic.js"); +const Bus = require("./class.bus.js"); + + +class Eventbus extends Bus { + + constructor(...args) { + super(...args); + } + + static RPC = RPC; + static Topic = Topic; + static Eventbus = Eventbus; + +} + + +const eventbus = new Eventbus(); +Object.assign(eventbus, Eventbus); +module.exports = eventbus; + + +console.log(eventbus); + +/* +eventbus.subscribe("endpoint/6458dc42b55679622e893e6d/state/6458dc53a7b3b998ebb67027", (value) => { + console.log("Topic published:", value); +}); + + +eventbus.publish("endpoint/6458dc42b55679622e893e6d/state/6458dc53a7b3b998ebb67027", 49); + + +//register(`${name}/${method}`, this[method]); + + +eventbus.register("components/rooms/foo", (a, b) => { + + + //return a + b; + //throw new Error("Foo bar alsdkflafjsdk") + + return new Promise((resolve, reject) => { + setTimeout(() => { + //reject(new Error("foo, math is bad")); + resolve(a + b); + }, 3000); + }); + +}); + + +eventbus.call("components/rooms/foo", [1, 2], (err, result) => { + console.log("Calculation done", err || result); +}); + + + +console.log(JSON.stringify({ + foo: true, + bar: "baz", + fnc: () => { + console.log("Hello World") + }, + buff: Buffer.from("Heöö") +})) +*/ \ No newline at end of file diff --git a/system/init/init.components.js b/system/init/init.components.js new file mode 100644 index 0000000..513e018 --- /dev/null +++ b/system/init/init.components.js @@ -0,0 +1,77 @@ +const path = require("path"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve) => { + + logger.debug("Init components..."); + + const componentNames = [ + "devices", + "endpoints", + "plugins", + "rooms", + "ssdp", + "store", + "users", + "vault", + "webhooks", + "mqtt", + "mdns", + "scenes" + ].sort(() => { + + // pseudo randomize start/init of components + // https://stackoverflow.com/a/18650169/5781499 + return 0.5 - Math.random(); + + }); + + let componentConter = 0; + //let counter = componentNames.length; + + + // map over array + // create from each promise + // use Promise.all() ? + // better/quicker start? + componentNames.forEach((name) => { + try { + + // this should be trace method + logger.verbose(`Starting component "${name}"`); + + let component = require(path.resolve(process.cwd(), `components/${name}/index.js`)); + + component.events.on("ready", () => { + + componentConter += 1; + + logger.debug(`Component "${name}" ready to use. (${componentConter}/${componentNames.length})`); + + if (componentConter === componentNames.length) { + logger.info(`All ${componentNames.length} Components ready`); + resolve(); + } + + }); + + // see issue #53, this should fire: + // the procces should not exit with a "unhandled execption" + // the try/catch block is for unhandled exception, not for startup errors + component.events.on("error", (err) => { + logger.error(err, `Component "${name}" error!`); + process.exit(1); // fix #53 + }); + + } catch (err) { + + console.error(err, "Component error"); + process.exit(800); + + } + }); + + }); + }; +}; \ No newline at end of file diff --git a/system/init/init.database.js b/system/init/init.database.js new file mode 100644 index 0000000..a77a96f --- /dev/null +++ b/system/init/init.database.js @@ -0,0 +1,90 @@ +const mongodb = require("mongodb"); +const { URL } = require("url"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve, reject) => { + + logger.debug("Init Database..."); + + let url = new URL(`mongodb://${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_NAME}`); + + if (process.env.DATABASE_AUTH_USERNAME) { + url.username = process.env.DATABASE_AUTH_USERNAME; + } + + if (process.env.DATABASE_AUTH_USERNAME) { + url.password = process.env.DATABASE_AUTH_PASSWORD; + } + + if (process.env.DATABASE_URL) { + console.log("OVerride DATBAASE_URL"); + Object.assign(url, new URL(process.env.DATABASE_URL)); + } + + // feedback + logger.verbose(`Connecting to "mongodb://${url.hostname}:${url.port}${url.pathname}"...`); + + + mongodb.MongoClient.connect(url.toString(), { + useUnifiedTopology: true, + useNewUrlParser: true, + //connectTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000, // #9 + //socketTimeoutMS: Number(process.env.DATABASE_TIMEOUT) * 1000 // #9 + }, async (err, client) => { + + if (err) { + logger.error(err, "Could not connect to database"); + return reject(err); + } + + // monky patch db instance + // use this instance in other files + //mongodb.client = client.db(process.env.DATABASE_NAME); + mongodb.connection = client; + mongodb.client = client.db(); + + + client.on("error", (err) => { + logger.error(err, "Could not connecto to databse: %s", err.message); + }); + + client.on("close", () => { + process.exit(1000); + }); + + + try { + + // test authenticiation + // throws a error is auth is noc successfull + await mongodb.client.stats(); + + // feedback + logger.info(`Connected to "mongodb://${url.hostname}:${url.port}${url.pathname}"`); + + process.once("SIGINT", () => { + mongodb.connection.close(() => { + logger.info(`Connection closed from "mongodb://${url.hostname}:${url.port}${url.pathname}"`); + }); + }); + + resolve(); + + } catch (err) { + + if (err?.code == 13) { + logger.error("Invalid database credentials!"); + } + + client.emit("error", err); + reject(err); + + } + + + }); + + }); + }; +}; \ No newline at end of file diff --git a/system/init/init.http-server.js b/system/init/init.http-server.js new file mode 100644 index 0000000..153e7c1 --- /dev/null +++ b/system/init/init.http-server.js @@ -0,0 +1,189 @@ +const http = require("http"); +const fs = require("fs"); + +module.exports = (logger) => { + return () => { + return new Promise((resolve, reject) => { + + logger.debug("Init http server..."); + + // store active sockets from requests + // see #345 + const sockets = new Set(); + + const servers = [ + + // http server for ip/port + new Promise((resolve, reject) => { + if (process.env.HTTP_ADDRESS !== "") { + + let server = http.createServer(); + + server.on("connection", (socket) => { + + sockets.add(socket); + + socket.on("close", () => { + sockets.delete(socket); + }); + + }); + + server.on("error", (err) => { + logger.error(err, `Could not start http server: ${err.message}`); + reject(err); + }); + + server.on("listening", () => { + + let addr = server.address(); + logger.info(`HTTP Server listening on http://${addr.address}:${addr.port}`); + + resolve(server); + + }); + + server.on("close", () => { + logger.info(`HTTP Server closed on http://${process.env.HTTP_ADDRESS}:${process.env.HTTP_PORT}`); + }); + + // NOTE: Route handler get required/create twice: + // instead, require router file global + // and pass/move the request handler here + // thus prevents to create 2 express apps for each server + // "routes/index.js" should export the express app + //require("../../routes/index.js")(server); + + // bind/start http server + server.listen(Number(process.env.HTTP_PORT), process.env.HTTP_ADDRESS); + + } else { + resolve(); + } + }), + + // http server for unix socket + new Promise((resolve, reject) => { + if (process.env.HTTP_SOCKET !== "") { + + let server = http.createServer(); + + server.on("connection", (socket) => { + + sockets.add(socket); + + socket.on("close", () => { + sockets.delete(socket); + }); + + }); + + server.on("error", (err) => { + + logger.error(err, `Could not start http server: ${err.message}`); + reject(err); + + }); + + server.on("listening", () => { + + logger.info(`HTTP Server listening on ${process.env.HTTP_SOCKET}`); + + resolve(server); + + }); + + server.on("close", () => { + logger.info(`HTTP Server closed on ${process.env.HTTP_SOCKET}`); + }); + + // NOTE: Route handler get required/create twice: + // instead, require router file global + // and pass/move the request handler here + // thus prevents to create 2 express apps for each server + // "routes/index.js" should export the express app + //require("../../routes/index.js")(server); + + try { + + // cleanup + fs.unlinkSync(process.env.HTTP_SOCKET); + + } catch (err) { + if (err.code !== "ENOENT") { + + reject(err); + + } + } finally { + + // bind/start http server + server.listen(process.env.HTTP_SOCKET); + + } + + } else { + resolve(); + } + }) + + ]; + + Promise.all(servers).then((servers) => { + + // require express main router + let app = require("../../routes/index.js"); + + // fix #435 + ["SIGINT", /*"SIGTERM", "SIGQUIT"*/].forEach((signal) => { + process.once(signal, () => { + + // see #345 + // close all active http sockets/requests + for (const socket of sockets.values()) { + socket.destroy(); + } + + servers.forEach((server) => { + server.close(); + }); + + }); + }); + + servers.forEach((server) => { + + // use express request handler + server.on("request", app); + + // fix #408, see: + // https://github.com/OpenHausIO/connector/issues/38 + // https://github.com/websockets/ws/issues/2193 + server.on("upgrade", (req, socket) => { + + let res = new http.ServerResponse(req); + res.assignSocket(socket); + + res.on("finish", () => { + res.socket.destroy(); + }); + + app(req, res); + + }); + + }); + + resolve(); + + }).catch((err) => { + + logger.error(err, "Could not start http server(s)", err); + + reject(err); + + }); + + }); + }; +}; \ No newline at end of file diff --git a/system/logger/class.logger.js b/system/logger/class.logger.js index da11f45..a4d8cf6 100644 --- a/system/logger/class.logger.js +++ b/system/logger/class.logger.js @@ -1,6 +1,23 @@ const { EOL } = require("os"); const util = require("util"); +const { Transform } = require("stream"); +//const exporter = new PassThrough(); +const exporter = new Transform({ + transform(chunk, encoding, cb) { + + // ignore & drop every message if no pipe/consumer. Otherwise this jams up the stream + // TODO: check with this.listenerCount('data'|'readable')? + if (this._readableState.pipes.length > 0 || this._events.data instanceof Function) { + this.push(chunk); + } + + //cb(); + process.nextTick(cb); + + } +}); + const levels = require("./levels"); /** @@ -55,6 +72,8 @@ module.exports = class Logger { let err = args.shift(); + // NOTE: `Object.getOwnPropertyNames(err)` makes no sense here + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify obj.error = JSON.stringify(err, Object.getOwnPropertyNames(err)); obj.message = util.format(...args); @@ -62,6 +81,21 @@ module.exports = class Logger { } else { + // fix #331 + // NOTE: here could be a level specific options + // e.g. for "verbose", set "showProxy" or "getters" + // https://nodejs.org/docs/latest/api/util.html#utilinspectobject-showhidden-depth-colors + // optinal configurable with environment variable like "LOGGER_INSPECT_OPTIONS" or so... + /* + args = args.map((arg) => { + //return JSON.stringify(arg, null, 2); + return util.inspect(arg, { + depth: null, + colors: true, + }); + }); + */ + //obj.message = args.shift(); obj.message = util.format(...args); //obj.fields = args; @@ -136,4 +170,8 @@ module.exports = class Logger { } + static exporter() { + return exporter; + } + }; \ No newline at end of file diff --git a/system/logger/index.js b/system/logger/index.js index fedf82b..1e3f5e9 100644 --- a/system/logger/index.js +++ b/system/logger/index.js @@ -60,7 +60,10 @@ const combined = createWriteStream(path.resolve(process.env.LOG_PATH, "combined. flags: "a" }); -[system, combined].forEach((stream) => { +const exporter = Logger.exporter(); + + +[system, combined, exporter].forEach((stream) => { stream.on("error", (err) => { console.error(err); process.exit(1); @@ -92,7 +95,8 @@ const options = { streams: [ stdout, system, - combined + combined, + exporter ], level: process.env.LOG_LEVEL }; @@ -126,7 +130,8 @@ Object.defineProperty(logger, "create", { streams: [ stdout, stream, - combined + combined, + exporter ] }); diff --git a/system/notifications/class.notification.js b/system/notifications/class.notification.js new file mode 100644 index 0000000..6dd30c4 --- /dev/null +++ b/system/notifications/class.notification.js @@ -0,0 +1,132 @@ +const { randomUUID } = require("crypto"); +const { EventEmitter } = require("events"); +const Joi = require("joi"); + + +const events = new EventEmitter(); +const notifications = []; + + +// `new Set()` would be better, but its not proxyable +// TypeError: Method Set.prototype.add called on incompatible receiver # +// try it with prop.bind(set/receiver)? +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Called_on_incompatible_type +// > why event the proxy trap? emit the added event when a new notificaiton instance is created +// TODO: test/switch to - with new Set(); +/* +const notifications = new Proxy([], { + set(target, prop, val, receiver) { + + events.emit("added", val); + return Reflect.set(target, prop, val, receiver); + //receiver.add(val); + + } +}); +*/ + + +module.exports = class Notification { + + constructor(data) { + + let { error, value } = Notification.validate(data); + + if (error) { + throw error; + } + + // set/merge default values + // TODO: check how to set defaults form schema definition! + Object.assign(this, { + timestamps: { + created: Date.now(), + published: null + } + }, value); + + // hidden property + // move into schema definition? + // why keep this secret? + Object.defineProperty(this, "published", { + value: false, + writable: true + }); + + // add notification + //notifications.add(this); + notifications.push(this); + events.emit("added", this); + + } + + publish() { + if (!this.published) { + + this.published = true; + this.timestamps.published = Date.now(); + + //if (!this.retain) { + process.nextTick(() => { + + events.emit("publish", this); + //notifications.delete(this); + + let index = notifications.find(({ uuid }) => { + return this.uuid === uuid; + }); + + notifications.splice(index, 1); + + }); + //} + + } + } + + detain() { + + let index = notifications.find(({ uuid }) => { + return this.uuid === uuid; + }); + + notifications.splice(index, 1); + + } + + static schema() { + return Joi.object({ + title: Joi.string().required(), + message: Joi.string().required(), + uuid: Joi.string().default(() => { + return randomUUID(); + }), + type: Joi.string().valid("info", "warn", "error").default("info"), + //actions: Joi.array().items().default([]), + //retain: Joi.boolean().default(false), + timestamps: Joi.object({ + created: Joi.number().allow(null).default(() => { + return Date.now(); + }), + published: Joi.number().allow(null).default(null) + }) + }); + } + + static validate(data) { + return Notification.schema().validate(data); + } + + static events() { + return events; + } + + static notifications(convert = false) { + if (convert) { + return Array.from(notifications); + } else { + return notifications; + } + } + +}; \ No newline at end of file diff --git a/system/notifications/index.js b/system/notifications/index.js new file mode 100644 index 0000000..d4a70cb --- /dev/null +++ b/system/notifications/index.js @@ -0,0 +1,8 @@ +const Notification = require("./class.notification.js"); + + +module.exports = { + Notification, + events: Notification.events(), + notifications: Notification.notifications() +}; \ No newline at end of file diff --git a/tests/components/endpoints.js b/tests/components/endpoints.js index 9f02635..1f5f595 100644 --- a/tests/components/endpoints.js +++ b/tests/components/endpoints.js @@ -16,7 +16,11 @@ try { C_COMPONENT.add({ _id, name: "Endpoint #1", - device: _device + device: _device, + labels: [ + "key1=value1", + "key2=value2" + ] }, (err, item) => { try { @@ -59,7 +63,11 @@ try { workflow(C_COMPONENT, "update", (done) => { C_COMPONENT.update(_id, { - name: "Endpoint #2 - updated" + name: "Endpoint #2 - updated", + labels: [ + "overriden=true", + "key3=value3" + ] }, (err, item) => { try { diff --git a/tests/components/plugins.js b/tests/components/plugins.js index 7c08e3b..3c54233 100644 --- a/tests/components/plugins.js +++ b/tests/components/plugins.js @@ -15,7 +15,7 @@ try { C_COMPONENT.add({ _id, name: "Plugin #1", - version: 1, + version: "1.2.3", intents: ["devices", "endpoints", "plugins", "rooms", "ssdp", "store", "users", "vault"] }, (err, item) => { try { @@ -59,13 +59,13 @@ try { workflow(C_COMPONENT, "update", (done) => { C_COMPONENT.update(_id, { - version: 2 + version: "2.3.8" }, (err, item) => { try { assert.ok(err === null); assert.equal(item instanceof Plugin, true); - assert.equal(item.version, 2); + assert.equal(item.version, "2.3.8"); done(err); @@ -83,7 +83,7 @@ try { // update call 1 C_COMPONENT.update(_id, { - version: 3 + version: "87.65.4321" }), // update call 2 diff --git a/tests/components/rooms.js b/tests/components/rooms.js index 2fe23b3..f137a6a 100644 --- a/tests/components/rooms.js +++ b/tests/components/rooms.js @@ -15,7 +15,11 @@ try { C_COMPONENT.add({ _id, name: "Room #1", - floor: 1 + floor: 1, + labels: [ + "foo=bar", + "baz=true" + ] }, (err, item) => { try { diff --git a/tests/components/store.js b/tests/components/store.js index 1677cb3..3e9e594 100644 --- a/tests/components/store.js +++ b/tests/components/store.js @@ -10,17 +10,20 @@ try { const workflow = require("./test.workflow.js"); let _id = String(new mongodb.ObjectId()); - let namespace = String(new mongodb.ObjectId()); + let uuid = uuidv4(); workflow(C_COMPONENT, "add", (done, { event }) => { C_COMPONENT.add({ _id, + name: "Test store", + description: "Test item for unit tests", config: [{ + name: "Test Key", key: "key", type: "string", description: "Test key" }], - namespace + uuid }, (err, item) => { // check event arguments @@ -57,16 +60,13 @@ try { workflow(C_COMPONENT, "update", (done) => { - let uuid = uuidv4(); - C_COMPONENT.update(_id, { - item: uuid + name: "Updated Name" }, (err, item) => { try { assert.ok(err === null); assert.equal(item instanceof Store, true); - assert.equal(item.item, uuid); done(err); @@ -85,12 +85,12 @@ try { // update call 1 C_COMPONENT.update(_id, { - item: uuidv4() + uuid: uuidv4() }), // update call 2 C_COMPONENT.update(_id, { - item: uuidv4() + name: "New config/store name" }) ]).then(() => { diff --git a/tests/components/test.workflow.js b/tests/components/test.workflow.js index 5a83433..af1594c 100644 --- a/tests/components/test.workflow.js +++ b/tests/components/test.workflow.js @@ -4,6 +4,9 @@ const sinon = require("sinon"); const _iterate = require("../../helper/iterate.js"); +const Item = require("../../system/component/class.item.js"); +const Label = require("../../system/component/class.label.js"); + module.exports = (C_COMPONENT, method, desc, worker) => { if (!worker && desc instanceof Function) { @@ -51,6 +54,28 @@ module.exports = (C_COMPONENT, method, desc, worker) => { done(); }); + it("Component item should be instance of item class", (done) => { + assert.ok(C_COMPONENT.items[0] instanceof Item); + done(); + }); + + it("Item .labels array should contain only class.label.js instances", () => { + + let valid = C_COMPONENT.items.map(({ labels }) => { + return labels; + }).flat().every((label) => { + return label instanceof Label; + }); + + assert.ok(valid); + + }); + + it("Component item _id property should be a string, not a ObjectId instance", (done) => { + assert.ok(typeof (C_COMPONENT.items[0]._id) === "string"); + done(); + }); + it(`Every array in item should have a _id property ${desc ? "(" + desc + ")" : ""}`, (done) => { try { @@ -59,11 +84,15 @@ module.exports = (C_COMPONENT, method, desc, worker) => { if (type === "array") { let result = value.every((entry) => { - if (entry instanceof Object) { + + // check if only "plain" objects have _id property + // otherwise this check fails on the .labels array items + if (entry instanceof Object && Object.getPrototypeOf(entry) === null) { return Object.hasOwnProperty.call(entry, "_id"); } else { return true; } + }); assert.ok(result === true); diff --git a/tests/components/users.js b/tests/components/users.js index 40c946e..6d0a9e8 100644 --- a/tests/components/users.js +++ b/tests/components/users.js @@ -59,7 +59,10 @@ try { workflow(C_COMPONENT, "update", (done) => { C_COMPONENT.update(_id, { - enabled: true + enabled: true, + labels: [ + "expires=29991231" + ] }, (err, item) => { try { @@ -83,7 +86,11 @@ try { // update call 1 C_COMPONENT.update(_id, { - password: "12345678" + password: "12345678", + labels: [ + "expires=29991231", + "key=value" + ] }), // update call 2 diff --git a/tests/helper/index.js b/tests/helper/index.js index adae309..8032d91 100644 --- a/tests/helper/index.js +++ b/tests/helper/index.js @@ -8,6 +8,7 @@ describe("Helper functions", function () { require("./test.extend.js"); //require("./test.filter.js"); // todo or remove?! see #19 require("./test.infinity.js"); + //require("./test.injectMethod.js"); // removed due to problems on `interface.bridge()`, see https://github.com/OpenHausIO/backend/issues/463#issuecomment-2131411981 require("./test.iterate.js"); require("./test.mixins.js"); require("./test.observe.js"); diff --git a/tests/helper/test.injectMethod.js b/tests/helper/test.injectMethod.js new file mode 100644 index 0000000..913edef --- /dev/null +++ b/tests/helper/test.injectMethod.js @@ -0,0 +1,77 @@ +const assert = require("assert"); +const { describe, it } = require("mocha"); + +const injectMethod = require("../../helper/injectMethod"); + +class Item{ + + constructor(){ + this.boolean = true; + } + + ping(){ + return this; + } + +} + +describe("helper/injectMethod", () => { + + it(`Define method on class protoype`, (done) => { + + let item = new Item(); + + injectMethod(item, "pong", function pong(){ + return this; + }); + + let proto = Object.getPrototypeOf(item); + let props = Object.getOwnPropertyNames(proto); + + assert.ok(props.includes("ping")); + assert.ok(props.includes("pong")); + + done(); + + }); + + + it(`Compare prototype descriptors of methods ping/pong`, (done) => { + + let item = new Item(); + + injectMethod(item, "pong", function(){ + return this; + }); + + let proto = Object.getPrototypeOf(item); + let ping = Object.getOwnPropertyDescriptor(proto, "ping"); + let pong = Object.getOwnPropertyDescriptor(proto, "pong"); + + // remove function (want only the descriptors); + delete ping.value; + delete pong.value; + + assert.deepEqual(ping, pong); + + done(); + + }); + + + it(`Check if "this" scope is set correctly for method`, (done) => { + + let item = new Item(); + + injectMethod(item, "pong", function(){ + return this; + }); + + assert.deepEqual(item.ping(), item.pong()); + assert.ok(item.ping() === item.pong()); + + done(); + + }); + +}); \ No newline at end of file diff --git a/tests/helper/test.request.js b/tests/helper/test.request.js index cfd64d2..763bd4c 100644 --- a/tests/helper/test.request.js +++ b/tests/helper/test.request.js @@ -44,9 +44,30 @@ describe("helper/request", () => { }); }); - it("- returns a http request object", () => { + it("- returns a promise if no callback provided", () => { - let req = request("http://127.0.0.1/"); + let rtrn = request("http://127.0.0.1/"); + + assert(rtrn instanceof Promise); + + }); + + it("- returns undefined if a callback is provided", (done) => { + + let rtrn = request("http://127.0.0.1/", (err) => { + assert(rtrn === undefined); + done(err); + }); + + }); + + it('- should have a ".perform" method patched', () => { + assert(request.perform instanceof Function); + }); + + it("- perform method should return instanceof ClientRequest", () => { + + let req = request.perform("http://127.0.0.1"); assert(req instanceof ClientRequest); diff --git a/tests/http-api/index.js b/tests/http-api/index.js new file mode 100644 index 0000000..a1a5927 --- /dev/null +++ b/tests/http-api/index.js @@ -0,0 +1,90 @@ +const { describe, it } = require("mocha"); +const newman = require("newman"); +const { fork } = require("child_process"); +const path = require("path"); +const crypto = require("crypto"); +const assert = require("assert"); + +const collection = require("../../postman.json"); + + +describe("HTTP API", function () { + + this.timeout(30000); + + //let HTTP_PORT = crypto.randomInt(2048, 1024); + let child = null; + + it("- Should start OpenHaus", (done) => { + + child = fork(path.resolve(process.cwd(), "index.js"), { + silent: true, + env: Object.assign({}, process.env, { + UUID: crypto.randomUUID(), + DATABASE_NAME: "test", + VAULT_MASTER_PASSWORD: crypto.randomBytes(24).toString("hex"), + USERS_JWT_SECRET: crypto.randomBytes(24).toString("hex") + }) + }); + + child.on("spawn", () => { + setTimeout(done, 1500); + }); + + child.on("error", (err) => { + done(err); + }); + + }); + + + // https://gist.github.com/davfive/eae043135ed98b9647ad631bbfc1ab38 + // https://github.com/postmanlabs/newman/wiki/Newman-Run-Events + it("- Should not have any items in summary.run.failres array", (done) => { + + // https://www.npmjs.com/package/newman#newman-options + let emitter = newman.run({ + collection, + //reporters: "json", + timeoutRequest: 3000 + }); + + emitter.once("exception", (err, { error }) => { + console.error("Exception happend", err || error); + done(err || error); + }); + + emitter.once("done", (err, summary) => { + try { + if (err || summary.error) { + + done(err || summary.error); + + } else { + + summary.run.failures.forEach(({ source: { request }, error }) => { + console.error(`[${request.method}] ${request.url.toString()}`, error.message); + }); + + assert.equal(summary.run.failures.length, 0); + + done(); + + } + } catch (err) { + + done(err); + + } + }); + + }); + + + // ensure to kill the backend + // so that github actions complete + this.afterAll(() => { + child.kill(); + }); + +}); \ No newline at end of file diff --git a/tests/index.js b/tests/index.js index 616cee4..672eb9e 100644 --- a/tests/index.js +++ b/tests/index.js @@ -67,6 +67,7 @@ describe("Database", () => { require("./helper/index.js"); require("./system/index.js"); require("./components/index.js"); + //require("./http-api/index.js"); }); }); diff --git a/tests/system/component/index.js b/tests/system/component/index.js index a717d51..5990e00 100644 --- a/tests/system/component/index.js +++ b/tests/system/component/index.js @@ -2,6 +2,8 @@ const { describe } = require("mocha"); describe("system/component", function () { + require("./test.label.js"); + require("./test.labels.js"); require("./test.base.js"); require("./test.common.js"); require("./test.component.js"); diff --git a/tests/system/component/test.component.js b/tests/system/component/test.component.js index 9193426..1978f56 100644 --- a/tests/system/component/test.component.js +++ b/tests/system/component/test.component.js @@ -25,7 +25,7 @@ const getItmes = (obj) => { describe("component", function () { - let instance = new COMPONENT("test", {}); + let instance = new COMPONENT("test", joi.object({})); describe("- should have following properties", () => { diff --git a/tests/system/component/test.label.js b/tests/system/component/test.label.js new file mode 100644 index 0000000..363b4fb --- /dev/null +++ b/tests/system/component/test.label.js @@ -0,0 +1,39 @@ +const { describe, it } = require("mocha"); +const assert = require("assert"); + +const Label = require("../../../system/component/class.label.js"); + +describe("label", function () { + + let instance = new Label("hello=world"); + + it("should have a key property", () => { + assert(instance.key); + }); + + it("should have a value property", () => { + assert(instance.key); + }); + + it("should have a label property", () => { + assert(instance.label); + }); + + it(".key = hello", () => { + assert.equal(instance.key, "hello"); + }); + + it(".value = world", () => { + assert.equal(instance.value, "world"); + }); + + ["toJSON", "toString"].forEach((fnc) => { + + it(`should have method "${fnc}"`, () => { + assert(instance[fnc] instanceof Function); + }); + + }); + + +}); \ No newline at end of file diff --git a/tests/system/component/test.labels.js b/tests/system/component/test.labels.js new file mode 100644 index 0000000..b6be5ca --- /dev/null +++ b/tests/system/component/test.labels.js @@ -0,0 +1,66 @@ +const { describe, it } = require("mocha"); +const assert = require("assert"); + +const Labels = require("../../../system/component/class.labels.js"); +const Label = require("../../../system/component/class.label.js"); + +describe("labels", function () { + + let labels = [ + "foo=bar", + "baz=true", + "gen=1", + 'json={"key": "value"}', + "gen=3" + ].map((txt) => { + return new Label(txt); + }); + + let instance = new Labels(...labels); + + it("should be a instance of Array", () => { + assert(instance instanceof Array); + }); + + it("should have 4 items", () => { + assert.equal(instance.length, 5); + }); + + it("every item should be a instance of class.label.js", () => { + + let valid = instance.every((label) => { + return label instanceof Label; + }); + + assert(valid); + + }); + + [ + "key", "value", "has", + "filter", "toJSON" + ].forEach((fnc) => { + + it(`should have method "${fnc}"`, () => { + assert(instance[fnc] instanceof Function); + }); + + }); + + it('labels.key("bar") should return "foo"', () => { + assert.equal(instance.key("bar"), "foo"); + }); + + it('labels.value("baz") should return "foo"', () => { + assert.equal(instance.value("baz"), "true"); + }); + + it('labels.has("gen") should return true', () => { + assert.equal(instance.has("gen"), true); + }); + + it('labels.filter("gen=*") should return 2 items', () => { + assert.equal(instance.filter("gen=*").length, 2); + }); + +}); \ No newline at end of file