From 6db0faefb4dcd752be8b7bc2316e5aa6b7027d61 Mon Sep 17 00:00:00 2001 From: Yuzu Date: Mon, 8 Jun 2026 22:38:42 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20introduce=20platform-specif?= =?UTF-8?q?ic=20BLE=20backends?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit solves lack of Linux support in #2 --- package.json | 1 + pnpm-lock.yaml | 952 ++++++++++++++++++++++++++ src/lib/ble/backend.ts | 51 ++ src/lib/ble/backends/dbus-backend.ts | 244 +++++++ src/lib/ble/backends/noble-backend.ts | 202 ++++++ src/lib/ble/ble-client.ts | 258 ++----- 6 files changed, 1521 insertions(+), 187 deletions(-) create mode 100644 src/lib/ble/backend.ts create mode 100644 src/lib/ble/backends/dbus-backend.ts create mode 100644 src/lib/ble/backends/noble-backend.ts diff --git a/package.json b/package.json index 4b486fd..ab372fc 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "ink": "^6.6.0", "ink-big-text": "^2.0.0", "ink-spinner": "^5.0.0", + "node-ble": "^1.13.0", "react": "^19.2.4", "sharp": "^0.34.5" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7f0595..5e4a1ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: ink-spinner: specifier: ^5.0.0 version: 5.0.0(ink@6.6.0(@types/react@19.2.10)(react@19.2.4))(react@19.2.4) + node-ble: + specifier: ^1.13.0 + version: 1.13.0 react: specifier: ^19.2.4 version: 19.2.4 @@ -244,89 +247,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -364,6 +383,10 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@nornagon/put@0.0.8': + resolution: {integrity: sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==} + engines: {node: '>=0.3.0'} + '@rollup/rollup-android-arm-eabi@4.57.1': resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] @@ -398,66 +421,79 @@ packages: resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} @@ -611,15 +647,25 @@ packages: '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ansi-escapes@7.2.0: resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + ansi-regex@6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} @@ -635,6 +681,20 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + aproba@1.2.0: + resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + + are-we-there-yet@1.1.7: + resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} + deprecated: This package is no longer supported. + + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -642,10 +702,31 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + auto-bind@5.0.1: resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -672,6 +753,9 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + cfonts@3.3.1: resolution: {integrity: sha512-ZGEmN3W9mViWEDjsuPo4nK4h39sfh6YtoneFYp9WLPI/rw8BaSSrfQC6jkrGW3JMvV3ZnExJB/AEqXc/nHYxkw==} engines: {node: '>=10'} @@ -697,6 +781,10 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -721,6 +809,10 @@ packages: resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -728,6 +820,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -736,6 +832,9 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -743,10 +842,19 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + convert-to-spaces@2.0.1: resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -754,6 +862,13 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + + dbus-next@0.10.2: + resolution: {integrity: sha512-kLNQoadPstLgKKGIXKrnRsMgtAK/o+ix3ZmcfTfvBHzghiO9yHXpoKImGnB50EXwnfSFaSAullW/7UrSkAISSQ==} + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -784,6 +899,13 @@ packages: resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} engines: {node: '>=0.10.0'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -792,9 +914,19 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -829,10 +961,26 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -842,6 +990,9 @@ packages: picomatch: optional: true + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -852,10 +1003,27 @@ packages: fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + + from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -864,6 +1032,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gauge@2.7.4: + resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} + deprecated: This package is no longer supported. + get-east-asian-width@1.4.0: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} @@ -879,6 +1051,13 @@ packages: get-tsconfig@4.13.1: resolution: {integrity: sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==} + getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -886,6 +1065,15 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + har-schema@2.0.0: + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} + + har-validator@5.1.5: + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} + deprecated: this library is no longer supported + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -897,14 +1085,32 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hexy@0.2.11: + resolution: {integrity: sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==} + hasBin: true + + http-signature@1.2.0: + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} + indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ink-big-text@2.0.0: resolution: {integrity: sha512-Juzqv+rIOLGuhMJiE50VtS6dg6olWfzFdL7wsU/EARSL5Eaa5JNXMogMBm9AkjgzO2Y3UwWCOh87jbhSn8aNdw==} engines: {node: '>=14.16'} @@ -952,6 +1158,10 @@ packages: engines: {node: '>=8'} hasBin: true + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@5.1.0: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} @@ -969,16 +1179,25 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -989,16 +1208,35 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + jsbi@2.0.5: + resolution: {integrity: sha512-TzO/62Hxeb26QMb4IGlI/5X+QLr9Uqp1FPkwp2+KOICW+Q+vSuFj61c8pkT6wAns4WcK56X7CmSHhJeDGWOqxQ==} + + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify@1.3.0: resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} engines: {node: '>= 0.4'} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + kind-of@3.2.2: resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} engines: {node: '>=0.10.0'} @@ -1017,6 +1255,9 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1027,6 +1268,9 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1035,13 +1279,41 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -1054,6 +1326,9 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nan@2.27.0: + resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1066,6 +1341,9 @@ packages: resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} engines: {node: ^18 || ^20 || >= 21} + node-ble@1.13.0: + resolution: {integrity: sha512-jg8GmyZwowUcze6t/GEEunYvAcASR9hMUpRxs2jehmgdalDQ0xXtkmDfdAQO4Rq3b1gBxBRo43E/ASzbPf3d/A==} + node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true @@ -1074,6 +1352,27 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-gyp@7.1.2: + resolution: {integrity: sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==} + engines: {node: '>= 10.12.0'} + hasBin: true + + nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + + npmlog@4.1.2: + resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} + deprecated: This package is no longer supported. + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + + oauth-sign@0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1082,6 +1381,9 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -1099,6 +1401,10 @@ packages: engines: {node: '>=14', npm: '>5'} hasBin: true + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1110,6 +1416,12 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1150,9 +1462,23 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.5.5: + resolution: {integrity: sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==} + engines: {node: '>=0.6'} + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -1166,10 +1492,18 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + request@2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -1181,11 +1515,29 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + rollup@4.57.1: resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -1198,6 +1550,9 @@ packages: resolution: {integrity: sha512-AmH3D9hHPFmnF/oq/rvigfiAouAKyK/TjnrkwZRYSFZxNggJxwvbAbfYrLeuvq7ktUdhuHdVdSjj852Z55R+uA==} engines: {node: '>=16.0.0'} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -1236,6 +1591,14 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -1246,6 +1609,13 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -1254,6 +1624,13 @@ packages: resolution: {integrity: sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==} engines: {node: '>=20'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + strip-ansi@7.1.2: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} @@ -1274,6 +1651,11 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -1281,6 +1663,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1311,6 +1696,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tough-cookie@2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -1345,6 +1734,12 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -1364,10 +1759,28 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + usb@2.17.0: resolution: {integrity: sha512-UuFgrlglgDn5ll6d5l7kl3nDb2Yx43qLUGcDq+7UNLZLtbNug0HZBb2Xodhgx2JZB1LqvU+dOGqLEeYUeZqsHg==} engines: {node: '>=12.22.0 <13.0 || >=14.17.0'} + usocket@0.3.0: + resolution: {integrity: sha512-V/H02RNiaOCJZuPoKont/y12VJaImC6C5xW7OzPFjYu9qnig0yv9hyp9E7Wqjm6d8yZuZouH3NAfDATVMgh2SQ==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1451,6 +1864,9 @@ packages: engines: {node: '>=8'} hasBin: true + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + widest-line@5.0.0: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} @@ -1464,6 +1880,9 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -1476,6 +1895,17 @@ packages: utf-8-validate: optional: true + xml2js@0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -1684,6 +2114,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@nornagon/put@0.0.8': {} + '@rollup/rollup-android-arm-eabi@4.57.1': optional: true @@ -1918,12 +2350,26 @@ snapshots: '@yarnpkg/lockfile@1.1.0': optional: true + abbrev@1.1.1: + optional: true + acorn@8.15.0: {} + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + optional: true + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 + ansi-regex@2.1.1: + optional: true + ansi-regex@6.2.2: {} ansi-styles@4.3.0: @@ -1935,13 +2381,58 @@ snapshots: any-promise@1.3.0: {} + aproba@1.2.0: + optional: true + + are-we-there-yet@1.1.7: + dependencies: + delegates: 1.0.0 + readable-stream: 2.3.8 + optional: true + + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + optional: true + + assert-plus@1.0.0: + optional: true + assertion-error@2.0.1: {} async@3.2.6: optional: true + asynckit@0.4.0: + optional: true + auto-bind@5.0.1: {} + aws-sign2@0.7.0: + optional: true + + aws4@1.13.2: + optional: true + + balanced-match@1.0.2: + optional: true + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 + optional: true + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + optional: true + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -1974,6 +2465,9 @@ snapshots: get-intrinsic: 1.3.0 optional: true + caseless@0.12.0: + optional: true + cfonts@3.3.1: dependencies: supports-color: 8.1.1 @@ -2001,6 +2495,9 @@ snapshots: dependencies: readdirp: 4.1.2 + chownr@2.0.0: + optional: true + ci-info@3.9.0: optional: true @@ -2021,6 +2518,9 @@ snapshots: dependencies: convert-to-spaces: 2.0.1 + code-point-at@1.1.0: + optional: true + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2029,16 +2529,33 @@ snapshots: color-name@1.1.4: optional: true + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + optional: true + commander@14.0.3: {} commander@4.1.1: {} + concat-map@0.0.1: + optional: true + confbox@0.1.8: {} consola@3.4.2: {} + console-control-strings@1.1.0: + optional: true + convert-to-spaces@2.0.1: {} + core-util-is@1.0.2: + optional: true + + core-util-is@1.0.3: + optional: true + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2048,6 +2565,23 @@ snapshots: csstype@3.2.3: {} + dashdash@1.14.1: + dependencies: + assert-plus: 1.0.0 + optional: true + + dbus-next@0.10.2: + dependencies: + '@nornagon/put': 0.0.8 + event-stream: 3.3.4 + hexy: 0.2.11 + jsbi: 2.0.5 + long: 4.0.0 + safe-buffer: 5.2.1 + xml2js: 0.4.23 + optionalDependencies: + usocket: 0.3.0 + debug@4.3.4: dependencies: ms: 2.1.2 @@ -2070,6 +2604,12 @@ snapshots: dependencies: is-descriptor: 1.0.3 + delayed-stream@1.0.0: + optional: true + + delegates@1.0.0: + optional: true + detect-libc@2.1.2: {} dunder-proto@1.0.1: @@ -2079,8 +2619,19 @@ snapshots: gopd: 1.2.0 optional: true + duplexer@0.1.2: {} + + ecc-jsbn@0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + optional: true + emoji-regex@10.6.0: {} + env-paths@2.2.1: + optional: true + environment@1.1.0: {} es-define-property@1.0.1: @@ -2133,12 +2684,37 @@ snapshots: dependencies: '@types/estree': 1.0.8 + event-stream@3.3.4: + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + expect-type@1.3.0: {} + extend@3.0.2: + optional: true + + extsprintf@1.3.0: + optional: true + + fast-deep-equal@3.1.3: + optional: true + + fast-json-stable-stringify@2.1.0: + optional: true + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 + file-uri-to-path@1.0.0: + optional: true + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -2155,6 +2731,18 @@ snapshots: mlly: 1.8.0 rollup: 4.57.1 + forever-agent@0.6.1: + optional: true + + form-data@2.3.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + optional: true + + from@0.1.7: {} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -2162,11 +2750,31 @@ snapshots: universalify: 2.0.1 optional: true + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + optional: true + + fs.realpath@1.0.0: + optional: true + fsevents@2.3.3: optional: true function-bind@1.1.2: {} + gauge@2.7.4: + dependencies: + aproba: 1.2.0 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 1.0.2 + strip-ansi: 3.0.1 + wide-align: 1.1.5 + optional: true + get-east-asian-width@1.4.0: {} get-intrinsic@1.3.0: @@ -2193,12 +2801,36 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + getpass@0.1.7: + dependencies: + assert-plus: 1.0.0 + optional: true + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + optional: true + gopd@1.2.0: optional: true graceful-fs@4.2.11: optional: true + har-schema@2.0.0: + optional: true + + har-validator@5.1.5: + dependencies: + ajv: 6.15.0 + har-schema: 2.0.0 + optional: true + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -2209,12 +2841,33 @@ snapshots: has-symbols@1.1.0: optional: true + has-unicode@2.0.1: + optional: true + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hexy@0.2.11: {} + + http-signature@1.2.0: + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.18.0 + optional: true + indent-string@5.0.0: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + optional: true + + inherits@2.0.4: + optional: true + ink-big-text@2.0.0(ink@6.6.0(@types/react@19.2.10)(react@19.2.4))(react@19.2.4): dependencies: cfonts: 3.3.1 @@ -2278,6 +2931,11 @@ snapshots: is-docker@2.2.1: optional: true + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + optional: true + is-fullwidth-code-point@5.1.0: dependencies: get-east-asian-width: 1.4.0 @@ -2291,23 +2949,43 @@ snapshots: is-number@7.0.0: optional: true + is-typedarray@1.0.0: + optional: true + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 optional: true + isarray@1.0.0: + optional: true + isarray@2.0.5: optional: true isexe@2.0.0: optional: true + isstream@0.1.2: + optional: true + joycon@3.1.1: {} js-tokens@4.0.0: {} js-tokens@9.0.1: {} + jsbi@2.0.5: {} + + jsbn@0.1.1: + optional: true + + json-schema-traverse@0.4.1: + optional: true + + json-schema@0.4.0: + optional: true + json-stable-stringify@1.3.0: dependencies: call-bind: 1.0.8 @@ -2317,6 +2995,9 @@ snapshots: object-keys: 1.1.1 optional: true + json-stringify-safe@5.0.1: + optional: true + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -2327,6 +3008,14 @@ snapshots: jsonify@0.0.1: optional: true + jsprim@1.4.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + optional: true + kind-of@3.2.2: dependencies: is-buffer: 1.1.6 @@ -2342,6 +3031,8 @@ snapshots: load-tsconfig@0.2.5: {} + long@4.0.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -2352,6 +3043,8 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + map-stream@0.1.0: {} + math-intrinsics@1.1.0: optional: true @@ -2361,11 +3054,41 @@ snapshots: picomatch: 2.3.1 optional: true + mime-db@1.52.0: + optional: true + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + optional: true + mimic-fn@2.1.0: {} + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.15 + optional: true + minimist@1.2.8: optional: true + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + optional: true + + minipass@5.0.0: + optional: true + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + optional: true + + mkdirp@1.0.4: + optional: true + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -2384,6 +3107,9 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nan@2.27.0: + optional: true + nanoid@3.3.11: {} node-addon-api@7.0.0: @@ -2391,16 +3117,58 @@ snapshots: node-addon-api@8.5.0: {} + node-ble@1.13.0: + dependencies: + dbus-next: 0.10.2 + node-gyp-build@4.6.0: optional: true node-gyp-build@4.8.4: {} + node-gyp@7.1.2: + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + nopt: 5.0.0 + npmlog: 4.1.2 + request: 2.88.2 + rimraf: 3.0.2 + semver: 7.7.3 + tar: 6.2.1 + which: 2.0.2 + optional: true + + nopt@5.0.0: + dependencies: + abbrev: 1.1.1 + optional: true + + npmlog@4.1.2: + dependencies: + are-we-there-yet: 1.1.7 + console-control-strings: 1.1.0 + gauge: 2.7.4 + set-blocking: 2.0.0 + optional: true + + number-is-nan@1.0.1: + optional: true + + oauth-sign@0.9.0: + optional: true + object-assign@4.1.1: {} object-keys@1.1.1: optional: true + once@1.4.0: + dependencies: + wrappy: 1.0.2 + optional: true + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -2431,6 +3199,9 @@ snapshots: yaml: 2.8.2 optional: true + path-is-absolute@1.0.1: + optional: true + path-key@3.1.1: optional: true @@ -2438,6 +3209,13 @@ snapshots: pathval@2.0.1: {} + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + + performance-now@2.1.0: + optional: true + picocolors@1.1.1: {} picomatch@2.3.1: @@ -2467,12 +3245,26 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + process-nextick-args@2.0.1: + optional: true + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + psl@1.15.0: + dependencies: + punycode: 2.3.1 + optional: true + + punycode@2.3.1: + optional: true + + qs@6.5.5: + optional: true + react-is@16.13.1: {} react-reconciler@0.33.0(react@19.2.4): @@ -2482,8 +3274,43 @@ snapshots: react@19.2.4: {} + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + optional: true + readdirp@4.1.2: {} + request@2.88.2: + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.5 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.5 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 3.4.0 + optional: true + resolve-from@5.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -2493,6 +3320,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + optional: true + rollup@4.57.1: dependencies: '@types/estree': 1.0.8 @@ -2524,6 +3356,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 + safe-buffer@5.1.2: + optional: true + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: + optional: true + + sax@1.6.0: {} + scheduler@0.27.0: {} semver@7.7.3: {} @@ -2548,6 +3390,9 @@ snapshots: - supports-color optional: true + set-blocking@2.0.0: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -2613,6 +3458,23 @@ snapshots: source-map@0.7.6: {} + split@0.3.3: + dependencies: + through: 2.3.8 + + sshpk@1.18.0: + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + optional: true + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -2621,6 +3483,17 @@ snapshots: std-env@3.10.0: {} + stream-combiner@0.0.4: + dependencies: + duplexer: 0.1.2 + + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + optional: true + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -2632,6 +3505,16 @@ snapshots: get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + optional: true + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + optional: true + strip-ansi@7.1.2: dependencies: ansi-regex: 6.2.2 @@ -2659,6 +3542,16 @@ snapshots: dependencies: has-flag: 4.0.0 + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + optional: true + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -2667,6 +3560,8 @@ snapshots: dependencies: any-promise: 1.3.0 + through@2.3.8: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -2690,6 +3585,12 @@ snapshots: is-number: 7.0.0 optional: true + tough-cookie@2.5.0: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + optional: true + tree-kill@1.2.2: {} ts-interface-checker@0.1.13: {} @@ -2732,6 +3633,14 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + + tweetnacl@0.14.5: + optional: true + type-fest@4.41.0: {} typescript@5.9.3: {} @@ -2743,6 +3652,11 @@ snapshots: universalify@2.0.1: optional: true + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + optional: true + usb@2.17.0: dependencies: '@types/w3c-web-usb': 1.0.13 @@ -2750,6 +3664,26 @@ snapshots: node-gyp-build: 4.8.4 optional: true + usocket@0.3.0: + dependencies: + bindings: 1.5.0 + nan: 2.27.0 + node-gyp: 7.1.2 + optional: true + + util-deprecate@1.0.2: + optional: true + + uuid@3.4.0: + optional: true + + verror@1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + optional: true + vite-node@3.2.4(@types/node@22.19.8)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 @@ -2836,6 +3770,11 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + wide-align@1.1.5: + dependencies: + string-width: 1.0.2 + optional: true + widest-line@5.0.0: dependencies: string-width: 7.2.0 @@ -2851,8 +3790,21 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 + wrappy@1.0.2: + optional: true + ws@8.19.0: {} + xml2js@0.4.23: + dependencies: + sax: 1.6.0 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + + yallist@4.0.0: + optional: true + yaml@2.8.2: optional: true diff --git a/src/lib/ble/backend.ts b/src/lib/ble/backend.ts new file mode 100644 index 0000000..a629495 --- /dev/null +++ b/src/lib/ble/backend.ts @@ -0,0 +1,51 @@ +export interface DiscoveredDevice { + address: string; + name: string | null; +} + +export interface BleCharacteristic { + uuid: string; + write(data: Buffer, withoutResponse: boolean): Promise; + subscribe(onData: (data: Buffer) => void): Promise; + unsubscribe(): Promise; +} + +export interface BleBackend { + readonly name: string; + + init(): Promise; + + scanFor( + matcher: (device: DiscoveredDevice) => boolean, + timeoutMs: number, + ): Promise; + + stopScan(): Promise; + + connect(address: string): Promise; + + onDisconnect(callback: () => void): void; + + discoverCharacteristics( + writeUUID: string, + notifyUUID: string, + normalizeUUID: (uuid: string) => string, + ): Promise<{ write: BleCharacteristic; notify: BleCharacteristic }>; + + disconnect(): Promise; +} + +export type BleBackendType = "noble" | "dbus"; + +/** + * Uses dbus on Linux and noble on other platforms. + * You can override with BEAMBOXCTL_BLE_BACKEND=noble|dbus. + */ +export function resolveBackendType(): BleBackendType { + const override = process.env.BEAMBOXCTL_BLE_BACKEND?.toLowerCase().trim(); + if (override === "noble" || override === "dbus") { + return override; + } + + return process.platform === "linux" ? "dbus" : "noble"; +} diff --git a/src/lib/ble/backends/dbus-backend.ts b/src/lib/ble/backends/dbus-backend.ts new file mode 100644 index 0000000..74c961f --- /dev/null +++ b/src/lib/ble/backends/dbus-backend.ts @@ -0,0 +1,244 @@ +import { createBluetooth } from "node-ble"; +import type NodeBle from "node-ble"; +import { ConnectionError } from "../../utils/errors.ts"; +import { logger } from "../../utils/logger.ts"; +import type { + BleBackend, + BleCharacteristic, + DiscoveredDevice, +} from "../backend.ts"; + +const POLL_INTERVAL_MS = 1000; + +class DBusCharacteristic implements BleCharacteristic { + private valueChangedListener: ((buffer: Buffer) => void) | null = null; + + constructor( + private characteristic: NodeBle.GattCharacteristic, + public readonly uuid: string, + ) {} + + async write(data: Buffer, withoutResponse: boolean): Promise { + if (withoutResponse) { + await this.characteristic.writeValueWithoutResponse(data); + } else { + await this.characteristic.writeValueWithResponse(data); + } + } + + async subscribe(onData: (data: Buffer) => void): Promise { + this.valueChangedListener = onData; + this.characteristic.on("valuechanged", onData); + await this.characteristic.startNotifications(); + } + + async unsubscribe(): Promise { + if (this.valueChangedListener) { + this.characteristic.removeListener( + "valuechanged", + this.valueChangedListener, + ); + this.valueChangedListener = null; + } + await this.characteristic.stopNotifications().catch(() => {}); + } +} + +export class DBusBackend implements BleBackend { + readonly name = "dbus"; + + private bluetooth: NodeBle.Bluetooth | null = null; + private destroy: (() => void) | null = null; + private adapter: NodeBle.Adapter | null = null; + private device: NodeBle.Device | null = null; + private scanning = false; + + async init(): Promise { + if (this.bluetooth) { + return; + } + + const { bluetooth, destroy } = createBluetooth(); + this.bluetooth = bluetooth; + this.destroy = destroy; + + try { + this.adapter = await bluetooth.defaultAdapter(); + } catch { + throw new ConnectionError( + "No Bluetooth adapter found (is bluetoothd running?)", + ); + } + + if (!(await this.adapter.isPowered())) { + throw new ConnectionError("Bluetooth adapter is not powered on"); + } + } + + private async ensureDiscovering(): Promise { + if (!this.adapter) { + throw new ConnectionError("Bluetooth adapter not initialized"); + } + if (!(await this.adapter.isDiscovering())) { + await this.adapter.startDiscovery(); + } + this.scanning = true; + } + + async scanFor( + matcher: (device: DiscoveredDevice) => boolean, + timeoutMs: number, + ): Promise { + if (!this.adapter) { + throw new ConnectionError("Bluetooth adapter not initialized"); + } + + await this.ensureDiscovering(); + + const adapter = this.adapter; + + // Keep re-checking unnamed devices on every poll instead of giving up on first sight. + // Not sure if this is the best way to handle this. + + const named = new Map(); + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + const addresses = await adapter.devices(); + + for (const address of addresses) { + if (named.get(address)) { + continue; + } + + let name: string | null = null; + try { + const remoteDevice = await adapter.getDevice(address); + name = await remoteDevice.getName().catch(async () => { + return await remoteDevice.getAlias().catch(() => null); + }); + } catch { + // device vanished mid-scan?? + } + + if (name && named.get(address) !== name) { + logger.debug(`Discovered device: ${name} (${address})`); + } + named.set(address, name); + + const candidate: DiscoveredDevice = { address, name }; + if (matcher(candidate)) { + await this.stopScan(); + this.device = await adapter.getDevice(address); + return candidate; + } + } + + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)); + } + + await this.stopScan(); + return null; + } + + async stopScan(): Promise { + if (this.adapter && this.scanning) { + await this.adapter.stopDiscovery().catch(() => {}); + this.scanning = false; + } + } + + async connect(address: string): Promise { + if (!this.adapter) { + throw new ConnectionError("Bluetooth adapter not initialized"); + } + + if (!this.device) { + this.device = await this.adapter.getDevice(address); + } + + if (await this.device.isConnected().catch(() => false)) { + await this.device.disconnect().catch(() => {}); + await new Promise((resolve) => setTimeout(resolve, 500)); + } + + await this.device.connect(); + } + + onDisconnect(callback: () => void): void { + this.device?.once("disconnect", callback); + } + + async discoverCharacteristics( + writeUUID: string, + notifyUUID: string, + normalizeUUID: (uuid: string) => string, + ): Promise<{ write: BleCharacteristic; notify: BleCharacteristic }> { + if (!this.device) { + throw new ConnectionError("Not connected to device"); + } + + const gattServer = await this.device.gatt(); + const serviceUuids = await gattServer.services(); + + const normalizedWriteUuid = normalizeUUID(writeUUID); + const normalizedNotifyUuid = normalizeUUID(notifyUUID); + + let writeChar: { char: NodeBle.GattCharacteristic; uuid: string } | null = + null; + let notifyChar: { char: NodeBle.GattCharacteristic; uuid: string } | null = + null; + + for (const serviceUuid of serviceUuids) { + const service = await gattServer.getPrimaryService(serviceUuid); + const charUuids = await service.characteristics(); + + for (const charUuid of charUuids) { + const normalizedCharUuid = normalizeUUID(charUuid); + + if (normalizedCharUuid === normalizedWriteUuid && !writeChar) { + writeChar = { + char: await service.getCharacteristic(charUuid), + uuid: charUuid, + }; + } + if (normalizedCharUuid === normalizedNotifyUuid && !notifyChar) { + notifyChar = { + char: await service.getCharacteristic(charUuid), + uuid: charUuid, + }; + } + } + } + + if (!writeChar || !notifyChar) { + throw new ConnectionError("Could not find required characteristics"); + } + + return { + write: new DBusCharacteristic(writeChar.char, writeChar.uuid), + notify: new DBusCharacteristic(notifyChar.char, notifyChar.uuid), + }; + } + + async disconnect(): Promise { + try { + await this.stopScan(); + + if (this.device) { + this.device.removeAllListeners(); + if (await this.device.isConnected().catch(() => false)) { + await this.device.disconnect().catch(() => {}); + } + this.device = null; + } + + this.destroy?.(); + this.destroy = null; + this.bluetooth = null; + this.adapter = null; + } catch { + // best-effort cleanup + } + } +} diff --git a/src/lib/ble/backends/noble-backend.ts b/src/lib/ble/backends/noble-backend.ts new file mode 100644 index 0000000..419f73c --- /dev/null +++ b/src/lib/ble/backends/noble-backend.ts @@ -0,0 +1,202 @@ +import noble from "@stoprocent/noble"; +import type { Peripheral, Characteristic } from "@stoprocent/noble"; +import { ConnectionError } from "../../utils/errors.ts"; +import { logger } from "../../utils/logger.ts"; +import type { + BleBackend, + BleCharacteristic, + DiscoveredDevice, +} from "../backend.ts"; + +class NobleCharacteristic implements BleCharacteristic { + constructor(private characteristic: Characteristic) {} + + get uuid(): string { + return this.characteristic.uuid; + } + + async write(data: Buffer, withoutResponse: boolean): Promise { + await this.characteristic.writeAsync(data, withoutResponse); + } + + async subscribe(onData: (data: Buffer) => void): Promise { + await this.characteristic.subscribeAsync(); + this.characteristic.on("data", onData); + } + + async unsubscribe(): Promise { + this.characteristic.removeAllListeners(); + await this.characteristic.unsubscribeAsync().catch(() => {}); + } +} + +export class NobleBackend implements BleBackend { + readonly name = "noble"; + + private peripheral: Peripheral | null = null; + private initialized = false; + + async init(): Promise { + if (this.initialized) { + return; + } + + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new ConnectionError("Bluetooth adapter initialization timeout")); + }, 10000); + + const checkState = (state: string) => { + if (state === "poweredOn") { + clearTimeout(timeout); + this.initialized = true; + resolve(); + } else if (state === "poweredOff") { + clearTimeout(timeout); + reject(new ConnectionError("Bluetooth adapter is not powered on")); + } else if (state === "unsupported") { + clearTimeout(timeout); + reject( + new ConnectionError("Bluetooth is not supported on this device"), + ); + } else if (state === "unauthorized") { + clearTimeout(timeout); + reject(new ConnectionError("Bluetooth access not authorized")); + } + }; + + if ((noble as any).state === "poweredOn") { + clearTimeout(timeout); + this.initialized = true; + resolve(); + return; + } + + noble.on("stateChange", checkState); + }); + } + + async scanFor( + matcher: (device: DiscoveredDevice) => boolean, + timeoutMs: number, + ): Promise { + return new Promise((resolve) => { + let found = false; + + const timeoutId = setTimeout(async () => { + if (!found) { + await this.stopScan(); + noble.removeListener("discover", onDiscover); + resolve(null); + } + }, timeoutMs); + + const onDiscover = async (peripheral: Peripheral) => { + const device: DiscoveredDevice = { + address: peripheral.address || peripheral.id, + name: peripheral.advertisement.localName ?? null, + }; + + logger.debug( + `Discovered device: ${device.name ?? "(unnamed)"} (${device.address})`, + ); + + if (matcher(device)) { + found = true; + clearTimeout(timeoutId); + await this.stopScan(); + noble.removeListener("discover", onDiscover); + this.peripheral = peripheral; + resolve(device); + } + }; + + noble.on("discover", onDiscover); + + noble.startScanningAsync([], false).catch((err: Error) => { + clearTimeout(timeoutId); + noble.removeListener("discover", onDiscover); + resolve(null); + }); + }); + } + + async stopScan(): Promise { + await noble.stopScanningAsync().catch(() => {}); + } + + async connect(address: string): Promise { + if (!this.peripheral) { + throw new ConnectionError(`No discovered peripheral for ${address}`); + } + + if ( + this.peripheral.state === "connected" || + this.peripheral.state === "connecting" + ) { + await this.peripheral.disconnectAsync().catch(() => {}); + await new Promise((resolve) => setTimeout(resolve, 500)); + } + + await this.peripheral.connectAsync(); + } + + onDisconnect(callback: () => void): void { + this.peripheral?.once("disconnect", callback); + } + + async discoverCharacteristics( + writeUUID: string, + notifyUUID: string, + normalizeUUID: (uuid: string) => string, + ): Promise<{ write: BleCharacteristic; notify: BleCharacteristic }> { + if (!this.peripheral) { + throw new ConnectionError("Not connected to device"); + } + + const { services } = + await this.peripheral.discoverAllServicesAndCharacteristicsAsync(); + + const normalizedWriteUuid = normalizeUUID(writeUUID); + const normalizedNotifyUuid = normalizeUUID(notifyUUID); + + let writeChar: Characteristic | null = null; + let notifyChar: Characteristic | null = null; + + for (const service of services) { + for (const char of service.characteristics) { + const normalizedCharUuid = normalizeUUID(char.uuid); + if (normalizedCharUuid === normalizedWriteUuid) { + writeChar = char; + } + if (normalizedCharUuid === normalizedNotifyUuid) { + notifyChar = char; + } + } + } + + if (!writeChar || !notifyChar) { + throw new ConnectionError("Could not find required characteristics"); + } + + return { + write: new NobleCharacteristic(writeChar), + notify: new NobleCharacteristic(notifyChar), + }; + } + + async disconnect(): Promise { + try { + if (this.peripheral) { + this.peripheral.removeAllListeners(); + await this.peripheral.disconnectAsync().catch(() => {}); + this.peripheral = null; + } + + noble.removeAllListeners(); + await noble.stopScanningAsync().catch(() => {}); + } catch { + // best-effort cleanup + } + } +} diff --git a/src/lib/ble/ble-client.ts b/src/lib/ble/ble-client.ts index 87bf279..25bd71f 100644 --- a/src/lib/ble/ble-client.ts +++ b/src/lib/ble/ble-client.ts @@ -1,13 +1,20 @@ import { EventEmitter } from "node:events"; EventEmitter.defaultMaxListeners = 20; -import noble from "@stoprocent/noble"; -import type { Peripheral, Characteristic } from "@stoprocent/noble"; import type { BLEConfig, ProtocolConfig } from "../protocol/index.ts"; import { PacketType } from "../protocol/index.ts"; import { DeviceNotFoundError, ConnectionError } from "../utils/errors.ts"; import { PayloadBuilder, ResponseParser } from "../protocol/index.ts"; import { logger, LogEventType } from "../utils/logger.ts"; +import type { BleBackend, BleCharacteristic } from "./backend.ts"; +import { resolveBackendType } from "./backend.ts"; +import { NobleBackend } from "./backends/noble-backend.ts"; +import { DBusBackend } from "./backends/dbus-backend.ts"; + +function createBackend(): BleBackend { + const type = resolveBackendType(); + return type === "dbus" ? new DBusBackend() : new NobleBackend(); +} /** * Handles notifications from the BeamBox device @@ -214,14 +221,15 @@ class NotificationHandler { * Manages BLE connection and data transfer to BeamBox device */ export class BleUploader { - private peripheral: Peripheral | null = null; - private writeCharacteristic: Characteristic | null = null; - private notifyCharacteristic: Characteristic | null = null; + private backend: BleBackend; + private writeCharacteristic: BleCharacteristic | null = null; + private notifyCharacteristic: BleCharacteristic | null = null; private notificationHandler: NotificationHandler; private payloadBuilder: PayloadBuilder; private chunkDelay: number; private verbose: boolean = false; private isInitialized: boolean = false; + private connectedAddress: string | null = null; constructor( private deviceAddress: string | null, @@ -234,50 +242,20 @@ export class BleUploader { this.verbose = verbose; this.notificationHandler = new NotificationHandler(verbose); this.payloadBuilder = new PayloadBuilder(protocolConfig); + this.backend = createBackend(); + logger.debug(`Using BLE backend: ${this.backend.name}`); } /** - * Initialize Bluetooth adapter and wait for powered on state + * Initialize Bluetooth adapter and wait for it to be ready */ private async initBluetooth(): Promise { if (this.isInitialized) { return; } - return new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - reject(new ConnectionError("Bluetooth adapter initialization timeout")); - }, 10000); - - const checkState = (state: string) => { - if (state === "poweredOn") { - clearTimeout(timeout); - this.isInitialized = true; - resolve(); - } else if (state === "poweredOff") { - clearTimeout(timeout); - reject(new ConnectionError("Bluetooth adapter is not powered on")); - } else if (state === "unsupported") { - clearTimeout(timeout); - reject( - new ConnectionError("Bluetooth is not supported on this device"), - ); - } else if (state === "unauthorized") { - clearTimeout(timeout); - reject(new ConnectionError("Bluetooth access not authorized")); - } - }; - - // Check current state first - if ((noble as any).state === "poweredOn") { - clearTimeout(timeout); - this.isInitialized = true; - resolve(); - return; - } - - noble.on("stateChange", checkState); - }); + await this.backend.init(); + this.isInitialized = true; } /** @@ -315,50 +293,26 @@ export class BleUploader { logger.info("Starting device scan...", LogEventType.SCAN_START); - return new Promise((resolve) => { - const timeout = this.bleConfig.scanTimeout * 1000; - let found = false; + const targetName = this.bleConfig.deviceName.toLowerCase(); + const timeout = this.bleConfig.scanTimeout * 1000; - const timeoutId = setTimeout(async () => { - if (!found) { - await noble.stopScanningAsync(); - noble.removeListener("discover", onDiscover); - resolve(null); - } - }, timeout); + const found = await this.backend.scanFor((device) => { + return ( + !!device.name && device.name.toLowerCase().includes(targetName) + ); + }, timeout); - const onDiscover = async (peripheral: Peripheral) => { - const name = peripheral.advertisement.localName; + if (!found) { + return null; + } - if ( - name && - name.toLowerCase().includes(this.bleConfig.deviceName.toLowerCase()) - ) { - found = true; - clearTimeout(timeoutId); - await noble.stopScanningAsync(); - noble.removeListener("discover", onDiscover); + logger.info( + `Found device: ${found.name} (${found.address})`, + LogEventType.DEVICE_FOUND, + { name: found.name, address: found.address }, + ); - const address = peripheral.address || peripheral.id; - logger.info( - `Found device: ${name} (${address})`, - LogEventType.DEVICE_FOUND, - { name, address }, - ); - - this.peripheral = peripheral; - resolve(address); - } - }; - - noble.on("discover", onDiscover); - - noble.startScanningAsync([], false).catch((err: Error) => { - clearTimeout(timeoutId); - logger.error(`Scan error: ${err}`); - resolve(null); - }); - }); + return found.address; } /** @@ -369,7 +323,7 @@ export class BleUploader { try { await this.initBluetooth(); - if (!this.peripheral) { + if (!this.connectedAddress) { if (!this.deviceAddress) { logger.info("Scanning for device...", LogEventType.SCAN_START); const address = await this.findDevice(); @@ -385,74 +339,30 @@ export class BleUploader { LogEventType.SCAN_START, ); - const foundPeripheral = await new Promise( - (resolve) => { - const timeout = this.bleConfig.scanTimeout * 1000; - let found = false; + const targetAddress = this.deviceAddress.toLowerCase(); + const timeout = this.bleConfig.scanTimeout * 1000; - const timeoutId = setTimeout(async () => { - if (!found) { - await noble.stopScanningAsync(); - noble.removeListener("discover", onDiscover); - resolve(null); - } - }, timeout); - - const onDiscover = async (peripheral: Peripheral) => { - const address = peripheral.address || peripheral.id; - if ( - address.toLowerCase() === this.deviceAddress?.toLowerCase() - ) { - found = true; - clearTimeout(timeoutId); - await noble.stopScanningAsync(); - noble.removeListener("discover", onDiscover); - resolve(peripheral); - } - }; - - noble.on("discover", onDiscover); - noble.startScanningAsync([], false).catch(() => { - clearTimeout(timeoutId); - resolve(null); - }); - }, + const found = await this.backend.scanFor( + (device) => device.address.toLowerCase() === targetAddress, + timeout, ); - if (!foundPeripheral) { + if (!found) { throw new DeviceNotFoundError( `Could not find device with address '${this.deviceAddress}'`, ); } - this.peripheral = foundPeripheral; } } - // Stop scanning before connecting - await noble.stopScanningAsync().catch(() => {}); - - // Check peripheral state before connecting - logger.debug( - `Peripheral state before connect: ${this.peripheral!.state}`, - ); - - // If already connected, disconnect first to ensure clean state - if ( - this.peripheral!.state === "connected" || - this.peripheral!.state === "connecting" - ) { - logger.debug( - "Device already connected/connecting, disconnecting first...", - ); - await this.peripheral!.disconnectAsync().catch(() => {}); - await this.sleep(500); // Brief delay after disconnect - } + await this.backend.stopScan(); // Connect to device logger.info("Connecting to device...", LogEventType.CONNECT_START); const connectStartTime = Date.now(); - await this.peripheral!.connectAsync(); + await this.backend.connect(this.deviceAddress!); + this.connectedAddress = this.deviceAddress; const connectDuration = Date.now() - connectStartTime; logger.info( @@ -461,9 +371,9 @@ export class BleUploader { ); // Handle disconnect events - this.peripheral!.once("disconnect", () => { + this.backend.onDisconnect(() => { logger.info("Device disconnected"); - this.peripheral = null; + this.connectedAddress = null; this.writeCharacteristic = null; this.notifyCharacteristic = null; }); @@ -473,10 +383,7 @@ export class BleUploader { // Setup notifications if (this.notifyCharacteristic) { - await this.notifyCharacteristic.subscribeAsync(); - - // Listen for notifications - this.notifyCharacteristic.on("data", (data: Buffer) => { + await this.notifyCharacteristic.subscribe((data: Buffer) => { this.notificationHandler.handleNotification(data); }); } @@ -509,13 +416,6 @@ export class BleUploader { * Discover required characteristics on the device */ private async discoverCharacteristics(): Promise { - if (!this.peripheral) { - throw new ConnectionError("Not connected to device"); - } - - const { services } = - await this.peripheral.discoverAllServicesAndCharacteristicsAsync(); - const normalizedWriteUuid = this.normalizeUUID( this.bleConfig.writeCharacteristicUUID, ); @@ -526,38 +426,25 @@ export class BleUploader { logger.debug(`Looking for write UUID: ${normalizedWriteUuid}`); logger.debug(`Looking for notify UUID: ${normalizedNotifyUuid}`); - // Iterate through services and their characteristics - for (const service of services) { - logger.debug(`Service: ${service.uuid}`); + const { write, notify } = await this.backend.discoverCharacteristics( + this.bleConfig.writeCharacteristicUUID, + this.bleConfig.notifyCharacteristicUUID, + (uuid) => this.normalizeUUID(uuid), + ); - for (const char of service.characteristics) { - const normalizedCharUuid = this.normalizeUUID(char.uuid); - logger.debug( - ` Characteristic: ${char.uuid} (normalized: ${normalizedCharUuid})`, - ); + this.writeCharacteristic = write; + this.notifyCharacteristic = notify; - if (normalizedCharUuid === normalizedWriteUuid) { - this.writeCharacteristic = char; - logger.debug( - `Found write characteristic: ${char.uuid}`, - LogEventType.DISCOVER_CHAR, - { type: "write", uuid: char.uuid }, - ); - } - if (normalizedCharUuid === normalizedNotifyUuid) { - this.notifyCharacteristic = char; - logger.debug( - `Found notify characteristic: ${char.uuid}`, - LogEventType.DISCOVER_CHAR, - { type: "notify", uuid: char.uuid }, - ); - } - } - } - - if (!this.writeCharacteristic || !this.notifyCharacteristic) { - throw new ConnectionError("Could not find required characteristics"); - } + logger.debug( + `Found write characteristic: ${write.uuid}`, + LogEventType.DISCOVER_CHAR, + { type: "write", uuid: write.uuid }, + ); + logger.debug( + `Found notify characteristic: ${notify.uuid}`, + LogEventType.DISCOVER_CHAR, + { type: "notify", uuid: notify.uuid }, + ); } /** @@ -566,16 +453,13 @@ export class BleUploader { public async disconnect(): Promise { try { if (this.notifyCharacteristic) { - this.notifyCharacteristic.removeAllListeners(); - await this.notifyCharacteristic.unsubscribeAsync().catch(() => {}); - } - if (this.peripheral) { - this.peripheral.removeAllListeners(); - await this.peripheral.disconnectAsync().catch(() => {}); + await this.notifyCharacteristic.unsubscribe(); } - noble.removeAllListeners(); - await noble.stopScanningAsync().catch(() => {}); + await this.backend.disconnect(); + this.connectedAddress = null; + this.writeCharacteristic = null; + this.notifyCharacteristic = null; } catch (error) { logger.warning(`Error during disconnect: ${error}`); } @@ -618,7 +502,7 @@ export class BleUploader { this.notificationHandler.logSentPacket(packet, "Image info packet"); // Write without response - await this.writeCharacteristic.writeAsync(packet, true); + await this.writeCharacteristic.write(packet, true); await this.sleep(this.protocolConfig.imageInfoDelay * 1000); } @@ -696,7 +580,7 @@ export class BleUploader { } // Write without response - await this.writeCharacteristic.writeAsync(packet, true); + await this.writeCharacteristic.write(packet, true); if (this.notificationHandler.errorFlag) { logger.error("Device error flag set; aborting send.");