diff --git a/README.md b/README.md index 32d723b..2bddaa6 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,11 @@ The following is supported from this package: - End-to-end encryption - [Currently a WIP](#end-to-end-encryption-notes) + - Can also use [pantalaimon](https://github.com/matrix-org/pantalaimon) as an alternative solution to E2EE (if you need multiple sessions synced up with keys) - Receive events from a room (messages, reactions, images, audio, locations, and files) whether encrypted or not - Send Images/Files (sending files to e2ee room doesn't currently encrypt them yet) - Edit messages +- Send typing events (Bot is typing ...) - Delete events (messages, reactions, etc) - Decrypt files in e2ee rooms - Send HTML/Plain Text Message/Notice diff --git a/examples/README.md b/examples/README.md index 5eaf8cf..9385a2e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -24,6 +24,7 @@ Build something cool with these nodes? Feel free to submit a pull request to sha - [Respond to "rooms " with user's rooms (list server's rooms if is left blank)](#respond-to-rooms-user_id-with-users-rooms-list-servers-rooms-if-user_id-is-left-blank) - [Respond to "whois " with information about the user's session](#respond-to-whois-user_id-with-information-about-the-users-session) - [Respond to "room_users" with current room's users](#respond-to-room_users-with-current-rooms-users) +- [Sending typing events to a room](#sending-typing-events-to-a-room) - [Download & store all received files/images](#download--store-all-received-filesimages) - [Kick/Ban user from room](#kickban-user-from-room) - [Deactivate user](#deactivate-user) @@ -221,6 +222,15 @@ Note: You may need to edit the storage directory for this to work. Default actio ![store-received-files.png](store-received-files.png) +### Sending typing events to a room + +[View JSON](send-typing-events.json) + +You can tell a room that Node-RED is writing a message and also cancel the writing event. This can be useful for making bots feel more interactive (show typing while requesting API endpoint for example). + +![store-received-files.png](send-typing-events.png) + + ### Kick/Ban user from room [View JSON](room-kick-ban.json) diff --git a/examples/send-typing-events.json b/examples/send-typing-events.json new file mode 100644 index 0000000..e73f7b7 --- /dev/null +++ b/examples/send-typing-events.json @@ -0,0 +1,127 @@ +[ + { + "id": "541dbfc3f04220cf", + "type": "matrix-typing", + "z": "f025a8b9fbd1b054", + "name": "", + "server": null, + "roomType": "msg", + "roomValue": "topic", + "typingType": "msg", + "typingValue": "typing", + "timeoutMsType": "num", + "timeoutMsValue": "20000", + "x": 1090, + "y": 220, + "wires": [ + [ + "febf8236f3683963" + ], + [ + "9db9819ebb6343c8" + ] + ] + }, + { + "id": "d7c3714c657bfe4f", + "type": "inject", + "z": "f025a8b9fbd1b054", + "name": "Start Typing", + "props": [ + { + "p": "topic", + "vt": "str" + }, + { + "p": "typing", + "v": "true", + "vt": "bool" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "!mohVKgDFYUubJQHcuX:skylar.tech", + "x": 910, + "y": 200, + "wires": [ + [ + "541dbfc3f04220cf" + ] + ] + }, + { + "id": "783121ff1a6bd833", + "type": "inject", + "z": "f025a8b9fbd1b054", + "name": "Stop Typing", + "props": [ + { + "p": "topic", + "vt": "str" + }, + { + "p": "typing", + "v": "false", + "vt": "bool" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "!mohVKgDFYUubJQHcuX:skylar.tech", + "x": 910, + "y": 240, + "wires": [ + [ + "541dbfc3f04220cf" + ] + ] + }, + { + "id": "9db9819ebb6343c8", + "type": "debug", + "z": "f025a8b9fbd1b054", + "name": "Failure msg", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1270, + "y": 240, + "wires": [] + }, + { + "id": "febf8236f3683963", + "type": "debug", + "z": "f025a8b9fbd1b054", + "name": "Success msg", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 1270, + "y": 200, + "wires": [] + }, + { + "id": "01e8c4c6303af390", + "type": "comment", + "z": "f025a8b9fbd1b054", + "name": "Send typing events to a room", + "info": "", + "x": 940, + "y": 160, + "wires": [] + } +] \ No newline at end of file diff --git a/examples/send-typing-events.png b/examples/send-typing-events.png new file mode 100644 index 0000000..703bc2d Binary files /dev/null and b/examples/send-typing-events.png differ diff --git a/package-lock.json b/package-lock.json index 337704d..ef3a926 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,28 @@ { "name": "node-red-contrib-matrix-chat", - "version": "0.7.0", + "version": "0.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "node-red-contrib-matrix-chat", - "version": "0.7.0", + "version": "0.8.0", "license": "SEE LICENSE FILE", "dependencies": { "abort-controller": "^3.0.0", + "fluent-ffmpeg": "^2.1.2", "fs-extra": "^11.1.0", "got": "^12.0.2", + "image-size": "^1.0.2", "isomorphic-webcrypto": "^2.3.8", "matrix-js-sdk": "^28.0.0", + "mime": "^3.0.0", "node-fetch": "^3.3.0", "node-localstorage": "^2.2.1", "olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/2572/download", "request": "^2.88.2", + "sharp": "^0.33.4", + "tmp": "^0.2.1", "utf8": "^3.0.0" }, "engines": { @@ -2640,6 +2645,15 @@ "node": ">=6.9.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@expo/bunyan": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz", @@ -3107,6 +3121,19 @@ "ms": "^2.1.1" } }, + "node_modules/@expo/devcert/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "optional": true, + "peer": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/@expo/env": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.0.5.tgz", @@ -3167,6 +3194,19 @@ "node": ">=10" } }, + "node_modules/@expo/image-utils/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/@expo/image-utils/node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -3492,6 +3532,437 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.31", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.1.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@jest/create-cache-key-function": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.6.3.tgz", @@ -4992,6 +5463,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@react-native-community/cli-tools/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/@react-native-community/cli-tools/node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -5909,9 +6393,7 @@ "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "optional": true, - "peer": true + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "node_modules/async-limiter": { "version": "1.0.1", @@ -6168,9 +6650,7 @@ "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==", - "optional": true, - "peer": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base-64": { "version": "0.1.0", @@ -6336,8 +6816,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6814,11 +7292,22 @@ "node": ">=6" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -6829,8 +7318,16 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "node_modules/colorette": { "version": "1.4.0", @@ -6948,9 +7445,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true, - "peer": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/connect": { "version": "3.7.0", @@ -8137,6 +8632,18 @@ "node": ">=0.4.0" } }, + "node_modules/fluent-ffmpeg": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz", + "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==", + "dependencies": { + "async": ">=0.2.9", + "which": "^1.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fontfaceobserver": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", @@ -8235,9 +8742,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true, - "peer": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.3", @@ -8339,8 +8844,6 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "optional": true, - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -8716,8 +9219,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "optional": true, - "peer": true, "dependencies": { "queue": "6.0.2" }, @@ -8781,8 +9282,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -8791,9 +9290,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "optional": true, - "peer": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", @@ -9098,9 +9595,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "optional": true, - "peer": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -11453,16 +11948,14 @@ } }, "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "optional": true, - "peer": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "bin": { "mime": "cli.js" }, "engines": { - "node": ">=4.0.0" + "node": ">=10.0.0" } }, "node_modules/mime-db": { @@ -11509,8 +12002,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "optional": true, - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -12022,8 +12513,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "optional": true, - "peer": true, "dependencies": { "wrappy": "1" } @@ -12404,8 +12893,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -12886,8 +13373,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "optional": true, - "peer": true, "dependencies": { "inherits": "~2.0.3" } @@ -13543,14 +14028,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -13558,26 +14038,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -13729,6 +14189,53 @@ "node": ">=8" } }, + "node_modules/sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + }, + "engines": { + "libvips": ">=8.15.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -13809,6 +14316,19 @@ "node": ">= 5.10.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -14478,16 +14998,28 @@ } }, "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "optional": true, - "peer": true, + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dependencies": { - "os-tmpdir": "~1.0.2" + "rimraf": "^3.0.0" }, "engines": { - "node": ">=0.6.0" + "node": ">=8.17.0" + } + }, + "node_modules/tmp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tmpl": { @@ -15002,8 +15534,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "optional": true, - "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -15059,9 +15589,7 @@ "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==", - "optional": true, - "peer": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "2.4.3", @@ -17114,6 +17642,15 @@ "to-fast-properties": "^2.0.0" } }, + "@emnapi/runtime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.2.0.tgz", + "integrity": "sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@expo/bunyan": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz", @@ -17519,6 +18056,16 @@ "requires": { "ms": "^2.1.1" } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "optional": true, + "peer": true, + "requires": { + "os-tmpdir": "~1.0.2" + } } } }, @@ -17576,6 +18123,13 @@ "universalify": "^1.0.0" } }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "optional": true, + "peer": true + }, "node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -17846,6 +18400,147 @@ "@hapi/hoek": "^9.0.0" } }, + "@img/sharp-darwin-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-arm64": "1.0.2" + } + }, + "@img/sharp-darwin-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-x64": "1.0.2" + } + }, + "@img/sharp-libvips-darwin-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "optional": true + }, + "@img/sharp-libvips-darwin-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", + "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "optional": true + }, + "@img/sharp-libvips-linux-arm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", + "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "optional": true + }, + "@img/sharp-libvips-linux-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", + "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "optional": true + }, + "@img/sharp-libvips-linux-s390x": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", + "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "optional": true + }, + "@img/sharp-libvips-linux-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", + "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", + "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", + "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "optional": true + }, + "@img/sharp-linux-arm": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm": "1.0.2" + } + }, + "@img/sharp-linux-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm64": "1.0.2" + } + }, + "@img/sharp-linux-s390x": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-s390x": "1.0.2" + } + }, + "@img/sharp-linux-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-x64": "1.0.2" + } + }, + "@img/sharp-linuxmusl-arm64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + } + }, + "@img/sharp-linuxmusl-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + } + }, + "@img/sharp-wasm32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "optional": true, + "requires": { + "@emnapi/runtime": "^1.1.1" + } + }, + "@img/sharp-win32-ia32": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "optional": true + }, + "@img/sharp-win32-x64": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "optional": true + }, "@jest/create-cache-key-function": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.6.3.tgz", @@ -19191,6 +19886,13 @@ "is-unicode-supported": "^0.1.0" } }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "optional": true, + "peer": true + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -19753,9 +20455,7 @@ "async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "optional": true, - "peer": true + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" }, "async-limiter": { "version": "1.0.1", @@ -19981,9 +20681,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "optional": true, - "peer": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base-64": { "version": "0.1.0", @@ -20123,8 +20821,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "peer": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -20464,11 +21160,19 @@ "shallow-clone": "^3.0.0" } }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, "requires": { "color-name": "~1.1.4" } @@ -20476,8 +21180,16 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "colorette": { "version": "1.4.0", @@ -20582,9 +21294,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true, - "peer": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "connect": { "version": "3.7.0", @@ -21524,6 +22234,15 @@ "optional": true, "peer": true }, + "fluent-ffmpeg": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz", + "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==", + "requires": { + "async": ">=0.2.9", + "which": "^1.1.1" + } + }, "fontfaceobserver": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", @@ -21598,9 +22317,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true, - "peer": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.3", @@ -21674,8 +22391,6 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "optional": true, - "peer": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -21949,8 +22664,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", - "optional": true, - "peer": true, "requires": { "queue": "6.0.2" } @@ -21998,8 +22711,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "peer": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -22008,9 +22719,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "optional": true, - "peer": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.8", @@ -22242,9 +22951,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "optional": true, - "peer": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isobject": { "version": "3.0.1", @@ -24103,11 +24810,9 @@ } }, "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "optional": true, - "peer": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" }, "mime-db": { "version": "1.52.0", @@ -24138,8 +24843,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "optional": true, - "peer": true, "requires": { "brace-expansion": "^1.1.7" } @@ -24532,8 +25235,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "optional": true, - "peer": true, "requires": { "wrappy": "1" } @@ -24824,9 +25525,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true, - "peer": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "2.0.1", @@ -25193,8 +25892,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "optional": true, - "peer": true, "requires": { "inherits": "~2.0.3" } @@ -25716,33 +26413,9 @@ "integrity": "sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, - "peer": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "peer": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true, - "peer": true - } - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" }, "send": { "version": "0.18.0", @@ -25871,6 +26544,42 @@ "kind-of": "^6.0.2" } }, + "sharp": { + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "requires": { + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", + "@img/sharp-libvips-darwin-arm64": "1.0.2", + "@img/sharp-libvips-darwin-x64": "1.0.2", + "@img/sharp-libvips-linux-arm": "1.0.2", + "@img/sharp-libvips-linux-arm64": "1.0.2", + "@img/sharp-libvips-linux-s390x": "1.0.2", + "@img/sharp-libvips-linux-x64": "1.0.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", + "@img/sharp-libvips-linuxmusl-x64": "1.0.2", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4", + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.0" + }, + "dependencies": { + "detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==" + } + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -25938,6 +26647,21 @@ } } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -26474,13 +27198,21 @@ } }, "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "optional": true, - "peer": true, + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "requires": { - "os-tmpdir": "~1.0.2" + "rimraf": "^3.0.0" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } } }, "tmpl": { @@ -26887,8 +27619,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "optional": true, - "peer": true, "requires": { "isexe": "^2.0.0" } @@ -26934,9 +27664,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "optional": true, - "peer": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "2.4.3", diff --git a/package.json b/package.json index 6aeb583..54afa7c 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,22 @@ { "name": "node-red-contrib-matrix-chat", - "version": "0.7.1", + "version": "0.8.0", "description": "Matrix chat server client for Node-RED", "dependencies": { "abort-controller": "^3.0.0", + "fluent-ffmpeg": "^2.1.2", "fs-extra": "^11.1.0", "got": "^12.0.2", + "image-size": "^1.0.2", "isomorphic-webcrypto": "^2.3.8", "matrix-js-sdk": "^28.0.0", + "mime": "^3.0.0", "node-fetch": "^3.3.0", "node-localstorage": "^2.2.1", "olm": "https://gitlab.matrix.org/matrix-org/olm/-/package_files/2572/download", "request": "^2.88.2", + "sharp": "^0.33.4", + "tmp": "^0.2.1", "utf8": "^3.0.0" }, "node-red": { @@ -20,10 +25,15 @@ "matrix-server-config": "src/matrix-server-config.js", "matrix-receive": "src/matrix-receive.js", "matrix-send-message": "src/matrix-send-message.js", + "matrix-typing": "src/matrix-typing.js", + "matrix-mark-read": "src/matrix-mark-read.js", "matrix-delete-event": "src/matrix-delete-event.js", "matrix-send-file": "src/matrix-send-file.js", "matrix-send-image": "src/matrix-send-image.js", + "matrix-upload-file": "src/matrix-upload-file.js", "matrix-react": "src/matrix-react.js", + "matrix-user-settings": "src/matrix-user-settings.js", + "matrix-get-user": "src/matrix-get-user.js", "matrix-create-room": "src/matrix-create-room.js", "matrix-invite-room": "src/matrix-invite-room.js", "matrix-room-invite": "src/matrix-room-invite.js", @@ -32,13 +42,15 @@ "matrix-crypt-file": "src/matrix-crypt-file.js", "matrix-room-kick": "src/matrix-room-kick.js", "matrix-room-ban": "src/matrix-room-ban.js", + "matrix-room-users": "src/matrix-room-users.js", + "matrix-room-state-events": "src/matrix-room-state-events.js", "matrix-synapse-users": "src/matrix-synapse-users.js", "matrix-synapse-register": "src/matrix-synapse-register.js", "matrix-synapse-create-edit-user": "src/matrix-synapse-create-edit-user.js", "matrix-synapse-deactivate-user": "src/matrix-synapse-deactivate-user.js", "matrix-synapse-join-room": "src/matrix-synapse-join-room.js", "matrix-whois-user": "src/matrix-whois-user.js", - "matrix-room-users": "src/matrix-room-users.js" + "matrix-paginate-room": "src/matrix-paginate-room.js" } }, "engines": { diff --git a/src/icons/matrix.png b/src/icons/matrix.png index eea69f5..a97ff11 100644 Binary files a/src/icons/matrix.png and b/src/icons/matrix.png differ diff --git a/src/matrix-create-room.html b/src/matrix-create-room.html index d57ae59..ee7926d 100644 --- a/src/matrix-create-room.html +++ b/src/matrix-create-room.html @@ -8,7 +8,7 @@ outputs: 2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" } + server: { type: "matrix-server-config" } }, label: function() { return this.name || "Create Room"; diff --git a/src/matrix-create-room.js b/src/matrix-create-room.js index d60d2b3..7ff02b4 100644 --- a/src/matrix-create-room.js +++ b/src/matrix-create-room.js @@ -8,9 +8,10 @@ module.exports = function(RED) { this.server = RED.nodes.getNode(n.server); if(!this.server) { - node.error('Server must be configured on the node.'); + node.error('Server must be configured on the node.', {}); return; } + node.server.register(node); this.encodeUri = function(pathTemplate, variables) { for (const key in variables) { @@ -41,8 +42,9 @@ module.exports = function(RED) { } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } if(!msg.payload) { @@ -64,6 +66,10 @@ module.exports = function(RED) { node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-create-room", MatrixCreateRoom); } \ No newline at end of file diff --git a/src/matrix-crypt-file.js b/src/matrix-crypt-file.js index e58086d..779a1c8 100644 --- a/src/matrix-crypt-file.js +++ b/src/matrix-crypt-file.js @@ -12,22 +12,22 @@ module.exports = function(RED) { const { got } = await import('got'); if(!msg.type) { - node.error('msg.type is required.'); + node.error('msg.type is required.', msg); return; } if(!msg.content) { - node.error('msg.content is required.'); + node.error('msg.content is required.', msg); return; } if(!msg.content.file) { - node.error('msg.content.file is required.'); + node.error('msg.content.file is required.', msg); return; } if(!msg.url) { - node.error('msg.url is required.'); + node.error('msg.url is required.', msg); return; } diff --git a/src/matrix-delete-event.html b/src/matrix-delete-event.html index 899ac22..acbff0e 100644 --- a/src/matrix-delete-event.html +++ b/src/matrix-delete-event.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, reason: { value: "" }, }, diff --git a/src/matrix-delete-event.js b/src/matrix-delete-event.js index cbb40d2..132ba16 100644 --- a/src/matrix-delete-event.js +++ b/src/matrix-delete-event.js @@ -13,6 +13,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -27,7 +28,7 @@ module.exports = function(RED) { node.on('input', function(msg) { if(!msg.eventId) { - node.error("eventId is missing"); + node.error("eventId is missing", msg); node.send([null, msg]) return; } @@ -38,7 +39,7 @@ module.exports = function(RED) { } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); return; } @@ -70,6 +71,10 @@ module.exports = function(RED) { node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-delete-event",MatrixDeleteEvent); } diff --git a/src/matrix-file-crypt.js b/src/matrix-file-crypt.js new file mode 100644 index 0000000..e69de29 diff --git a/src/matrix-get-user.html b/src/matrix-get-user.html new file mode 100644 index 0000000..705a50a --- /dev/null +++ b/src/matrix-get-user.html @@ -0,0 +1,352 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-get-user.js b/src/matrix-get-user.js new file mode 100644 index 0000000..9afa8fc --- /dev/null +++ b/src/matrix-get-user.js @@ -0,0 +1,145 @@ +module.exports = function(RED) { + function MatrixGetUser(n) { + RED.nodes.createNode(this, n); + + var node = this; + + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.userType = n.userType || "msg"; + this.userValue = n.userValue || "userId"; + this.propertyType = n.propertyType || "msg"; + this.propertyValue = n.propertyValue || "user"; + + if (!node.server) { + node.warn("No configuration node"); + return; + } + node.server.register(node); + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.on("input", async function (msg) { + + function getToValue(msg, type, property) { + let value = property; + if (type === "msg") { + value = RED.util.getMessageProperty(msg, property); + } else if ((type === 'flow') || (type === 'global')) { + try { + value = RED.util.evaluateNodeProperty(property, type, node, msg); + } catch(e2) { + throw new Error("Invalid value evaluation"); + } + } else if(type === "bool") { + value = (property === 'true'); + } else if(type === "num") { + value = Number(property); + } + return value; + } + + function setToValue(value, type, property) { + if(type === 'global' || type === 'flow') { + var contextKey = RED.util.parseContextStore(property); + if (/\[msg/.test(contextKey.key)) { + // The key has a nest msg. reference to evaluate first + contextKey.key = RED.util.normalisePropertyExpression(contextKey.key, msg, true) + } + var target = node.context()[type]; + var callback = err => { + if (err) { + node.error(err, msg); + getterErrors[rule.p] = err.message; + } + } + target.set(contextKey.key, value, contextKey.store, callback); + } else if(type === 'msg') { + if (!RED.util.setMessageProperty(msg, property, value)) { + node.warn(RED._("change.errors.no-override",{property:property})); + } + } + } + + if (! node.server || ! node.server.matrixClient) { + msg.error = "No matrix server selected"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + if(!node.server.isConnected()) { + msg.error = "Matrix server connection is currently closed"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + let userId = getToValue(msg, node.userType, node.userValue); + if(!userId) { + msg.error = "Missing userId"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + let user = null; + try { + user = node.server.matrixClient.getUser(userId); + } catch(e) { + msg.error = "Failed getting user: " + e.message; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + if(!user) { + // failed to fetch from local storage, try to fetch data from server + let user2 = {}; + + try { + let profileInfo = node.server.matrixClient.getProfileInfo(userId); + if(Object.keys(profileInfo).length > 0) { + user2.displayName = profileInfo.displayname; + user2.avatarUrl = profileInfo.avatar_url; + } + + let presence = node.server.matrixClient.getPresence(userId); + if(Object.keys(presence).length > 0) { + user2.currentlyActive = presence.currently_active; + user2.lastActiveAgo = presence.last_active_ago; + user2.presenceStatusMsg = presence.presence_status_msg; + user2.presence = presence.presence; + } + + if(Object.keys(user2).length > 0) { + setToValue(user2, node.propertyType, node.propertyValue); + node.send([msg, null]); + return; + } + } catch(e) { + msg.error = "Failed getting user: " + e.message; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + } + + setToValue(user, node.propertyType, node.propertyValue); + node.send([msg, null]); + }); + + node.on("close", function() { + node.server.deregister(node); + }); + } + RED.nodes.registerType("matrix-get-user", MatrixGetUser); +} \ No newline at end of file diff --git a/src/matrix-invite-room.html b/src/matrix-invite-room.html index 20f49d1..dd5cb0d 100644 --- a/src/matrix-invite-room.html +++ b/src/matrix-invite-room.html @@ -8,7 +8,7 @@ outputs: 2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, }, label: function() { diff --git a/src/matrix-invite-room.js b/src/matrix-invite-room.js index 334cb0c..61c7589 100644 --- a/src/matrix-invite-room.js +++ b/src/matrix-invite-room.js @@ -9,9 +9,10 @@ module.exports = function(RED) { this.roomId = n.roomId; if(!this.server) { - node.error('Server must be configured on the node.'); + node.error('Server must be configured on the node.', {}); return; } + node.server.register(node); this.encodeUri = function(pathTemplate, variables) { for (const key in variables) { @@ -37,18 +38,19 @@ module.exports = function(RED) { node.on("input", function (msg) { if (! node.server || ! node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } msg.topic = node.roomId || msg.topic; if(!msg.topic) { - node.error("room must be defined in either msg.topic or in node config"); + node.error("room must be defined in either msg.topic or in node config", msg); return; } @@ -64,6 +66,10 @@ module.exports = function(RED) { node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-invite-room", MatrixInviteRoom); } \ No newline at end of file diff --git a/src/matrix-join-room.html b/src/matrix-join-room.html index c3c75f5..81e403e 100644 --- a/src/matrix-join-room.html +++ b/src/matrix-join-room.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" } + server: { type: "matrix-server-config" } }, label: function() { return this.name || "Join Room"; diff --git a/src/matrix-join-room.js b/src/matrix-join-room.js index bee81fd..61d54fc 100644 --- a/src/matrix-join-room.js +++ b/src/matrix-join-room.js @@ -11,6 +11,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -24,17 +25,18 @@ module.exports = function(RED) { node.on("input", function (msg) { if (! node.server || ! node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } if(!msg.topic) { - node.error("Room must be specified in msg.topic"); + node.error("Room must be specified in msg.topic", msg); return; } @@ -46,11 +48,15 @@ module.exports = function(RED) { node.send([msg, null]); }) .catch(function(e){ - node.error("Error trying to join room " + msg.topic + ":" + e); + node.error("Error trying to join room " + msg.topic + ":" + e, msg); msg.error = e; node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-join-room", MatrixJoinRoom); } \ No newline at end of file diff --git a/src/matrix-leave-room.html b/src/matrix-leave-room.html index 4795c66..7b14b68 100644 --- a/src/matrix-leave-room.html +++ b/src/matrix-leave-room.html @@ -8,7 +8,7 @@ outputs: 2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, }, label: function() { diff --git a/src/matrix-leave-room.js b/src/matrix-leave-room.js index f69877d..b46f8d7 100644 --- a/src/matrix-leave-room.js +++ b/src/matrix-leave-room.js @@ -11,9 +11,10 @@ module.exports = function(RED) { node.status({ fill: "red", shape: "ring", text: "disconnected" }); if (!node.server) { - node.error("No configuration node"); + node.error("No configuration node", {}); return; } + node.server.register(node); node.server.on("disconnected", function(){ node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -25,30 +26,36 @@ module.exports = function(RED) { node.on('input', function(msg) { if (! node.server || ! node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!msg.topic) { - node.error('No room provided in msg.topic'); + node.error('No room provided in msg.topic', msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } try { node.log("Leaving room " + msg.topic); node.server.matrixClient.leave(msg.topic); + node.server.matrixClient.store.removeRoom(msg.topic); node.send([msg, null]); } catch(e) { - node.error("Failed to leave room " + msg.topic + ": " + e); + node.error("Failed to leave room " + msg.topic + ": " + e, msg); msg.payload = e; node.send([null, msg]); } }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-leave-room", MatrixLeaveRoom); } \ No newline at end of file diff --git a/src/matrix-mark-read.html b/src/matrix-mark-read.html new file mode 100644 index 0000000..e74f899 --- /dev/null +++ b/src/matrix-mark-read.html @@ -0,0 +1,254 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-mark-read.js b/src/matrix-mark-read.js new file mode 100644 index 0000000..f9559ca --- /dev/null +++ b/src/matrix-mark-read.js @@ -0,0 +1,73 @@ +const {TimelineWindow, RelationType, Filter} = require("matrix-js-sdk"); +const crypto = require('crypto'); +module.exports = function(RED) { + function MatrixReceiveMessage(n) { + RED.nodes.createNode(this, n); + + let node = this; + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.roomType = n.roomType; + this.roomValue = n.roomValue; + this.eventIdType = n.eventIdType; + this.eventIdValue = n.eventIdValue; + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + if (!node.server) { + node.error("No configuration node", {}); + return; + } + node.server.register(node); + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.on("input", async function (msg) { + if (! node.server || ! node.server.matrixClient) { + node.error("No matrix server selected", msg); + return; + } + + function getToValue(msg, type, property) { + let value = property; + if (type === "msg") { + value = RED.util.getMessageProperty(msg, property); + } else if ((type === 'flow') || (type === 'global')) { + try { + value = RED.util.evaluateNodeProperty(property, type, node, msg); + } catch(e2) { + throw new Error("Invalid value evaluation"); + } + } else if(type === "bool") { + value = (property === 'true'); + } else if(type === "num") { + value = Number(property); + } + return value; + } + + try { + let roomId = getToValue(msg, node.roomType, node.roomValue), + eventId = getToValue(msg, node.eventIdType, node.eventIdValue); + + msg.payload = await node.server.matrixClient.setRoomReadMarkers(roomId, eventId); + node.send([msg, null]); + } catch(e) { + msg.error = `Room pagination error: ${e}`; + node.error(msg.error, msg); + node.send([null, msg]); + } + }); + + node.on("close", function() { + node.server.deregister(node); + }); + } + RED.nodes.registerType("matrix-mark-read", MatrixReceiveMessage); +} \ No newline at end of file diff --git a/src/matrix-paginate-room.html b/src/matrix-paginate-room.html new file mode 100644 index 0000000..f5fdbe5 --- /dev/null +++ b/src/matrix-paginate-room.html @@ -0,0 +1,284 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-paginate-room.js b/src/matrix-paginate-room.js new file mode 100644 index 0000000..8798e6c --- /dev/null +++ b/src/matrix-paginate-room.js @@ -0,0 +1,155 @@ +const {TimelineWindow, RelationType, Filter} = require("matrix-js-sdk"); +const crypto = require('crypto'); +module.exports = function(RED) { + function MatrixReceiveMessage(n) { + RED.nodes.createNode(this, n); + + let node = this; + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.roomType = n.roomType; + this.roomValue = n.roomValue; + this.paginateBackwardsType = n.paginateBackwardsType; + this.paginateBackwardsValue = n.paginateBackwardsValue; + this.paginateKeyType = n.paginateKeyType; + this.paginateKeyValue = n.paginateKeyValue; + this.pageSizeType = n.pageSizeType; + this.pageSizeValue = n.pageSizeValue; + this.timelineWindows = new Map(); + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + if (!node.server) { + node.error("No configuration node", {}); + return; + } + node.server.register(node); + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.on("input", async function (msg) { + if (! node.server || ! node.server.matrixClient) { + node.error("No matrix server selected", msg); + return; + } + + function getToValue(msg, type, property) { + let value = property; + if (type === "msg") { + value = RED.util.getMessageProperty(msg, property); + } else if ((type === 'flow') || (type === 'global')) { + try { + value = RED.util.evaluateNodeProperty(property, type, node, msg); + } catch(e2) { + throw new Error("Invalid value evaluation"); + } + } else if(type === "bool") { + value = (property === 'true'); + } else if(type === "num") { + value = Number(property); + } + return value; + } + + function setToValue(value, type, property) { + if(type === 'global' || type === 'flow') { + var contextKey = RED.util.parseContextStore(property); + if (/\[msg/.test(contextKey.key)) { + // The key has a nest msg. reference to evaluate first + contextKey.key = RED.util.normalisePropertyExpression(contextKey.key, msg, true) + } + var target = node.context()[type]; + var callback = err => { + if (err) { + node.error(err, msg); + getterErrors[rule.p] = err.message; + } + } + target.set(contextKey.key, value, contextKey.store, callback); + } else if(type === 'msg') { + if (!RED.util.setMessageProperty(msg, property, value)) { + node.warn(RED._("change.errors.no-override",{property:property})); + } + } + } + + try { + let roomId = getToValue(msg, node.roomType, node.roomValue), + paginateBackwards = getToValue(msg, node.paginateBackwardsType, node.paginateBackwardsValue), + pageSize = getToValue(msg, node.pageSizeType, node.pageSizeValue), + pageKey = getToValue(msg, node.paginateKeyType, node.paginateKeyValue); + + let room = node.server.matrixClient.getRoom(roomId); + + if(!room) { + throw new Error(`Room ${roomId} does not exist`); + } + if(pageSize > node.server.initialSyncLimit) { + throw new Error(`Page size=${pageSize} cannot exceed initialSyncLimit=${node.server.initialSyncLimit}`); + } + if(!pageKey) { + pageKey = crypto.randomUUID(); + setToValue(pageKey, node.paginateKeyType, node.paginateKeyValue); + } + let timelineWindow = node.timelineWindows.get(pageKey), + moreMessages = true; + if(!timelineWindow) { + let timelineSet = room.getUnfilteredTimelineSet(); + node.debug(JSON.stringify(timelineSet.getFilter())); + // MatrixClient's option initialSyncLimit gets set to the filter we are using + // so override that value with our pageSize + timelineWindow = new TimelineWindow(node.server.matrixClient, timelineSet); + await timelineWindow.load(msg.eventId || null, pageSize); + node.timelineWindows.set(pageKey, timelineWindow); + } else { + moreMessages = await timelineWindow.paginate(paginateBackwards ? 'b' : 'f', pageSize); // b for backwards f for forwards + if(moreMessages) { + await timelineWindow.unpaginate(pageSize, !paginateBackwards); + } + } + + // MatrixEvent objects are massive so this throws an encode error for the string being too long + // since msg objects convert to JSON + // msg.payload = moreMessages ? timelineWindow.getEvents() : false; + + msg.payload = false; + msg.start = timelineWindow.getTimelineIndex('b')?.index; + msg.end = timelineWindow.getTimelineIndex('f')?.index; + if(moreMessages) { + msg.payload = timelineWindow.getEvents().map(function(event) { + return { + encrypted : event.isEncrypted(), + redacted : event.isRedacted(), + content : event.getContent(), + type : (event.getContent()['msgtype'] || event.getType()) || null, + payload : (event.getContent()['body'] || event.getContent()) || null, + isThread : event.getContent()?.['m.relates_to']?.rel_type === RelationType.Thread, + mentions : event.getContent()["m.mentions"] || null, + userId : event.getSender(), + // user : node.matrixClient.getUser(event.getSender()), + topic : event.getRoomId(), + eventId : event.getId(), + event : event, + }; + }); + } + node.send([msg, null]); + } catch(e) { + msg.error = `Room pagination error: ${e}`; + node.error(msg.error, msg); + node.send([null, msg]); + } + }); + + node.on("close", function() { + node.server.deregister(node); + }); + } + RED.nodes.registerType("matrix-paginate-room", MatrixReceiveMessage); +} \ No newline at end of file diff --git a/src/matrix-react.html b/src/matrix-react.html index b552980..e9706e2 100644 --- a/src/matrix-react.html +++ b/src/matrix-react.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, reaction: { value: null } }, diff --git a/src/matrix-react.js b/src/matrix-react.js index 8da269e..a176277 100644 --- a/src/matrix-react.js +++ b/src/matrix-react.js @@ -13,6 +13,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -26,30 +27,31 @@ module.exports = function(RED) { node.on("input", function (msg) { if (!node.server || !node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } msg.topic = node.roomId || msg.topic; if(!msg.topic) { - node.error("Room must be specified in msg.topic or in configuration"); + node.error("Room must be specified in msg.topic or in configuration", msg); return; } let payload = n.reaction || msg.payload; if(!payload) { - node.error('msg.payload must be defined or the reaction configured on the node.'); + node.error('msg.payload must be defined or the reaction configured on the node.', msg); return; } let eventId = msg.referenceEventId || msg.eventId; if(!eventId) { - node.error('Either msg.referenceEventId or msg.eventId must be defined to react to a message.'); + node.error('Either msg.referenceEventId or msg.eventId must be defined to react to a message.', msg); return; } @@ -75,6 +77,10 @@ module.exports = function(RED) { node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-react", MatrixReact); } \ No newline at end of file diff --git a/src/matrix-receive.html b/src/matrix-receive.html index cfde1e7..285ced2 100644 --- a/src/matrix-receive.html +++ b/src/matrix-receive.html @@ -8,8 +8,9 @@ outputs:1, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: {"value": null}, + acceptOwnEvents: {"value": false}, acceptText: {"value": true}, acceptEmotes: {"value": true}, acceptStickers: {"value": true}, @@ -45,7 +46,17 @@
Timeline event filters
-
+
+ + +
+
m.text
-
+
m.emote
-
+
m.sticker
-
+
m.reaction
-
+
m.file
-
+
m.audio
-
+
m.image
-
+
m.video
-
+
s.trim()) : []; node.status({ fill: "red", shape: "ring", text: "disconnected" }); if (!node.server) { - node.error("No configuration node"); + node.error("No configuration node", {}); return; } + node.server.register(node); node.server.on("disconnected", function(){ node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -35,120 +38,103 @@ module.exports = function(RED) { node.server.on("Room.timeline", async function(event, room, toStartOfTimeline, removed, data, msg) { // if node has a room ID set we only listen on that room - if(node.roomIds.length && node.roomIds.indexOf(room.roomId) === -1) { + if (node.roomIds.length && !node.roomIds.includes(room.roomId)) { return; } - switch(msg.type) { + if (!node.acceptOwnEvents && (!event.getSender() || event.getSender().toLowerCase() === node.server.matrixClient.getUserId().toLowerCase())) { + node.log(`Ignoring${msg.encrypted ? ' encrypted' : ''} timeline event [${msg.type}]: (${room.name}) ${event.getId()} for reason: own event`); + return; + } + + const setUrls = (urlKey, encryptedKey) => { + const url = msg.encrypted ? msg.content[encryptedKey]?.url : msg.content[urlKey]; + if (url) { + msg.url = node.server.matrixClient.mxcUrlToHttp(url); + msg.mxc_url = url; + } + }; + + const setThumbnailUrls = (infoKey) => { + const thumbnailFile = msg.content.info?.[infoKey]; + const thumbnailUrl = thumbnailFile?.url; + if (thumbnailUrl) { + msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(thumbnailUrl); + msg.thumbnail_mxc_url = thumbnailUrl; + } + }; + + switch (msg.type) { case 'm.emote': - if(!node.acceptEmotes) return; + if (!node.acceptEmotes) return; break; case 'm.text': - if(!node.acceptText) return; + if (!node.acceptText) return; break; case 'm.sticker': - if(!node.acceptStickers) return; - if(msg.content.info) { - if(msg.content.info.thumbnail_url) { - msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_url); - msg.thumbnail_mxc_url = msg.content.info.thumbnail_url; - } - - if(msg.content.url) { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url); - msg.mxc_url = msg.content.url; - } - } + if (!node.acceptStickers) return; + setThumbnailUrls('thumbnail_url'); + setUrls('url', 'url'); break; case 'm.file': - if(!node.acceptFiles) return; + if (!node.acceptFiles) return; msg.filename = msg.content.filename || msg.content.body; - if(msg.encrypted) { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url); - msg.mxc_url = msg.content.file.url; - } else { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url); - msg.mxc_url = msg.content.url; - } + setUrls('url', 'file'); break; case 'm.audio': - if(!node.acceptAudio) return; - if(msg.encrypted) { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url); - msg.mxc_url = msg.content.file.url; - } else { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url); - msg.mxc_url = msg.content.url; - } - - if('org.matrix.msc1767.file' in msg.content) { + if (!node.acceptAudio) return; + setUrls('url', 'file'); + if ('org.matrix.msc1767.file' in msg.content) { msg.filename = msg.content['org.matrix.msc1767.file'].name; msg.mimetype = msg.content['org.matrix.msc1767.file'].mimetype; } - - if('org.matrix.msc1767.audio' in msg.content) { + if ('org.matrix.msc1767.audio' in msg.content) { msg.duration = msg.content['org.matrix.msc1767.audio'].duration; msg.waveform = msg.content['org.matrix.msc1767.audio'].waveform; } break; case 'm.image': - if(!node.acceptImages) return; + if (!node.acceptImages) return; msg.filename = msg.content.filename || msg.content.body; - if(msg.encrypted) { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url); - msg.mxc_url = msg.content.file.url; - msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_file.url); - msg.thumbnail_mxc_url = msg.content.info.thumbnail_file.url; - } else { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url); - msg.mxc_url = msg.content.url; - msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_url); - msg.thumbnail_mxc_url = msg.content.info.thumbnail_url; - } + setUrls('url', 'file'); + setThumbnailUrls('thumbnail_file'); break; - case 'm.video': - if(!node.acceptVideos) return; + if (!node.acceptVideos) return; msg.filename = msg.content.filename || msg.content.body; - if(msg.encrypted) { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.file.url); - msg.mxc_url = msg.content.file.url; - msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_file.url); - msg.thumbnail_mxc_url = msg.content.info.thumbnail_file.url; - } else { - msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url); - msg.mxc_url = msg.content.url; - msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_url); - msg.thumbnail_mxc_url = msg.content.info.thumbnail_url; - } + setUrls('url', 'file'); + setThumbnailUrls('thumbnail_file'); break; case 'm.location': - if(!node.acceptLocations) return; + if (!node.acceptLocations) return; msg.geo_uri = msg.content.geo_uri; msg.payload = msg.content.body; break; case 'm.reaction': - if(!node.acceptReactions) return; + if (!node.acceptReactions) return; msg.info = msg.content["m.relates_to"].info; msg.referenceEventId = msg.content["m.relates_to"].event_id; msg.payload = msg.content["m.relates_to"].key; break; default: - // node.warn("Unknown event type: " + msg.type); return; } node.send(msg); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-receive", MatrixReceiveMessage); } \ No newline at end of file diff --git a/src/matrix-room-ban.html b/src/matrix-room-ban.html index 32bb931..1bb6f58 100644 --- a/src/matrix-room-ban.html +++ b/src/matrix-room-ban.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, reason: { value: null } }, diff --git a/src/matrix-room-ban.js b/src/matrix-room-ban.js index 0a26b74..a0af7db 100644 --- a/src/matrix-room-ban.js +++ b/src/matrix-room-ban.js @@ -13,6 +13,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -26,23 +27,24 @@ module.exports = function(RED) { node.on("input", function (msg) { if (! node.server || ! node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } msg.topic = node.roomId || msg.topic; if(!msg.topic) { - node.error("Room must be specified in msg.topic or in configuration"); + node.error("Room must be specified in msg.topic or in configuration", msg); return; } if(!msg.userId) { - node.error("msg.userId was not set."); + node.error("msg.userId was not set.", msg); return; } @@ -53,11 +55,15 @@ module.exports = function(RED) { node.send([msg, null]); }) .catch(function(e){ - node.error("Error trying to ban " + msg.userId + " from " + msg.topic); + node.error("Error trying to ban " + msg.userId + " from " + msg.topic, msg); msg.error = e; node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-room-ban", MatrixBan); } \ No newline at end of file diff --git a/src/matrix-room-invite.html b/src/matrix-room-invite.html index 79c9c39..a2999ee 100644 --- a/src/matrix-room-invite.html +++ b/src/matrix-room-invite.html @@ -8,7 +8,7 @@ outputs: 1, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, }, label: function() { diff --git a/src/matrix-room-invite.js b/src/matrix-room-invite.js index 9c7edf5..1dbbfae 100644 --- a/src/matrix-room-invite.js +++ b/src/matrix-room-invite.js @@ -9,9 +9,10 @@ module.exports = function(RED) { this.roomId = n.roomId; if(!this.server) { - node.error('Server must be configured on the node.'); + node.error('Server must be configured on the node.', {}); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -26,6 +27,10 @@ module.exports = function(RED) { node.server.on("Room.invite", async function(msg) { node.send(msg); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-room-invite", MatrixRoomInvite); } \ No newline at end of file diff --git a/src/matrix-room-kick.html b/src/matrix-room-kick.html index f0bf0e1..287f74b 100644 --- a/src/matrix-room-kick.html +++ b/src/matrix-room-kick.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: null }, reason: { value: null } }, diff --git a/src/matrix-room-kick.js b/src/matrix-room-kick.js index 5fb9d6f..ac3efb0 100644 --- a/src/matrix-room-kick.js +++ b/src/matrix-room-kick.js @@ -13,6 +13,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -26,23 +27,24 @@ module.exports = function(RED) { node.on("input", function (msg) { if (! node.server || ! node.server.matrixClient) { - node.error("No matrix server selected"); + node.error("No matrix server selected", msg); return; } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } msg.topic = node.roomId || msg.topic; if(!msg.topic) { - node.error("Room must be specified in msg.topic or in configuration"); + node.error("Room must be specified in msg.topic or in configuration", msg); return; } if(!msg.userId) { - node.error("msg.userId was not set."); + node.error("msg.userId was not set.", msg); return; } @@ -53,11 +55,15 @@ module.exports = function(RED) { node.send([msg, null]); }) .catch(function(e){ - node.error("Error trying to kick " + msg.userId + " from " + msg.topic); + node.error("Error trying to kick " + msg.userId + " from " + msg.topic, msg); msg.error = e; node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-room-kick", MatrixKick); } \ No newline at end of file diff --git a/src/matrix-room-state-events.html b/src/matrix-room-state-events.html new file mode 100644 index 0000000..6eaccb5 --- /dev/null +++ b/src/matrix-room-state-events.html @@ -0,0 +1,369 @@ + + + + + \ No newline at end of file diff --git a/src/matrix-room-state-events.js b/src/matrix-room-state-events.js new file mode 100644 index 0000000..de48888 --- /dev/null +++ b/src/matrix-room-state-events.js @@ -0,0 +1,293 @@ +module.exports = function(RED) { + function MatrixRoomStateEvents(n) { + RED.nodes.createNode(this, n); + + var node = this; + + this.name = n.name; + this.server = RED.nodes.getNode(n.server); + this.roomId = n.roomId; + this.rules = n.rules; + + if (!node.server) { + node.warn("No configuration node"); + return; + } + node.server.register(node); + + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + + node.server.on("disconnected", function(){ + node.status({ fill: "red", shape: "ring", text: "disconnected" }); + }); + + node.server.on("connected", function() { + node.status({ fill: "green", shape: "ring", text: "connected" }); + }); + + node.on("input", async function (msg) { + if (! node.server || ! node.server.matrixClient) { + msg.error = "No matrix server selected"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + if(!node.server.isConnected()) { + msg.error = "Matrix server connection is currently closed"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + msg.topic = node.roomId || msg.topic; + if(!msg.topic) { + msg.error = "Room must be specified in msg.topic or in configuration"; + node.error(msg.error, msg); + node.send([null, msg]); + return; + } + + let getterErrors = {}, + setterErrors = {}; + + if(!Array.isArray(node.rules) || !node.rules.length) { + node.warn("No rules configured, skipping", msg); + return msg; + } + + function getToValue(msg, rule) { + var value = rule.to; + if (rule.tot === 'json') { + try { + value = JSON.parse(rule.to); + } catch(e) { + throw new Error("Invalid JSON"); + } + } else if (rule.tot === 'bin') { + try { + value = Buffer.from(JSON.parse(rule.to)) + } catch(e) { + throw new Error("Invalid Binary"); + } + } + if (rule.tot === "msg") { + value = RED.util.getMessageProperty(msg,rule.to); + } else if ((rule.tot === 'flow') || (rule.tot === 'global')) { + try { + value = RED.util.evaluateNodeProperty(rule.to, rule.tot, node, msg); + } catch(e2) { + throw new Error("Invalid value evaluation"); + } + } else if (rule.tot === 'date') { + value = Date.now(); + } else if (rule.tot === 'jsonata') { + try { + value = RED.util.evaluateJSONataExpression(rule.to,msg); + } catch(e3) { + throw new Error("Invalid expression"); + } + return; + } + return value; + } + + function setToValue(value, rule) { + if(rule.tot === 'global' || rule.tot === 'flow') { + var contextKey = RED.util.parseContextStore(rule.to); + if (/\[msg/.test(contextKey.key)) { + // The key has a nest msg. reference to evaluate first + contextKey.key = RED.util.normalisePropertyExpression(contextKey.key, msg, true) + } + var target = node.context()[rule.tot]; + var callback = err => { + if (err) { + node.error(err, msg); + getterErrors[rule.p] = err.message; + } + } + target.set(contextKey.key, value, contextKey.store, callback); + } else if(rule.tot === 'msg') { + if (!RED.util.setMessageProperty(msg, rule.to, value)) { + node.warn(RED._("change.errors.no-override",{property:rule.to})); + } + } + } + + for(let rule of node.rules) { + // [ + // { + // "t": "set", + // "p": "m.room.topic", + // "to": "asdf", + // "tot": "str" + // }, ... + // ] + + let cachedGetters = {}; + if(rule.t === 'set') { + let value; + try { + value = getToValue(msg, rule); + switch(rule.p) { + case "m.room.name": + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.name", + typeof value === "string" + ? {name: value} + : value); + break; + case "m.room.topic": + if (typeof value === "string") { + await node.server.matrixClient.setRoomTopic(msg.topic, value); + } else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.topic", + value + ); + } + break; + case "m.room.avatar": + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.avatar", + typeof value === "string" + ? {"url": value} + : value, + ""); + break; + case "m.room.join_rules": + if(typeof value !== 'object') { + setterErrors[rule.p] = "m.room.join_rules content must be object"; + } else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.join_rules", + value, + ""); + } + break; + case "m.room.canonical_alias": + if(typeof value !== 'object') { + setterErrors[rule.p] = "m.room.canonical_alias content must be object"; + } else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.canonical_alias", + value, + ""); + } + break; + case "m.space.parent": + if (typeof value !== 'object') { + setterErrors[rule.p] = "m.space.parent content must be object"; + } else if (!msg.state_key) { + setterErrors[rule.p] = "m.space.parent required msg.state_key input to be set to the child roomId"; + }else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.power_levels", + value, + msg.state_key); + } + break; + case "m.space.child": + if (typeof value !== 'object') { + setterErrors[rule.p] = "m.space.child content must be object"; + } else if (!msg.state_key) { + setterErrors[rule.p] = "m.space.child required msg.state_key input to be set to the parent roomId"; + }else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.power_levels", + value, + msg.state_key); + } + break; + case "m.room.guest_access": + await node.server.matrixClient.sendStateEvent( + msg.topic, + "m.room.guest_access", + typeof value === "string" + ? { "guest_access": value } + : value, + ""); + break; + default: + if(typeof value !== 'object') { + setterErrors[rule.p] = `${rule.p} content must be object`; + } else { + await node.server.matrixClient.sendStateEvent( + msg.topic, + rule.p, + value, + msg.state_key || ""); + } + break; + } + } catch(e) { + setterErrors[rule.p] = e.message; + } + } else if(rule.t === 'get') { + let value; + if(cachedGetters.hasOwnProperty(rule.p)) { + value = cachedGetters[rule.p]; + } else { + try { + if(rule.ls) { + // we opted to lookup from local storage, will fallback to server if necessary + let room = node.server.matrixClient.getRoom(msg.topic); + if(room) { + value = await room.getLiveTimeline().getState("f").getStateEvents(rule.p, ""); + } + } + if(!value) { + // fetch the latest state event by type from server + value = await node.server.matrixClient.getStateEvent(msg.topic, rule.p, ""); + if(value) { + // normalize some simpler events for easier access + switch(rule.p) { + case "m.room.name": + value = value?.name + break; + case "m.room.topic": + value = value?.topic + break; + case "m.room.avatar": + value = value?.url + break; + case "m.room.guest_access": + value = value?.guest_access; + break; + } + } + } + setToValue(value, rule); + cachedGetters[rule.p] = value; + } catch(e) { + getterErrors[rule.p] = e; + } + } + + } + } + + if(Object.keys(setterErrors).length) { + msg.setter_errors = setterErrors; + } + + if(Object.keys(getterErrors).length) { + msg.getter_errors = getterErrors; + } + + node.send([msg, null]); + }); + + node.on("close", function() { + node.server.deregister(node); + }); + } + RED.nodes.registerType("matrix-room-state-events", MatrixRoomStateEvents); +} \ No newline at end of file diff --git a/src/matrix-room-users.html b/src/matrix-room-users.html index 34e6452..c0fc2fa 100644 --- a/src/matrix-room-users.html +++ b/src/matrix-room-users.html @@ -8,7 +8,7 @@ outputs:2, defaults: { name: { value: null }, - server: { value: "", type: "matrix-server-config" }, + server: { type: "matrix-server-config" }, roomId: { value: "" } }, label: function() { diff --git a/src/matrix-room-users.js b/src/matrix-room-users.js index 7d1da9b..8a801c6 100644 --- a/src/matrix-room-users.js +++ b/src/matrix-room-users.js @@ -13,6 +13,7 @@ module.exports = function(RED) { node.warn("No configuration node"); return; } + node.server.register(node); node.status({ fill: "red", shape: "ring", text: "disconnected" }); @@ -31,13 +32,14 @@ module.exports = function(RED) { } if(!node.server.isConnected()) { - node.error("Matrix server connection is currently closed"); + node.error("Matrix server connection is currently closed", msg); node.send([null, msg]); + return; } let roomId = node.roomId || msg.topic; if(!roomId) { - node.error("msg.topic is required. Specify in the input or configure the room ID on the node."); + node.error("msg.topic is required. Specify in the input or configure the room ID on the node.", msg); return; } @@ -65,6 +67,10 @@ module.exports = function(RED) { node.send([null, msg]); }); }); + + node.on("close", function() { + node.server.deregister(node); + }); } RED.nodes.registerType("matrix-room-users", MatrixRoomUsers); } \ No newline at end of file diff --git a/src/matrix-send-file.html b/src/matrix-send-file.html index e3edac5..e706113 100644 --- a/src/matrix-send-file.html +++ b/src/matrix-send-file.html @@ -1,6 +1,6 @@ @@ -43,6 +56,9 @@
+
+ If message is an object it sets the full content of the message. +
+
+ + +
+