diff --git a/Dockerfile b/Dockerfile index 1669a20..55760a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN mkdir -p /usr/node_app COPY . /usr/node_app WORKDIR /usr/node_app RUN apt-get update ; apt-get install -fy git python make g++ npm curl dirmngr apt-transport-https lsb-release ca-certificates -RUN curl -sL https://deb.nodesource.com/setup_16.x | bash +RUN curl -sL https://deb.nodesource.com/setup_18.x | bash RUN apt-get update ; apt-get -fy install nodejs RUN npm install --production diff --git a/README.md b/README.md index 90a169b..3a6a20f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This is a simple docker container that I use to bridge UniFi protect with my MQTT bridge. +Please note this only works with UniFi protect 5.0 and greater + I have a collection of bridges, and the general format of these begins with these environment variables: ``` @@ -25,10 +27,9 @@ services: image: ghcr.io/terafin/mqtt-unifi-protect-bridge:latest environment: LOGGING_NAME: mqtt-unifi-protect-bridge - PROTECT_URL: URL_FOR_UNIFI_PROTECT_LOGIN (eg: https://10.0.1.2:7443) + PROTECT_URL: URL_FOR_UNIFI_PROTECT_LOGIN (eg: 10.0.1.2) USERNAME: YOUR_USERNAME_FOR_ABOVE_URL PASSWORD: YOUR_PASSWORD_FOR_ABOVE_URL - POLL_FREQUENCY: 1 TOPIC_PREFIX: /your_topic_prefix (eg: /motion) MQTT_HOST: YOUR_MQTT_URL (eg: mqtt://mqtt.yourdomain.net) (OPTIONAL) MQTT_USER: YOUR_MQTT_USERNAME diff --git a/lib/auth.js b/lib/auth.js deleted file mode 100644 index a8f9d83..0000000 --- a/lib/auth.js +++ /dev/null @@ -1,92 +0,0 @@ -const _ = require('lodash') -const logging = require('homeautomation-js-lib/logging.js') -const utils = require('./utils.js') -const got = require('got') - -const API_AUTH_URL_SUFFIX = '/api/auth/login' -const API_ACCESS_KEY_URL_SUFFIX = '/api/auth/access-key' - -var lastCsrfToken = null -var lastCookie = null - -var configuredUsername = null -var configuredPassword = null - -module.exports.setAccount = function(username, password) { - configuredUsername = username - configuredPassword = password -} - -async function authenticate() { - const authURL = utils.generateURL(API_AUTH_URL_SUFFIX) - const accesskeyURL = utils.generateURL(API_ACCESS_KEY_URL_SUFFIX) - var accessToken = null - - logging.info('oauth request url: ' + authURL) - logging.debug(' accesskeyURL: ' + accesskeyURL) - - try { - const response = await got.post(authURL, { json: { username: configuredUsername, password: configuredPassword } }) - const body = response.body - const headers = response.headers - accessToken = lastCsrfToken - - const csrfToken = headers['x-csrf-token'] - const cookie = headers['set-cookie'] - logging.info('csrfToken: ' + csrfToken) - logging.info('cookie: ' + cookie) - - if (!_.isNil(csrfToken)) { - lastCsrfToken = csrfToken - } else { - logging.error(' no csrfToken - bad auth?') - } - - if (!_.isNil(cookie)) { - lastCookie = cookie - } else { - logging.error(' no cookie - bad auth?') - } - - // const accessKeyResponse = await got.post(accesskeyURL, { - // headers: { - // 'Authorization': 'Bearer ' + accessToken.toString() - // } - // }) - - // lastAccessKey = JSON.parse(accessKeyResponse.body).accessKey - } catch (error) { - logging.error('authenticate failed: ' + error) - throw ('authenticate error ' + error) - - } - - return accessToken -} - -module.exports.authenticate = authenticate - -async function authenticateifNeeded() { - if (!_.isNil(lastCsrfToken)) { - return lastCsrfToken - } - - var newToken = null - - try { - newToken = await authenticate() - } catch (error) { - logging.error(' failed authenticaing: ' + error) - throw (error) - } - return newToken -} - -module.exports.authenticateifNeeded = authenticateifNeeded - -module.exports.cachedAuthHeaders = function() { - return { - 'Cookie': lastCookie, - 'X-CSRF-Token': lastCsrfToken - } -} \ No newline at end of file diff --git a/lib/protect.js b/lib/protect.js deleted file mode 100644 index e443c9c..0000000 --- a/lib/protect.js +++ /dev/null @@ -1,101 +0,0 @@ -const _ = require('lodash') -const logging = require('homeautomation-js-lib/logging.js') -const authentication = require('./auth.js') -const utils = require('./utils.js') -const got = require('got') -const API_CAMERA_PATCH = '/api/cameras/' -const API_BOOTSTRAP_SUFFIX = '/proxy/protect/api/bootstrap' -const API_EVENTS_URL = '/proxy/protect/api/events?' -process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0 -var localUsername = null -var localPassword = null - -async function getEvents(types) { - await authentication.authenticateifNeeded() - - var eventURL = utils.generateURL(API_EVENTS_URL) - const now = new Date().getTime() - - eventURL = eventURL + 'allCameras=true&end=' + now + '&start=' + (now - (60 * 1000 * 10)) // pull the last 10 minutes - if (!_.isNil(types)) { - types.forEach(type => { - eventURL = eventURL + '&types=' + type - }) - } - - logging.debug("event url: " + eventURL) - var response_body = null - - try { - const response = await got.get(eventURL, { - headers: { - ...authentication.cachedAuthHeaders() - } - }) - - response_body = JSON.parse(response.body) - } catch (error) { - logging.error('getEvents failed: ' + error) - throw ('getEvents error ' + error) - } - - return response_body -} - -module.exports.getEvents = getEvents - -async function getAPIBootstrap() { - await authentication.authenticateifNeeded() - - const bootstrapURL = utils.generateURL(API_BOOTSTRAP_SUFFIX) - var bootstrap_body = null - - try { - const bootstrap_response = await got.get(bootstrapURL, { - headers: { - ...authentication.cachedAuthHeaders() - } - }) - - bootstrap_body = JSON.parse(bootstrap_response.body) - } catch (error) { - logging.error('get api bootstrap failed: ' + error) - throw ('getAPIBootstrap error ' + error) - } - - return bootstrap_body -} - -module.exports.getAPIBootstrap = getAPIBootstrap - -async function updateDoorbellMessage(camera, message) { - await authentication.authenticateifNeeded() - - const cameraPatchURL = utils.generateURL(API_CAMERA_PATCH) + camera.id - var resultBody = null - const patchJSON = { - lcdMessage: { - type: "CUSTOM_MESSAGE", - text: message - } - } - - logging.info('sending patch to url: ' + cameraPatchURL + ' patch: ' + JSON.stringify(patchJSON)) - try { - const response = await got.patch(cameraPatchURL, { - headers: { - ...authentication.cachedAuthHeaders() - }, - json: patchJSON - }) - - resultBody = JSON.parse(response.body) - } catch (error) { - logging.error('update patch failed: ' + error) - throw ('updateDoorbellMessage error ' + error) - } - - return resultBody -} - -module.exports.updateDoorbellMessage = updateDoorbellMessage \ No newline at end of file diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index 326b57f..0000000 --- a/lib/utils.js +++ /dev/null @@ -1,5 +0,0 @@ -const protectURL = process.env.PROTECT_URL - -module.exports.generateURL = function(suffix) { - return '' + protectURL + suffix -} \ No newline at end of file diff --git a/mqtt-unifi-protect-bridge.js b/mqtt-unifi-protect-bridge.js index d8fc60c..c1d2c7f 100644 --- a/mqtt-unifi-protect-bridge.js +++ b/mqtt-unifi-protect-bridge.js @@ -1,34 +1,25 @@ // Requirements -const mqtt = require('mqtt') -const _ = require('lodash') -const logging = require('homeautomation-js-lib/logging.js') -const health = require('homeautomation-js-lib/health.js') -const mqtt_helpers = require('homeautomation-js-lib/mqtt_helpers.js') -const got = require('got') -const interval = require('interval-promise') -const authentication = require('./lib/auth.js') -const protect = require('./lib/protect.js') -const utils = require('./lib/utils.js') -const username = process.env.USERNAME -const password = process.env.PASSWORD +import { ProtectApi } from "unifi-protect" +import util from "node:util" -var cachedBootstrap = null +import { default as mqtt } from "mqtt" +import { default as _ } from "lodash" +import { default as logging } from "homeautomation-js-lib/logging.js" +import { default as health } from "homeautomation-js-lib/health.js" +import { default as mqtt_helpers } from "homeautomation-js-lib/mqtt_helpers.js" -authentication.setAccount(username, password) +const username = process.env.USERNAME +const password = process.env.PASSWORD +const protectURL = process.env.PROTECT_URL +// TODO: Does this library handle this fully? var authenticate_poll_time = process.env.AUTH_POLL_FREQUENCY if (_.isNil(authenticate_poll_time)) { authenticate_poll_time = 60 * 60 } -var pollTime = process.env.POLL_FREQUENCY - -if (_.isNil(pollTime)) { - pollTime = 1 -} - var shouldRetain = process.env.MQTT_RETAIN if (_.isNil(shouldRetain)) { @@ -41,7 +32,7 @@ if (!_.isNil(shouldRetain)) { mqttOptions['retain'] = shouldRetain } -// Config +// // Config const baseTopic = process.env.TOPIC_PREFIX if (_.isNil(baseTopic)) { @@ -61,205 +52,98 @@ var disconnectedEvent = function () { } -// Setup MQTT +// // Setup MQTT var client = mqtt_helpers.setupClient(connectedEvent, disconnectedEvent) -var lastCameras = null - -// { -// "id": "6076012103001603e701eb8f", -// "type": "smartDetectZone", -// "start": 1618346270231, -// "end": 1618346277093, -// "score": 95, -// "smartDetectTypes": [ -// "person" -// ], -// "smartDetectEvents": [], -// "camera": "5ff5204001bcb603e7000408", -// "partition": null, -// "thumbnail": "e-6076012103001603e701eb8f", -// "heatmap": "e-6076012103001603e701eb8f", -// "modelKey": "event" -// }, +// Create a new Protect API instance. +const ufp = new ProtectApi() -// { -// "id": "6076003200bd1603e701eb74", -// "type": "ring", -// "start": 1618346034188, -// "end": 1618346035188, -// "score": 0, -// "smartDetectTypes": [], -// "smartDetectEvents": [], -// "camera": "5ff5204001bcb603e7000408", -// "partition": null, -// "thumbnail": "e-6076003200bd1603e701eb74", -// "heatmap": "e-6076003200bd1603e701eb74", -// "modelKey": "event" -// }, +// Set a listener to wait for the bootstrap event to occur. +ufp.once("bootstrap", (bootstrapJSON) => { + // Once we've bootstrapped the Protect controller, output the bootstrap JSON and we're done. + // process.stdout.write(util.inspect(bootstrapJSON, { colors: true, depth: null, sorted: true }) + "\n", () => process.exit(0)) +}); -// { -// "id": "6075430d00ae1603e701e401", -// "type": "motion", -// "start": 1618297610112, -// "end": 1618297615447, -// "score": 18, -// "smartDetectTypes": [], -// "smartDetectEvents": [], -// "camera": "5ff5204001deb603e7000409", -// "partition": null, -// "thumbnail": "e-6075430d00ae1603e701e401", -// "heatmap": "e-6075430d00ae1603e701e401", -// "modelKey": "event" -// }, +// Login to the Protect controller. +if (!(await ufp.login(protectURL, username, password))) { -async function pollEvents() { - try { - const events = await protect.getEvents(['ring', 'motion', 'smartDetectZone']) - logging.debug('events: ' + JSON.stringify(events)) + console.log("Invalid login credentials.") + process.exit(0) +}; - const now = new Date() - events.forEach(event => { - const id = event.id - const type = event.type - const start = event.start - const end = event.end - const score = event.score - const camera_id = event.camera - const smartDetectTypes = event.smartDetectTypes - var camera_name = id - const startTimeSinceNow = (now.getTime() - start) / 1000 - const threshold = (Number(pollTime) + 5) +// Bootstrap the controller. It will emit a message once it's received the bootstrap JSON, or you can alternatively wait for the promise to resolve. +if (!(await ufp.getBootstrap())) { - if (_.isNil(cachedBootstrap)) - return; - - const cameras = cachedBootstrap.cameras - cameras.forEach(camera_record => { - if (camera_record.id == camera_id) { - camera_name = camera_record.name.toLowerCase() - } - }) - - if (startTimeSinceNow < threshold) { - logging.info('** camera_name: ' + camera_name) - logging.info(' event type: ' + type) - logging.info(' threshold: ' + threshold) - logging.info(' start: ' + start) - logging.info(' now: ' + now.getTime()) - logging.info(' score: ' + score) - logging.info(' startTimeSinceNow: ' + startTimeSinceNow) - - if (!_.isNil(smartDetectTypes)) { - logging.info(' smart types: ' + JSON.stringify(smartDetectTypes)) - } - - if (type == 'smartDetectZone') { - smartDetectTypes.forEach(detected_type => { - client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, detected_type), '1', mqttOptions) + console.log("Unable to bootstrap the Protect controller.") + process.exit(0) +} - setTimeout(() => { - client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, detected_type), '0', mqttOptions) - }, (threshold * 1000 * 2)); - }); - } - } else { - // logging.info('** SKIPPING camera_name: ' + camera_name) - // logging.info(' event type: ' + type) - // logging.info(' threshold: ' + threshold) - // logging.info(' start: ' + start) - // logging.info(' now: ' + now.getTime()) - // logging.info(' score: ' + score) - // logging.info(' startTimeSinceNow: ' + startTimeSinceNow) +ufp.on("message", (packet) => { + const action = packet.header.action + const model = packet.header.modelKey + const payload = packet.payload + const id = packet.header.id + + const ring = payload.ring + const lastMotion = payload.lastMotion + const lastRing = payload.lastRing + const motion = payload.motion + const isSmartDetected = payload.isSmartDetected + const smartDetectZone = payload.smartDetectZone + const smartDetectTypes = payload.smartDetectTypes + + logging.debug("Action: " + action + " model: " + model) + if (model == "smartDetectObject" && 0 ) { // Disabled for now + var camera_name = null + const bootstrap = ufp.bootstrap + const cameras = bootstrap.cameras + cameras.forEach(camera_record => { + if (camera_record.id == id) { + camera_name = camera_record.name.toLowerCase() } }) - } catch (error) { - logging.error('Failed to poll bootstrap: ' + error) - } -} + const type = packet.body.type -async function pollBootstrap() { - try { - const body = await protect.getAPIBootstrap() - logging.debug('body: ' + JSON.stringify(body)) - const cameras = body.cameras - lastCameras = cameras - cachedBootstrap = body + logging.info("smart detect packet: " + JSON.stringify(packet)) + logging.info("camera: " + camera_name + " detected: " + type) +// if (type == 'smartDetectZone') { +// smartDetectTypes.forEach(detected_type => { +// client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, detected_type), '1', mqttOptions) - for (const camera of cameras) { - if (!_.isNil(camera.name)) { - const name = camera.name.toLowerCase() - const state = camera.state - const lastRing = camera.lastRing - const lastMotion = camera.lastMotion - const isMotionDetected = camera.isMotionDetected - const now = new Date() - logging.debug('** camera: ' + JSON.stringify(camera)) +// setTimeout(() => { +// client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, detected_type), '0', mqttOptions) +// }, (threshold * 1000 * 2)); +// }); +// } - if (!_.isNil(lastRing)) { - logging.debug('** camera ring:') - logging.debug(' lastRing: ' + lastRing) - const ringDate = new Date(lastRing) - logging.debug(' ringDate: ' + ringDate) - const ringTimeDifferenceSeconds = (now - lastRing) / 1000 - logging.debug(' ringTimeDifferenceSeconds: ' + ringTimeDifferenceSeconds) - - const recentRing = (ringTimeDifferenceSeconds < pollTime * 3) ? 1 : 0 - client.smartPublish(mqtt_helpers.generateTopic(baseTopic, name, 'ringing'), recentRing ? '1' : '0', mqttOptions) - } - - client.smartPublish(mqtt_helpers.generateTopic(baseTopic, name, 'state'), mqtt_helpers.generateTopic(state), mqttOptions) - client.smartPublish(mqtt_helpers.generateTopic(baseTopic, name), isMotionDetected ? '1' : '0', mqttOptions) - } - } - } catch (error) { - logging.error('Failed to poll bootstrap: ' + error) } -} - -const startWatching = function () { - logging.info('starting poll') - - interval(async () => { - try { - pollBootstrap() - pollEvents() - } catch (error) { - logging.error('error polling: ' + error) - } - }, pollTime * 1000) - - interval(async () => { - logging.info(' => polling auth') - await authentication.authenticate() - }, authenticate_poll_time * 1000) -} - - -client.on('message', (topic, message) => { - logging.info(' => ' + topic + ':' + message) - const components = topic.split('/') - const name = components[components.length - 3] - const command = components[components.length - 2] - switch (command) { - case 'message': - if (!_.isNil(lastCameras)) { - logging.info('Looking for camera name: ' + name) - - for (const camera of lastCameras) { - const camera_name = mqtt_helpers.generateTopic(camera.name).toLowerCase() - - if (name == camera_name) - protect.updateDoorbellMessage(camera, message.toString()) - } + if (model == "camera") { + var camera_name = null + const bootstrap = ufp.bootstrap + const cameras = bootstrap.cameras + cameras.forEach(camera_record => { + if (camera_record.id == id) { + camera_name = camera_record.name.toLowerCase() } + }) - break - default: - logging.warn('Unhandled command: ' + command) - break - + logging.debug("Action: " + action + " model: " + model) + logging.debug("id: " + id) + logging.debug("name: " + camera_name) + logging.debug("lastMotion: " + lastMotion) + logging.debug("ring: " + ring) + logging.debug("lastRing: " + lastRing) + logging.debug("isSmartDetected: " + isSmartDetected) + logging.debug("motion: " + motion) + logging.debug("smartDetectZone: " + smartDetectZone) + logging.debug("smartDetectZone: " + smartDetectTypes) + + const isMotionDetected = isSmartDetected || lastMotion + client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name), isMotionDetected ? '1' : '0', mqttOptions) + + // TODO: Check to see if the device supports ringing before publishing this + client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, 'ringing'), lastRing ? '1' : '0', mqttOptions) + // TODO: this should be offline/online + // client.smartPublish(mqtt_helpers.generateTopic(baseTopic, camera_name, 'state'), mqtt_helpers.generateTopic(state), mqttOptions) } -}) - -startWatching() \ No newline at end of file +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3b8f717..f09bca4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,71 +9,45 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "got": "11.8.5", "homeautomation-js-lib": "https://github.com/terafin/homeautomation-js-lib.git", - "interval-promise": "latest", "lodash": "latest", - "mqtt": "latest" + "mqtt": "latest", + "unifi-protect": "latest" }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@babel/runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", - "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "node_modules/@adobe/fetch": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@adobe/fetch/-/fetch-4.1.9.tgz", + "integrity": "sha512-FWIzm4vvl1OtCarTBgWDW6otj4gxrNmMf/DdriqBUw7DjjmckjT3ZQA43b4HzBkzkuAHhajwMy91btp9fWgTEw==", "dependencies": { - "regenerator-runtime": "^0.14.0" + "debug": "4.3.7", + "http-cache-semantics": "4.1.1", + "lru-cache": "7.18.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.16" } }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "node_modules/@adobe/fetch/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "node": ">=12" } }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "node_modules/@babel/runtime": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "dependencies": { - "defer-to-connect": "^2.0.0" + "regenerator-runtime": "^0.14.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dependencies": { - "@types/node": "*" + "node": ">=6.9.0" } }, "node_modules/@types/node": { @@ -93,14 +67,6 @@ "safe-buffer": "~5.1.1" } }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/ws": { "version": "8.5.12", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", @@ -183,29 +149,17 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "optional": true, "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" + "node-gyp-build": "^4.3.0" }, "engines": { - "node": ">=8" + "node": ">=6.14.2" } }, "node_modules/call-bind": { @@ -240,17 +194,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/commist": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", @@ -307,39 +250,6 @@ } } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "engines": { - "node": ">=10" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -356,14 +266,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -455,20 +357,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -480,30 +368,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -589,18 +453,6 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -625,11 +477,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/interval-promise": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interval-promise/-/interval-promise-1.4.0.tgz", - "integrity": "sha512-PUwEmGqUglJhb6M01JNvMDvxr4DA8FCeYoYCLHPEcBBZiq/8yOpCchfs1VJui7fXj69l170gAxzF1FeSA0nSlg==" - }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -650,11 +497,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -663,14 +505,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -691,27 +525,11 @@ "node": ">=8.0" } }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "engines": { - "node": ">=8" - } - }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -766,15 +584,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, "node_modules/number-allocator": { @@ -797,22 +615,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "engines": { - "node": ">=8" - } - }, "node_modules/path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -835,15 +637,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -863,17 +656,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -911,22 +693,6 @@ "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -1033,6 +799,24 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, + "node_modules/unifi-protect": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/unifi-protect/-/unifi-protect-4.16.0.tgz", + "integrity": "sha512-M8/VUTKhPxlzagIQdpjvXbdUPp4a/3F051CghaLXWT9JfnVuJZGLYC3U1zYOXtKVIfqP+KcTmn6sSTawHTGADQ==", + "dependencies": { + "@adobe/fetch": "4.1.9", + "ws": "8.18.0" + }, + "bin": { + "ufp": "dist/util/ufp.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "bufferutil": "4.0.8" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -1102,11 +886,6 @@ "tslib": "^2.6.2" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", @@ -1129,6 +908,23 @@ } }, "dependencies": { + "@adobe/fetch": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@adobe/fetch/-/fetch-4.1.9.tgz", + "integrity": "sha512-FWIzm4vvl1OtCarTBgWDW6otj4gxrNmMf/DdriqBUw7DjjmckjT3ZQA43b4HzBkzkuAHhajwMy91btp9fWgTEw==", + "requires": { + "debug": "4.3.7", + "http-cache-semantics": "4.1.1", + "lru-cache": "7.18.3" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, "@babel/runtime": { "version": "7.25.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", @@ -1137,43 +933,6 @@ "regenerator-runtime": "^0.14.0" } }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" - }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "requires": { - "@types/node": "*" - } - }, "@types/node": { "version": "22.7.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", @@ -1191,14 +950,6 @@ "safe-buffer": "~5.1.1" } }, - "@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "requires": { - "@types/node": "*" - } - }, "@types/ws": { "version": "8.5.12", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", @@ -1250,23 +1001,13 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" - }, - "cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "optional": true, "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" + "node-gyp-build": "^4.3.0" } }, "call-bind": { @@ -1289,14 +1030,6 @@ "readdirp": "^4.0.1" } }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "requires": { - "mimic-response": "^1.0.0" - } - }, "commist": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz", @@ -1338,26 +1071,6 @@ "ms": "^2.1.3" } }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" - } - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" - }, "define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -1368,14 +1081,6 @@ "gopd": "^1.0.1" } }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, "es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -1440,14 +1145,6 @@ "hasown": "^2.0.0" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -1456,24 +1153,6 @@ "get-intrinsic": "^1.1.3" } }, - "got": { - "version": "11.8.5", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", - "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1534,15 +1213,6 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -1553,11 +1223,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "interval-promise": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interval-promise/-/interval-promise-1.4.0.tgz", - "integrity": "sha512-PUwEmGqUglJhb6M01JNvMDvxr4DA8FCeYoYCLHPEcBBZiq/8yOpCchfs1VJui7fXj69l170gAxzF1FeSA0nSlg==" - }, "js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", @@ -1571,11 +1236,6 @@ "argparse": "^2.0.1" } }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -1584,14 +1244,6 @@ "graceful-fs": "^4.1.6" } }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "requires": { - "json-buffer": "3.0.1" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1609,21 +1261,11 @@ "streamroller": "^3.1.5" } }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - }, "lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1667,10 +1309,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + "node-gyp-build": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "optional": true }, "number-allocator": { "version": "1.0.14", @@ -1686,19 +1329,6 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" - }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -1718,15 +1348,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -1740,11 +1361,6 @@ "side-channel": "^1.0.6" } }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" - }, "readable-stream": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", @@ -1772,19 +1388,6 @@ "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==" }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" - }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "requires": { - "lowercase-keys": "^2.0.0" - } - }, "rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -1864,6 +1467,16 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, + "unifi-protect": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/unifi-protect/-/unifi-protect-4.16.0.tgz", + "integrity": "sha512-M8/VUTKhPxlzagIQdpjvXbdUPp4a/3F051CghaLXWT9JfnVuJZGLYC3U1zYOXtKVIfqP+KcTmn6sSTawHTGADQ==", + "requires": { + "@adobe/fetch": "4.1.9", + "bufferutil": "4.0.8", + "ws": "8.18.0" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -1929,11 +1542,6 @@ "tslib": "^2.6.2" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, "ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", diff --git a/package.json b/package.json index 0bbab95..4fa448d 100644 --- a/package.json +++ b/package.json @@ -3,21 +3,21 @@ "version": "0.0.1", "description": "Bridge Unifi Protect HTTP to MQTT", "license": "MIT", - "main": "mqtt-unifi-protect-bridge.js", + "exports": "./mqtt-unifi-protect-bridge.js", "repository": { "url": "https://github.com/terafin/mqtt-unifi-protect-bridge" }, + "type": "module", "scripts": { "start": "node mqtt-unifi-protect-bridge.js" }, "dependencies": { "homeautomation-js-lib": "https://github.com/terafin/homeautomation-js-lib.git", "lodash": "latest", - "mqtt": "latest", - "interval-promise": "latest", - "got": "11.8.5" + "unifi-protect": "latest", + "mqtt": "latest" }, "engines": { - "node": ">=10" + "node": ">=18" } } \ No newline at end of file