From 05c625e6306aeb3798f3d069adbed216ad5a56ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 11:37:48 +0000 Subject: [PATCH 01/25] Update dependency @oxc-node/core to ^0.0.32 (#24) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 214 +++++++++++++++++++++++++++---------------------- 2 files changed, 118 insertions(+), 98 deletions(-) diff --git a/package.json b/package.json index 1ab60be..2b8636d 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "license": "MIT", "devDependencies": { "@napi-rs/cli": "^3.0.4", - "@oxc-node/core": "^0.0.23", + "@oxc-node/core": "^0.0.32", "oxlint": "^0.16.0" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e30d840..ae7b1cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.0.4(@emnapi/runtime@1.4.5) + version: 3.0.4(@emnapi/runtime@1.5.0) '@oxc-node/core': - specifier: ^0.0.23 - version: 0.0.23 + specifier: ^0.0.32 + version: 0.0.32 oxlint: specifier: ^0.16.0 version: 0.16.12 @@ -30,24 +30,24 @@ importers: packages: - '@emnapi/core@1.4.3': - resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} - '@emnapi/core@1.4.5': resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - '@emnapi/runtime@1.4.3': - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@emnapi/core@1.5.0': + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} - '@emnapi/wasi-threads@1.0.2': - resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + '@emnapi/runtime@1.5.0': + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} '@emnapi/wasi-threads@1.0.4': resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@inquirer/checkbox@4.1.8': resolution: {integrity: sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==} engines: {node: '>=18'} @@ -415,6 +415,9 @@ packages: '@napi-rs/wasm-runtime@1.0.1': resolution: {integrity: sha512-KVlQ/jgywZpixGCKMNwxStmmbYEMyokZpCf2YuIChhfJA2uqfAKNEM8INz7zzTo55iEXfBhIIs3VqYyqzDLj8g==} + '@napi-rs/wasm-runtime@1.0.7': + resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@napi-rs/wasm-tools-android-arm-eabi@1.0.0': resolution: {integrity: sha512-Ks0hplmrYatIjSi8XeTObCi0x13AOQD41IQXpBjrz+UK71gDkbxyLWO7B/ckuels3mC1DW3OCQCv+q0lPnaG/A==} engines: {node: '>= 10'} @@ -548,92 +551,93 @@ packages: '@octokit/types@14.1.0': resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} - '@oxc-node/core-android-arm-eabi@0.0.23': - resolution: {integrity: sha512-KVPR2HZ9mYOxdgoDM59ckz8TxeH72CRcdnFu2yOxDyJRwRSz64jCCIZxcgc2PQ7dFpU8r0S71ay+R0QKWs8Qbg==} + '@oxc-node/core-android-arm-eabi@0.0.32': + resolution: {integrity: sha512-Ykkz+xYJ1Hd+vjVSXljyIFRW/ZRMp2tQfPy9T2jj9F2pm5CAchqJHSXEbB3FbhdUXusUqhWLmu70JdVhS4SBcQ==} cpu: [arm] os: [android] - '@oxc-node/core-android-arm64@0.0.23': - resolution: {integrity: sha512-s1517VgPasE22bqEizOKs+c4O0zOAgLXsWPtHrTq8XAZbhKf7eVJyLtZRbnKYD7WTPWb1o3IaGfsglF0JQQd/Q==} + '@oxc-node/core-android-arm64@0.0.32': + resolution: {integrity: sha512-csPEZPGTlPtkoMnDeG+hrYX2AJIh8dPKW7TW5E0MdNMIkJ8aFIymBH2QF+xSMsFl9Gpbl5ZxYLkRIrth+Mhzhg==} cpu: [arm64] os: [android] - '@oxc-node/core-darwin-arm64@0.0.23': - resolution: {integrity: sha512-wo/ZugfeFMX6/+KnZIfWsA9jezBqFWjZnuEiv3D/tesRI1j3vxxPj23TXJNF25uBaM9IzQQHFeBf9Td01gLLIg==} + '@oxc-node/core-darwin-arm64@0.0.32': + resolution: {integrity: sha512-wlURG+gBge3ovdBtMQ/KvyFsLVXnQ4h5vlIxBYMCTkwCzwvfXbcSOLLZMxypOeXPlH/cdVqOigvh9XBbc3KAfg==} cpu: [arm64] os: [darwin] - '@oxc-node/core-darwin-x64@0.0.23': - resolution: {integrity: sha512-JWa1PF+lK31PO1QyjD6L3MsiXA796YjiwDumb9vikwqZJbCav1YEJvY43BzSR7AvnosWg8gNTNJAk03emWak/w==} + '@oxc-node/core-darwin-x64@0.0.32': + resolution: {integrity: sha512-tFlUz54cemNp6N7+suP+uwCXErzol7ibMslxOHbXtGWwRVckV3Bb1rQyCajFSQYCr/du1ZdDCVsTfuPmXQlejg==} cpu: [x64] os: [darwin] - '@oxc-node/core-freebsd-x64@0.0.23': - resolution: {integrity: sha512-F3/xYyv//61puQN95VRQfyFRHQ6DhObd2q54/h4yP4ioKhFfErEN2pspZzXu2S0szfxN0oYT52M8uJB9mz2/lQ==} + '@oxc-node/core-freebsd-x64@0.0.32': + resolution: {integrity: sha512-yqikvHq0VbnPasRwOkDiMe5dhLZexvZSBzNroBVGbMWNaHBvkP+GP4EFZ3Y5pcNPC3og3xP4J6+N8bbbEZk3vg==} cpu: [x64] os: [freebsd] - '@oxc-node/core-linux-arm-gnueabihf@0.0.23': - resolution: {integrity: sha512-WyaCm9uIYA5CyvVRNNDlyRhPz3OKAhK77OjshQ3ACaarTui3cQ1GeSBxxpPiEmMdWr3SEA7n28ynvrXsPzkzvw==} + '@oxc-node/core-linux-arm-gnueabihf@0.0.32': + resolution: {integrity: sha512-Qbv937NEH4gNNC1W3Lx6G4Mh5mETMYSf2jbTxCzcfng74BVorpQd0pKB72bvEA0RQtIkXoEfCW24VeyR3yA84Q==} cpu: [arm] os: [linux] - '@oxc-node/core-linux-arm64-gnu@0.0.23': - resolution: {integrity: sha512-x/KFcQbHhTFzKGRDE/eL7LdkeZU9BmclxlKugYbsJhUYr4pRA6GKThTEz7vFYm7CWlMxzhq8IgKWwHfm1T0BKg==} + '@oxc-node/core-linux-arm64-gnu@0.0.32': + resolution: {integrity: sha512-w+6SmMWEaVap5RC9axCvg1ZOFdQsNLlLYrYrKX5siZvcVs6jPNyg3O9rbO85tBFPvuAvSLr66mBJwW70MQJv0w==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-arm64-musl@0.0.23': - resolution: {integrity: sha512-ujsdd24zJzYqshzuqjSFZIWT8KZI9PWKI8m36qbdeE4TbKSlGAaJbbMwA/RS2ZfzHFhNCLDAaQxX6N2llfgPCQ==} + '@oxc-node/core-linux-arm64-musl@0.0.32': + resolution: {integrity: sha512-AZeVCYaECJbQaj6bxCZK77ApbAQUKNOq4wWoRIkVZnn9/ay5wqHLmkvWdOku0aw2WkGiteLp5nCXSDZjw1g0/A==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-ppc64-gnu@0.0.23': - resolution: {integrity: sha512-MjwbpDIPSRpihK/VTvhBeRKJCXKY0x9PRGFeUEBYOHmaZmX7YEJvJViqJHrDu7ZttRmHwPwumrdN71skDnEqFw==} + '@oxc-node/core-linux-ppc64-gnu@0.0.32': + resolution: {integrity: sha512-sz8r3BPLWZC5vZ/5UCb2MhcEFT8bRIeo3IFnksh6K9umAyjgByxnBZP/EyL4twcjQqbrDC64Ox0Pm5vtTIiFWw==} cpu: [ppc64] os: [linux] - '@oxc-node/core-linux-s390x-gnu@0.0.23': - resolution: {integrity: sha512-UFwpqXY8ESq0S1UQLOV+i0qq+8b2Rr39fqVNOxcLDwRpCKF8EGbZyO2byJljci1+zAPK8Bl9mXpwwVLMs+TctA==} + '@oxc-node/core-linux-s390x-gnu@0.0.32': + resolution: {integrity: sha512-YLpDVEcsvj03z6SqqcxA1J+ocTR+pP6dv0oIrGXaATwQtx0C+nt6WrVESaXjJpQDAc/5I+LkVDlimeAJb4iLNQ==} cpu: [s390x] os: [linux] - '@oxc-node/core-linux-x64-gnu@0.0.23': - resolution: {integrity: sha512-fm91kTpC6f2BxgPm3Z4As8V3xtH34jvxcv1/ZQMtC2ZXDIMrPdYAd8/CbGUni4FhaEMp0GwBGqYllNj9AWX3Iw==} + '@oxc-node/core-linux-x64-gnu@0.0.32': + resolution: {integrity: sha512-FCBaQq4Y08AOLvl83AVzGeRAp/7RI49sDb44sE3/XzxdAVHYyhp0wA84h/NBi8Cj8XhSJdr6KosskHl1cVB0Qg==} cpu: [x64] os: [linux] - '@oxc-node/core-linux-x64-musl@0.0.23': - resolution: {integrity: sha512-b+OF7y4yHyCzJC2cmnSeFzdTyTdlYHk9K5xHbm3Z+mUqW8D6Gww72yF7SGPcEMEGaktieRJoJeVEfn9uOeFebw==} + '@oxc-node/core-linux-x64-musl@0.0.32': + resolution: {integrity: sha512-QKvj6d7VGKK3udW8TXfB0NYNjCloKxZznl58eaoFMoO+bOwuOWJX/8tN37FjkghH4Sb38vRK24+BdqebAHjBdA==} cpu: [x64] os: [linux] - '@oxc-node/core-wasm32-wasi@0.0.23': - resolution: {integrity: sha512-aJZI9wDI5eBDYdDQ3TqYnq6aJ0gfCgU2062QHpO7HDkCX/SRbw4bpxAfArbQz1vPS3mFkOSVx5L4vKaNRvaZVQ==} + '@oxc-node/core-openharmony-arm64@0.0.32': + resolution: {integrity: sha512-k8wqQZ04J4l44v6iB7VFVNc+tz0BBJV2nxSwhLTHpciAFZnOG4BJUqw+2OsObUreR3z5zarebkVFyEJ3QaUH5g==} + cpu: [arm64] + os: [openharmony] + + '@oxc-node/core-wasm32-wasi@0.0.32': + resolution: {integrity: sha512-O8Bj67iC0lm0xSlpmHseU+tQytrqdhDFUc0MzYmPSvs0i60u3CNGiw/BWuO6xDpBfhp/IQkWSGBrecZZt1hMFg==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-node/core-win32-arm64-msvc@0.0.23': - resolution: {integrity: sha512-yLpb7Z9BQJmXicu305/rC5eGjy/R7j4AWuerNYQuKRqryjsOhjD6J0nnwlOj+qYGG/U+yWdP5r9hg+OHBzcQ4A==} + '@oxc-node/core-win32-arm64-msvc@0.0.32': + resolution: {integrity: sha512-mGFu9B3E/jBqvy6FzTZHjUZUOOst1dnN/LIX1Bi8wbSrB+1TdOBykOcNJ3F+BppdaTCWqKb6ieLU6BvvnxboaA==} cpu: [arm64] os: [win32] - '@oxc-node/core-win32-ia32-msvc@0.0.23': - resolution: {integrity: sha512-nVnzvQC0y7gUQWRa48eJUzKyaEFRRiRtKhoWoXCfFe1LzAWNKppyFwzmt8kwlsmJFjqnl4RpjNPk+HIHnNE1Hw==} + '@oxc-node/core-win32-ia32-msvc@0.0.32': + resolution: {integrity: sha512-JEk4P/c/x6T4MHPBtty7IdCx/hxqhdhLrrJ0pIQ8Ue1Kkx74Aq6NDPg6TWtHAxmn+4cw6c1TLzGPXW+1dwbFcA==} cpu: [ia32] os: [win32] - '@oxc-node/core-win32-x64-msvc@0.0.23': - resolution: {integrity: sha512-S88EHX7n3WISr+yCaQ7pyTVSI0ESOCZKfuWz882F5ubQjP6OxqCigdEg3ddJ9PUF4xEgDRLBqxn14/scBf8gDQ==} + '@oxc-node/core-win32-x64-msvc@0.0.32': + resolution: {integrity: sha512-6G0YmfxjD3Ec8G619VXfJ3luryJb1Fq649H8ZcfLO8810WLwtzZiAXZCsCLs8lPsLTEpTeFR+AWuc8v4IRHekg==} cpu: [x64] os: [win32] - '@oxc-node/core@0.0.23': - resolution: {integrity: sha512-1UyURTZf97mu/HEcZNopd1SMJ7sz4zdXwN6r205tMeLOdBHLH9Ljphpvfy5fh03pccxXYYrq1YxO2HLgDKgJ8A==} - - '@oxc-project/runtime@0.62.0': - resolution: {integrity: sha512-l6nPv12hDRhJnE3IPxzLjWpACpIQYUQFO8tSax6ky61+FJsy+uOAehZWugirfJWN0Pvc2gtXcHpwaOOtP5y4tA==} - engines: {node: '>=6.9.0'} + '@oxc-node/core@0.0.32': + resolution: {integrity: sha512-2lbEquSd7qU5SZwbu2ngxs/vaa5sgRB5FE6TSPIPp6wfy7+11M0OrzD3g9TxH5CcsawecF2pC8nNpRVjBgBhOg==} '@oxlint/darwin-arm64@0.16.12': resolution: {integrity: sha512-G7phYhlIA4ke2nW7tHLl+E5+rvdzgGA6830D+e+y1RGllT0w2ONGdKcVTj+2pXGCw6yPmCC5fDsDEn2+RPTfxg==} @@ -696,6 +700,9 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -868,20 +875,15 @@ packages: snapshots: - '@emnapi/core@1.4.3': - dependencies: - '@emnapi/wasi-threads': 1.0.2 - tslib: 2.8.1 - optional: true - '@emnapi/core@1.4.5': dependencies: '@emnapi/wasi-threads': 1.0.4 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.3': + '@emnapi/core@1.5.0': dependencies: + '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true @@ -890,7 +892,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.0.2': + '@emnapi/runtime@1.5.0': dependencies: tslib: 2.8.1 optional: true @@ -900,6 +902,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + '@inquirer/checkbox@4.1.8': dependencies: '@inquirer/core': 10.1.13 @@ -990,7 +997,7 @@ snapshots: '@inquirer/type@3.0.7': {} - '@napi-rs/cli@3.0.4(@emnapi/runtime@1.4.5)': + '@napi-rs/cli@3.0.4(@emnapi/runtime@1.5.0)': dependencies: '@inquirer/prompts': 7.5.3 '@napi-rs/cross-toolchain': 1.0.0 @@ -1005,7 +1012,7 @@ snapshots: semver: 7.7.2 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.5.0 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -1168,8 +1175,8 @@ snapshots: '@napi-rs/wasm-runtime@0.2.11': dependencies: - '@emnapi/core': 1.4.3 - '@emnapi/runtime': 1.4.3 + '@emnapi/core': 1.4.5 + '@emnapi/runtime': 1.4.5 '@tybys/wasm-util': 0.9.0 optional: true @@ -1180,6 +1187,13 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true + '@napi-rs/wasm-runtime@1.0.7': + dependencies: + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 + '@tybys/wasm-util': 0.10.1 + optional: true + '@napi-rs/wasm-tools-android-arm-eabi@1.0.0': optional: true @@ -1299,79 +1313,80 @@ snapshots: dependencies: '@octokit/openapi-types': 25.1.0 - '@oxc-node/core-android-arm-eabi@0.0.23': + '@oxc-node/core-android-arm-eabi@0.0.32': optional: true - '@oxc-node/core-android-arm64@0.0.23': + '@oxc-node/core-android-arm64@0.0.32': optional: true - '@oxc-node/core-darwin-arm64@0.0.23': + '@oxc-node/core-darwin-arm64@0.0.32': optional: true - '@oxc-node/core-darwin-x64@0.0.23': + '@oxc-node/core-darwin-x64@0.0.32': optional: true - '@oxc-node/core-freebsd-x64@0.0.23': + '@oxc-node/core-freebsd-x64@0.0.32': optional: true - '@oxc-node/core-linux-arm-gnueabihf@0.0.23': + '@oxc-node/core-linux-arm-gnueabihf@0.0.32': optional: true - '@oxc-node/core-linux-arm64-gnu@0.0.23': + '@oxc-node/core-linux-arm64-gnu@0.0.32': optional: true - '@oxc-node/core-linux-arm64-musl@0.0.23': + '@oxc-node/core-linux-arm64-musl@0.0.32': optional: true - '@oxc-node/core-linux-ppc64-gnu@0.0.23': + '@oxc-node/core-linux-ppc64-gnu@0.0.32': optional: true - '@oxc-node/core-linux-s390x-gnu@0.0.23': + '@oxc-node/core-linux-s390x-gnu@0.0.32': optional: true - '@oxc-node/core-linux-x64-gnu@0.0.23': + '@oxc-node/core-linux-x64-gnu@0.0.32': optional: true - '@oxc-node/core-linux-x64-musl@0.0.23': + '@oxc-node/core-linux-x64-musl@0.0.32': optional: true - '@oxc-node/core-wasm32-wasi@0.0.23': + '@oxc-node/core-openharmony-arm64@0.0.32': + optional: true + + '@oxc-node/core-wasm32-wasi@0.0.32': dependencies: - '@napi-rs/wasm-runtime': 0.2.11 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@oxc-node/core-win32-arm64-msvc@0.0.23': + '@oxc-node/core-win32-arm64-msvc@0.0.32': optional: true - '@oxc-node/core-win32-ia32-msvc@0.0.23': + '@oxc-node/core-win32-ia32-msvc@0.0.32': optional: true - '@oxc-node/core-win32-x64-msvc@0.0.23': + '@oxc-node/core-win32-x64-msvc@0.0.32': optional: true - '@oxc-node/core@0.0.23': + '@oxc-node/core@0.0.32': dependencies: - '@oxc-project/runtime': 0.62.0 pirates: 4.0.7 optionalDependencies: - '@oxc-node/core-android-arm-eabi': 0.0.23 - '@oxc-node/core-android-arm64': 0.0.23 - '@oxc-node/core-darwin-arm64': 0.0.23 - '@oxc-node/core-darwin-x64': 0.0.23 - '@oxc-node/core-freebsd-x64': 0.0.23 - '@oxc-node/core-linux-arm-gnueabihf': 0.0.23 - '@oxc-node/core-linux-arm64-gnu': 0.0.23 - '@oxc-node/core-linux-arm64-musl': 0.0.23 - '@oxc-node/core-linux-ppc64-gnu': 0.0.23 - '@oxc-node/core-linux-s390x-gnu': 0.0.23 - '@oxc-node/core-linux-x64-gnu': 0.0.23 - '@oxc-node/core-linux-x64-musl': 0.0.23 - '@oxc-node/core-wasm32-wasi': 0.0.23 - '@oxc-node/core-win32-arm64-msvc': 0.0.23 - '@oxc-node/core-win32-ia32-msvc': 0.0.23 - '@oxc-node/core-win32-x64-msvc': 0.0.23 - - '@oxc-project/runtime@0.62.0': {} + '@oxc-node/core-android-arm-eabi': 0.0.32 + '@oxc-node/core-android-arm64': 0.0.32 + '@oxc-node/core-darwin-arm64': 0.0.32 + '@oxc-node/core-darwin-x64': 0.0.32 + '@oxc-node/core-freebsd-x64': 0.0.32 + '@oxc-node/core-linux-arm-gnueabihf': 0.0.32 + '@oxc-node/core-linux-arm64-gnu': 0.0.32 + '@oxc-node/core-linux-arm64-musl': 0.0.32 + '@oxc-node/core-linux-ppc64-gnu': 0.0.32 + '@oxc-node/core-linux-s390x-gnu': 0.0.32 + '@oxc-node/core-linux-x64-gnu': 0.0.32 + '@oxc-node/core-linux-x64-musl': 0.0.32 + '@oxc-node/core-openharmony-arm64': 0.0.32 + '@oxc-node/core-wasm32-wasi': 0.0.32 + '@oxc-node/core-win32-arm64-msvc': 0.0.32 + '@oxc-node/core-win32-ia32-msvc': 0.0.32 + '@oxc-node/core-win32-x64-msvc': 0.0.32 '@oxlint/darwin-arm64@0.16.12': optional: true @@ -1411,6 +1426,11 @@ snapshots: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 From 8e27693ed0d625419beadedbabf775617673dea4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 12 Oct 2025 02:39:43 +0000 Subject: [PATCH 02/25] Update dependency @platformatic/python-node-darwin-arm64 to v0.1.10 (#25) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae7b1cb..7c8773c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,7 +20,7 @@ importers: optionalDependencies: '@platformatic/python-node-darwin-arm64': specifier: ^0.1.4 - version: 0.1.4 + version: 0.1.10 '@platformatic/python-node-darwin-x64': specifier: ^0.1.4 version: 0.1.4 @@ -679,8 +679,8 @@ packages: cpu: [x64] os: [win32] - '@platformatic/python-node-darwin-arm64@0.1.4': - resolution: {integrity: sha512-6L7GhZN3wKS8TpwpRF8JfM2+wi5eMPrYfzh6q2uDQnQ0WDH0a2p0iCoovYNPR9oy/e9Y8SDCYSJ1iXwrPToB2w==} + '@platformatic/python-node-darwin-arm64@0.1.10': + resolution: {integrity: sha512-FbvvFc1DcGn9MbiyPJ2zsAYzuESMiO49443wI383Liebb/HaIO32Y+E7JsM5tmf6A2larvRWoO4HprtjbZSUmA==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] @@ -1412,7 +1412,7 @@ snapshots: '@oxlint/win32-x64@0.16.12': optional: true - '@platformatic/python-node-darwin-arm64@0.1.4': + '@platformatic/python-node-darwin-arm64@0.1.10': optional: true '@platformatic/python-node-darwin-x64@0.1.4': From 80c849041de37b9b9cd0bbbe4aa5f522b9baeb58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Oct 2025 05:58:01 +0000 Subject: [PATCH 03/25] Update dependency @platformatic/python-node-linux-x64-gnu to v0.1.10 (#28) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c8773c..1d8b581 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,7 +26,7 @@ importers: version: 0.1.4 '@platformatic/python-node-linux-x64-gnu': specifier: ^0.1.4 - version: 0.1.4 + version: 0.1.10 packages: @@ -691,8 +691,8 @@ packages: cpu: [x64] os: [darwin] - '@platformatic/python-node-linux-x64-gnu@0.1.4': - resolution: {integrity: sha512-qwZIN6nBVYBQphkTxuyuwaJx7OyxswzCmWVekgsfI7RGAMh6eXwtajBRqTTB0XhZ4eht2G3SUYo/xvM6QIUzeA==} + '@platformatic/python-node-linux-x64-gnu@0.1.10': + resolution: {integrity: sha512-raqvdM6W74qa/m6qjhr2OV0dPyt5VVmFD/e/X/wZllR3iDtpO/D7c5VQJ4HsY166VmYA7ffOGBoNh8luV1Gdng==} engines: {node: '>= 20'} cpu: [x64] os: [linux] @@ -1418,7 +1418,7 @@ snapshots: '@platformatic/python-node-darwin-x64@0.1.4': optional: true - '@platformatic/python-node-linux-x64-gnu@0.1.4': + '@platformatic/python-node-linux-x64-gnu@0.1.10': optional: true '@tybys/wasm-util@0.10.0': From 13fb93c56eafbb929857ab6bcee5efd97b49b5cd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Oct 2025 10:38:15 +0000 Subject: [PATCH 04/25] Lock file maintenance (#27) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 217 +++-------- pnpm-lock.yaml | 961 ++++++++++++++++++++++--------------------------- 2 files changed, 474 insertions(+), 704 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1183d49..8cd1de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -84,7 +75,7 @@ checksum = "2f24bcf6fb87a8db3f69b7050bd1ca7a55d91bf2f07caf7c54f27c97af87fb67" dependencies = [ "clap", "goblin", - "object 0.36.7", + "object", "scroll", "thiserror", ] @@ -106,21 +97,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object 0.37.3", - "rustc-demangle", - "windows-link", -] - [[package]] name = "bitflags" version = "2.9.4" @@ -135,15 +111,15 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", "clap_derive", @@ -151,9 +127,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstream", "anstyle", @@ -163,9 +139,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -175,9 +151,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" @@ -358,12 +334,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "goblin" version = "0.9.3" @@ -410,7 +380,7 @@ dependencies = [ [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#5a4f58c43dac33e4994918024766ec7d5ab7cc06" +source = "git+https://github.com/platformatic/http-handler#b32e0e1f529b28785623d93806775df3b3eb3201" dependencies = [ "async-trait", "bytes", @@ -423,7 +393,7 @@ dependencies = [ [[package]] name = "http-rewriter" version = "1.0.0" -source = "git+https://github.com/platformatic/http-rewriter#7bc755877b25ee09f995f5a63df8b0493bcfb67f" +source = "git+https://github.com/platformatic/http-rewriter#d31cd99f759bf15fa4d441e31b920bcc09c2ac2d" dependencies = [ "bytes", "http", @@ -436,9 +406,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -450,17 +420,6 @@ version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -475,9 +434,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" @@ -531,13 +490,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -617,15 +576,6 @@ dependencies = [ "ruzstd", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -806,9 +756,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -818,9 +768,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -829,15 +779,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" - -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustc-hash" @@ -915,12 +859,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -974,29 +918,26 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -1049,38 +990,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows-link", ] [[package]] @@ -1090,106 +1015,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - [[package]] name = "windows_x86_64_msvc" version = "0.53.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d8b581..8a1b314 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.0.4(@emnapi/runtime@1.5.0) + version: 3.3.1(@emnapi/runtime@1.5.0) '@oxc-node/core': specifier: ^0.0.32 version: 0.0.32 @@ -23,33 +23,37 @@ importers: version: 0.1.10 '@platformatic/python-node-darwin-x64': specifier: ^0.1.4 - version: 0.1.4 + version: 0.1.10 '@platformatic/python-node-linux-x64-gnu': specifier: ^0.1.4 version: 0.1.10 packages: - '@emnapi/core@1.4.5': - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - '@emnapi/core@1.5.0': resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} - '@emnapi/runtime@1.4.5': - resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} - '@emnapi/runtime@1.5.0': resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} - '@emnapi/wasi-threads@1.0.4': - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} - '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@inquirer/checkbox@4.1.8': - resolution: {integrity: sha512-d/QAsnwuHX2OPolxvYcgSj7A9DO9H6gVOy2DvBTx+P2LH2iRTo/RSGV3iwCzW024nP9hw98KIuDmdyhZQj1UQg==} + '@inquirer/ansi@1.0.1': + resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.3.0': + resolution: {integrity: sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.19': + resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -57,8 +61,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.12': - resolution: {integrity: sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==} + '@inquirer/core@10.3.0': + resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -66,8 +70,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.1.13': - resolution: {integrity: sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==} + '@inquirer/editor@4.2.21': + resolution: {integrity: sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -75,8 +79,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.13': - resolution: {integrity: sha512-WbicD9SUQt/K8O5Vyk9iC2ojq5RHoCLK6itpp2fHsWe44VxxcA9z3GTWlvjSTGmMQpZr+lbVmrxdHcumJoLbMA==} + '@inquirer/expand@4.0.21': + resolution: {integrity: sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -84,8 +88,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.15': - resolution: {integrity: sha512-4Y+pbr/U9Qcvf+N/goHzPEXiHH8680lM3Dr3Y9h9FFw4gHS+zVpbj8LfbKWIb/jayIB4aSO4pWiBTrBYWkvi5A==} + '@inquirer/external-editor@1.0.2': + resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -93,12 +97,12 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.12': - resolution: {integrity: sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==} + '@inquirer/figures@1.0.14': + resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} engines: {node: '>=18'} - '@inquirer/input@4.1.12': - resolution: {integrity: sha512-xJ6PFZpDjC+tC1P8ImGprgcsrzQRsUh9aH3IZixm1lAZFK49UGHxM3ltFfuInN2kPYNfyoPRh+tU4ftsjPLKqQ==} + '@inquirer/input@4.2.5': + resolution: {integrity: sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -106,8 +110,8 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.15': - resolution: {integrity: sha512-xWg+iYfqdhRiM55MvqiTCleHzszpoigUpN5+t1OMcRkJrUrw7va3AzXaxvS+Ak7Gny0j2mFSTv2JJj8sMtbV2g==} + '@inquirer/number@3.0.21': + resolution: {integrity: sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -115,8 +119,8 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.15': - resolution: {integrity: sha512-75CT2p43DGEnfGTaqFpbDC2p2EEMrq0S+IRrf9iJvYreMy5mAWj087+mdKyLHapUEPLjN10mNvABpGbk8Wdraw==} + '@inquirer/password@4.0.21': + resolution: {integrity: sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -124,8 +128,8 @@ packages: '@types/node': optional: true - '@inquirer/prompts@7.5.3': - resolution: {integrity: sha512-8YL0WiV7J86hVAxrh3fE5mDCzcTDe1670unmJRz6ArDgN+DBK1a0+rbnNWp4DUB5rPMwqD5ZP6YHl9KK1mbZRg==} + '@inquirer/prompts@7.9.0': + resolution: {integrity: sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -133,8 +137,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.3': - resolution: {integrity: sha512-7XrV//6kwYumNDSsvJIPeAqa8+p7GJh7H5kRuxirct2cgOcSWwwNGoXDRgpNFbY/MG2vQ4ccIWCi8+IXXyFMZA==} + '@inquirer/rawlist@4.1.9': + resolution: {integrity: sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -142,8 +146,8 @@ packages: '@types/node': optional: true - '@inquirer/search@3.0.15': - resolution: {integrity: sha512-YBMwPxYBrADqyvP4nNItpwkBnGGglAvCLVW8u4pRmmvOsHUtCAUIMbUrLX5B3tFL1/WsLGdQ2HNzkqswMs5Uaw==} + '@inquirer/search@3.2.0': + resolution: {integrity: sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -151,8 +155,8 @@ packages: '@types/node': optional: true - '@inquirer/select@4.2.3': - resolution: {integrity: sha512-OAGhXU0Cvh0PhLz9xTF/kx6g6x+sP+PcyTiLvCrewI99P3BBeexD+VbuwkNDvqGkk3y2h5ZiWLeRP7BFlhkUDg==} + '@inquirer/select@4.4.0': + resolution: {integrity: sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -160,8 +164,8 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.7': - resolution: {integrity: sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==} + '@inquirer/type@3.0.9': + resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -169,357 +173,360 @@ packages: '@types/node': optional: true - '@napi-rs/cli@3.0.4': - resolution: {integrity: sha512-ilbCI69DVDQcIUSUB504LM1+Nhvo0jKycWAzzPJ22YwUoWrru/w0+V5sfjPINgkshQ4Ykv+oZOJXk9Kg1ZBUvg==} + '@napi-rs/cli@3.3.1': + resolution: {integrity: sha512-KVO9tLhtOtDc8iMUJYRkj6WZcYmV6+fhXbLa1Qstrm6ZQa9McIsqjFH7PLx3BnEWwejjJrenrCX5JENwl0MpKg==} engines: {node: '>= 16'} hasBin: true peerDependencies: - '@emnapi/runtime': ^1.1.0 - emnapi: ^1.1.0 + '@emnapi/runtime': ^1.5.0 peerDependenciesMeta: '@emnapi/runtime': optional: true - emnapi: - optional: true - '@napi-rs/cross-toolchain@1.0.0': - resolution: {integrity: sha512-5Ha9SkZC8NjLB4Xe6C9v+3c+Oraz9FdbuN2L4d/mh1kTK8Y/zGt5geM/U+sboAP3HoK2aRWRnx4GK0eV3oPoUQ==} + '@napi-rs/cross-toolchain@1.0.3': + resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==} peerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.0 - '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.0 - '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.0 - '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.0 - '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.0 - '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.0 + '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.3 peerDependenciesMeta: '@napi-rs/cross-toolchain-arm64-target-aarch64': optional: true '@napi-rs/cross-toolchain-arm64-target-armv7': optional: true + '@napi-rs/cross-toolchain-arm64-target-ppc64le': + optional: true + '@napi-rs/cross-toolchain-arm64-target-s390x': + optional: true '@napi-rs/cross-toolchain-arm64-target-x86_64': optional: true '@napi-rs/cross-toolchain-x64-target-aarch64': optional: true '@napi-rs/cross-toolchain-x64-target-armv7': optional: true + '@napi-rs/cross-toolchain-x64-target-ppc64le': + optional: true + '@napi-rs/cross-toolchain-x64-target-s390x': + optional: true '@napi-rs/cross-toolchain-x64-target-x86_64': optional: true - '@napi-rs/lzma-android-arm-eabi@1.4.3': - resolution: {integrity: sha512-XpjRUZ/EbWtVbMvW+ucon5Ykz7PjMoX65mIlUdAiVnaPGykzFAUrl8dl6Br5bfqnhQQfDjjUIgTAwWl3G++n1g==} + '@napi-rs/lzma-android-arm-eabi@1.4.5': + resolution: {integrity: sha512-Up4gpyw2SacmyKWWEib06GhiDdF+H+CCU0LAV8pnM4aJIDqKKd5LHSlBht83Jut6frkB0vwEPmAkv4NjQ5u//Q==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/lzma-android-arm64@1.4.3': - resolution: {integrity: sha512-Bve6BF/4pnlO6HotIgRWgmUT3rbbW/QH471RF/GBA29GfEeUOPEdfQWC7tlzrLYsVFNX2KCWKd+XlxQNz9sRaA==} + '@napi-rs/lzma-android-arm64@1.4.5': + resolution: {integrity: sha512-uwa8sLlWEzkAM0MWyoZJg0JTD3BkPknvejAFG2acUA1raXM8jLrqujWCdOStisXhqQjZ2nDMp3FV6cs//zjfuQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/lzma-darwin-arm64@1.4.3': - resolution: {integrity: sha512-UxTb56kL6pSVTsZ1ShibnqLSwJZLTWtPU5TNYuyIjVNQYAIG8JQ5Yxz35azjwBCK7AjD8pBdpWLYUSyJRGAVAw==} + '@napi-rs/lzma-darwin-arm64@1.4.5': + resolution: {integrity: sha512-0Y0TQLQ2xAjVabrMDem1NhIssOZzF/y/dqetc6OT8mD3xMTDtF8u5BqZoX3MyPc9FzpsZw4ksol+w7DsxHrpMA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/lzma-darwin-x64@1.4.3': - resolution: {integrity: sha512-ps6HiwGKS1P4ottyV2/hVboZ0ugdM1Z1qO9YFpcuKweORfxAkxwJ6S8jOt7G27LQiWiiQHVwsUCODTHDFhOUPQ==} + '@napi-rs/lzma-darwin-x64@1.4.5': + resolution: {integrity: sha512-vR2IUyJY3En+V1wJkwmbGWcYiT8pHloTAWdW4pG24+51GIq+intst6Uf6D/r46citObGZrlX0QvMarOkQeHWpw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/lzma-freebsd-x64@1.4.3': - resolution: {integrity: sha512-W49h41U3+vLnbthbPzvJX1fQtTG+1jyUlfB+wX3oxILvIur06PjJRdMXrFtOZpWkFsihK9gO2DRkQYQJIIgTZw==} + '@napi-rs/lzma-freebsd-x64@1.4.5': + resolution: {integrity: sha512-XpnYQC5SVovO35tF0xGkbHYjsS6kqyNCjuaLQ2dbEblFRr5cAZVvsJ/9h7zj/5FluJPJRDojVNxGyRhTp4z2lw==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': - resolution: {integrity: sha512-11PNPiMGuwwxIxd9yPZY3Ek6RFGFRFQb/AtMStJIwlmJ6sM/djEknClLJVbVXbC/nqm7htVZEr+qmYgoDy0fAw==} + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': + resolution: {integrity: sha512-ic1ZZMoRfRMwtSwxkyw4zIlbDZGC6davC9r+2oX6x9QiF247BRqqT94qGeL5ZP4Vtz0Hyy7TEViWhx5j6Bpzvw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/lzma-linux-arm64-gnu@1.4.3': - resolution: {integrity: sha512-XzlxZjSXTcrWFHbvvv2xbV5+bSV5IJqCJ8CCksc7xV3uWEAso9yBPJ8VSRD3GPc7ZoBDRqJmgCb/HQzHpLBekw==} + '@napi-rs/lzma-linux-arm64-gnu@1.4.5': + resolution: {integrity: sha512-asEp7FPd7C1Yi6DQb45a3KPHKOFBSfGuJWXcAd4/bL2Fjetb2n/KK2z14yfW8YC/Fv6x3rBM0VAZKmJuz4tysg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/lzma-linux-arm64-musl@1.4.3': - resolution: {integrity: sha512-k4fWiI4Pm61Esj8hnm7NWIbpZueTtP2jlJqmMhTqJyjqW3NUxbTHjSErZOZKIFRF1B3if4v5Tyzo7JL2X+BaSQ==} + '@napi-rs/lzma-linux-arm64-musl@1.4.5': + resolution: {integrity: sha512-yWjcPDgJ2nIL3KNvi4536dlT/CcCWO0DUyEOlBs/SacG7BeD6IjGh6yYzd3/X1Y3JItCbZoDoLUH8iB1lTXo3w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': - resolution: {integrity: sha512-tTIfk+TYZYbFySxaCMuzp4Zz1T3I6OYVYNAm+IrCSkZDLmUKUzBK3+Su+mT+PjcTNsAiHBa5NVjARXC7b7jmgQ==} + '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': + resolution: {integrity: sha512-0XRhKuIU/9ZjT4WDIG/qnX7Xz7mSQHYZo9Gb3MP2gcvBgr6BA4zywQ9k3gmQaPn9ECE+CZg2V7DV7kT+x2pUMQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': - resolution: {integrity: sha512-HPyLYOYhkN7QYaWiKWhSnsLmx/l0pqgiiyaYeycgxCm9dwL8ummFWxveZqYjqdbUUvG7Mgi1jqgRe+55MVdyZQ==} + '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': + resolution: {integrity: sha512-QrqDIPEUUB23GCpyQj/QFyMlr8SGxxyExeZz9OWFnHfb70kXdTLWrHS/hEI1Ru+lSbQ/6xRqeoGyQ4Aqdg+/RA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@napi-rs/lzma-linux-s390x-gnu@1.4.3': - resolution: {integrity: sha512-YkcV+RSZZIMM3D5sPZqvo2Q7/tHXBhgJWBi+6ceo46pTlqgn/nH+pVz+CzsDmLWz5hqNSXyv5IAhOcg2CH6rAg==} + '@napi-rs/lzma-linux-s390x-gnu@1.4.5': + resolution: {integrity: sha512-k8RVM5aMhW86E9H0QXdquwojew4H3SwPxbRVbl49/COJQWCUjGi79X6mYruMnMPEznZinUiT1jgKbFo2A00NdA==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - '@napi-rs/lzma-linux-x64-gnu@1.4.3': - resolution: {integrity: sha512-ep6PLjN1+g4P12Hc7sLRmVpXXaHX22ykqxnOzjXUoj1KTph5XgM4+fUCyE5dsYI+lB4/tXqFuf9ZeFgHk5f00A==} + '@napi-rs/lzma-linux-x64-gnu@1.4.5': + resolution: {integrity: sha512-6rMtBgnIq2Wcl1rQdZsnM+rtCcVCbws1nF8S2NzaUsVaZv8bjrPiAa0lwg4Eqnn1d9lgwqT+cZgm5m+//K08Kw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/lzma-linux-x64-musl@1.4.3': - resolution: {integrity: sha512-QkCO6rVw0Z7eY0ziVc4aCFplbOTMpt0UBLPXWxsPd2lXtkAlRChzqaHOxdcL/HoLmBsqdCxmG0EZuHuAP/vKZQ==} + '@napi-rs/lzma-linux-x64-musl@1.4.5': + resolution: {integrity: sha512-eiadGBKi7Vd0bCArBUOO/qqRYPHt/VQVvGyYvDFt6C2ZSIjlD+HuOl+2oS1sjf4CFjK4eDIog6EdXnL0NE6iyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/lzma-wasm32-wasi@1.4.3': - resolution: {integrity: sha512-+rMamB0xaeDyVt4OP4cV888cnmso+m78iUebNhGcrL/WXIziwql50KQrmj7PBdBCza/W7XEcraZT8pO8gSDGcg==} + '@napi-rs/lzma-wasm32-wasi@1.4.5': + resolution: {integrity: sha512-+VyHHlr68dvey6fXc2hehw9gHVFIW3TtGF1XkcbAu65qVXsA9D/T+uuoRVqhE+JCyFHFrO0ixRbZDRK1XJt1sA==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/lzma-win32-arm64-msvc@1.4.3': - resolution: {integrity: sha512-6gQ+R6ztw11hswdsEu0jsOOXXnJPwhOA1yHRjqfuFemhf6esMd8l9b0uh3BfLBNe7qumtrH4KLrHu8yC9pSY3g==} + '@napi-rs/lzma-win32-arm64-msvc@1.4.5': + resolution: {integrity: sha512-eewnqvIyyhHi3KaZtBOJXohLvwwN27gfS2G/YDWdfHlbz1jrmfeHAmzMsP5qv8vGB+T80TMHNkro4kYjeh6Deg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/lzma-win32-ia32-msvc@1.4.3': - resolution: {integrity: sha512-+AJeJQoGE+QtZKlwM4VzDkfLmUa+6DsGOO5zdbIPlRCB6PEstRCXxp8lkMiQBNgk9f/IO0UEkRcJSZ+Hhqd8zw==} + '@napi-rs/lzma-win32-ia32-msvc@1.4.5': + resolution: {integrity: sha512-OeacFVRCJOKNU/a0ephUfYZ2Yt+NvaHze/4TgOwJ0J0P4P7X1mHzN+ig9Iyd74aQDXYqc7kaCXA2dpAOcH87Cg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/lzma-win32-x64-msvc@1.4.3': - resolution: {integrity: sha512-66dFCX9ACpVUyTTom89nxhllc88yJyjxGFHO0M2olFcrSJArulfbE9kNIATgh04NDAe/l8VsDhnAxWuvJY1GuA==} + '@napi-rs/lzma-win32-x64-msvc@1.4.5': + resolution: {integrity: sha512-T4I1SamdSmtyZgDXGAGP+y5LEK5vxHUFwe8mz6D4R7Sa5/WCxTcCIgPJ9BD7RkpO17lzhlaM2vmVvMy96Lvk9Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/lzma@1.4.3': - resolution: {integrity: sha512-uBjLLoUM9ll03jL/bP7XjyPg0vTU0vQ35N1vVqQHbzlK/fVZyuF2B1p/A6kqPsFFhaoBKgO6oaxsuerv091RtQ==} + '@napi-rs/lzma@1.4.5': + resolution: {integrity: sha512-zS5LuN1OBPAyZpda2ZZgYOEDC+xecUdAGnrvbYzjnLXkrq/OBC3B9qcRvlxbDR3k5H/gVfvef1/jyUqPknqjbg==} engines: {node: '>= 10'} - '@napi-rs/tar-android-arm-eabi@1.0.0': - resolution: {integrity: sha512-oEntU16IkWykPJnSwv/VIICzIt2SwEsz45z2Ab+EXOas10EB+pu0z31AiSNI5pr1CaJcadbf1JGMI9aOtbAuRQ==} + '@napi-rs/tar-android-arm-eabi@1.1.0': + resolution: {integrity: sha512-h2Ryndraj/YiKgMV/r5by1cDusluYIRT0CaE0/PekQ4u+Wpy2iUVqvzVU98ZPnhXaNeYxEvVJHNGafpOfaD0TA==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/tar-android-arm64@1.0.0': - resolution: {integrity: sha512-b2X7nQ/wH2VGzzl4KhVOR/gHqxIuqrUjMY8VKJYxAGdCrmUPRfc47kersiu6DG706kSv9T+BxeeUQvwqnXZRXQ==} + '@napi-rs/tar-android-arm64@1.1.0': + resolution: {integrity: sha512-DJFyQHr1ZxNZorm/gzc1qBNLF/FcKzcH0V0Vwan5P+o0aE2keQIGEjJ09FudkF9v6uOuJjHCVDdK6S6uHtShAw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/tar-darwin-arm64@1.0.0': - resolution: {integrity: sha512-m1Ug1452/DOUbJGSuJuHRTUCBQOXY0arGqXCHuSiaQhBQQjgBhlbHWCv291gV8CytFYd5lvSyiG2gFUU26Qd7A==} + '@napi-rs/tar-darwin-arm64@1.1.0': + resolution: {integrity: sha512-Zz2sXRzjIX4e532zD6xm2SjXEym6MkvfCvL2RMpG2+UwNVDVscHNcz3d47Pf3sysP2e2af7fBB3TIoK2f6trPw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/tar-darwin-x64@1.0.0': - resolution: {integrity: sha512-1RiC53g1y4pxX7P2L9sbZcqsw6dfXvGnTNwXHDjg4ATZncZa7uoPUWa7aHAGcQm8ZBO4P0ICt2SHOepstDWWTg==} + '@napi-rs/tar-darwin-x64@1.1.0': + resolution: {integrity: sha512-EI+CptIMNweT0ms9S3mkP/q+J6FNZ1Q6pvpJOEcWglRfyfQpLqjlC0O+dptruTPE8VamKYuqdjxfqD8hifZDOA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/tar-freebsd-x64@1.0.0': - resolution: {integrity: sha512-uLaYn+eO3ZY2ojbohdlRFcuqYP+j2alovtuLdFvCzzsArg4DSnmcJvEQ+I4l99lfyThYB1c8GA64oxSOfmn/UA==} + '@napi-rs/tar-freebsd-x64@1.1.0': + resolution: {integrity: sha512-J0PIqX+pl6lBIAckL/c87gpodLbjZB1OtIK+RDscKC9NLdpVv6VGOxzUV/fYev/hctcE8EfkLbgFOfpmVQPg2g==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/tar-linux-arm-gnueabihf@1.0.0': - resolution: {integrity: sha512-PhGIaT45i1Fj5iY6NiWYTLPUOHb7rXiwnqKhco+IXOeIclaGcEVoAbhrLiLGQrfv9viLdyhzAxECoOr+zKnApw==} + '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': + resolution: {integrity: sha512-SLgIQo3f3EjkZ82ZwvrEgFvMdDAhsxCYjyoSuWfHCz0U16qx3SuGCp8+FYOPYCECHN3ZlGjXnoAIt9ERd0dEUg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/tar-linux-arm64-gnu@1.0.0': - resolution: {integrity: sha512-syDburynsi2WxhD0hVUfNDpRowG+3Luiv2BKiYOUEwMZy6E/By1vQCn2NbLAqoPxaE9N/4Cp3xcW+Hn+CZ2EFA==} + '@napi-rs/tar-linux-arm64-gnu@1.1.0': + resolution: {integrity: sha512-d014cdle52EGaH6GpYTQOP9Py7glMO1zz/+ynJPjjzYFSxvdYx0byrjumZk2UQdIyGZiJO2MEFpCkEEKFSgPYA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/tar-linux-arm64-musl@1.0.0': - resolution: {integrity: sha512-KlrlAxNaZbWvGKgr4g4Cm5dRdwlogBaF3fvysaqR0kT8pA4ODBHtjsbx+ErhrQNDfg6QZIEfmFn3lrsTG/lqUA==} + '@napi-rs/tar-linux-arm64-musl@1.1.0': + resolution: {integrity: sha512-L/y1/26q9L/uBqiW/JdOb/Dc94egFvNALUZV2WCGKQXc6UByPBMgdiEyW2dtoYxYYYYc+AKD+jr+wQPcvX2vrQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/tar-linux-ppc64-gnu@1.0.0': - resolution: {integrity: sha512-IbB4I8RFcvKI/zGsboUQPmlKoXfXgNOMiJw7Cbe7T1OBeYzDy6n/yEUEaG4zIbocxqjRVsF4ElrW1V/0Ihlqzg==} + '@napi-rs/tar-linux-ppc64-gnu@1.1.0': + resolution: {integrity: sha512-EPE1K/80RQvPbLRJDJs1QmCIcH+7WRi0F73+oTe1582y9RtfGRuzAkzeBuAGRXAQEjRQw/RjtNqr6UTJ+8UuWQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - '@napi-rs/tar-linux-s390x-gnu@1.0.0': - resolution: {integrity: sha512-Tl4HSo07u3TLsNQ4KEVfYKdHVNfF/k0o5KQlyGnePiO34Kb+NfaqSKMspjSkrmXKEc0PjB+u9af3BZdTUwml4Q==} + '@napi-rs/tar-linux-s390x-gnu@1.1.0': + resolution: {integrity: sha512-B2jhWiB1ffw1nQBqLUP1h4+J1ovAxBOoe5N2IqDMOc63fsPZKNqF1PvO/dIem8z7LL4U4bsfmhy3gBfu547oNQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - '@napi-rs/tar-linux-x64-gnu@1.0.0': - resolution: {integrity: sha512-Xe57Yz4MKSeG6HGECiIHuBKFwAuqs2fzwblTdMd1CoSgaaUc/K/dKTDWZwPtjC0Hh5pM86K0WZuwggbsjmFGNg==} + '@napi-rs/tar-linux-x64-gnu@1.1.0': + resolution: {integrity: sha512-tbZDHnb9617lTnsDMGo/eAMZxnsQFnaRe+MszRqHguKfMwkisc9CCJnks/r1o84u5fECI+J/HOrKXgczq/3Oww==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/tar-linux-x64-musl@1.0.0': - resolution: {integrity: sha512-VA4RXspXyelNAtaFEf2ZLnTYXRILVlH20OGV0oqzuUcQzpwEwK2cJbYtYHK+yCYpxrNbEGsAwN+12LYJMW+NlA==} + '@napi-rs/tar-linux-x64-musl@1.1.0': + resolution: {integrity: sha512-dV6cODlzbO8u6Anmv2N/ilQHq/AWz0xyltuXoLU3yUyXbZcnWYZuB2rL8OBGPmqNcD+x9NdScBNXh7vWN0naSQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/tar-wasm32-wasi@1.0.0': - resolution: {integrity: sha512-yPMq3jMldKOi6rbbhKp+7zfaRsA2toIfRV7TbqSzwz64S5euiMrsZQcrq3F9oTtFu4wCSLo83IsNdgoVuiy44g==} + '@napi-rs/tar-wasm32-wasi@1.1.0': + resolution: {integrity: sha512-jIa9nb2HzOrfH0F8QQ9g3WE4aMH5vSI5/1NYVNm9ysCmNjCCtMXCAhlI3WKCdm/DwHf0zLqdrrtDFXODcNaqMw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/tar-win32-arm64-msvc@1.0.0': - resolution: {integrity: sha512-VdUjZK8jh6mvGRiurK3ms6Yt2hbBbtYjzKCn78Mnme2KGC585Kx1jXl7HShvreCgqh3r0162OSygoE7d/I0Jlw==} + '@napi-rs/tar-win32-arm64-msvc@1.1.0': + resolution: {integrity: sha512-vfpG71OB0ijtjemp3WTdmBKJm9R70KM8vsSExMsIQtV0lVzP07oM1CW6JbNRPXNLhRoue9ofYLiUDk8bE0Hckg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/tar-win32-ia32-msvc@1.0.0': - resolution: {integrity: sha512-8d/4iRXROPXLoe+4FEqXkpgP2KD9A45VUf76WfT6nXZwzQuoh+9WCJNRPVs5vfXV1SMnG9Z32WNc2ivCq0+HZw==} + '@napi-rs/tar-win32-ia32-msvc@1.1.0': + resolution: {integrity: sha512-hGPyPW60YSpOSgzfy68DLBHgi6HxkAM+L59ZZZPMQ0TOXjQg+p2EW87+TjZfJOkSpbYiEkULwa/f4a2hcVjsqQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/tar-win32-x64-msvc@1.0.0': - resolution: {integrity: sha512-HHtL1g0niVa4xDvyfi9wQtCTDDKkhDlaOb3bmayTqWs29mk+pcVHBST3OdXaaViSaduqdG9meosU5sOj5iKQAQ==} + '@napi-rs/tar-win32-x64-msvc@1.1.0': + resolution: {integrity: sha512-L6Ed1DxXK9YSCMyvpR8MiNAyKNkQLjsHsHK9E0qnHa8NzLFqzDKhvs5LfnWxM2kJ+F7m/e5n9zPm24kHb3LsVw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/tar@1.0.0': - resolution: {integrity: sha512-4sE8bFyOQFKcjWwBoBMtB+YIgKTqQFOFQZWKJP54jENpFulw8cieBaYoA3bbKCCFxXl2jCFulFKDtDErPWULTg==} + '@napi-rs/tar@1.1.0': + resolution: {integrity: sha512-7cmzIu+Vbupriudo7UudoMRH2OA3cTw67vva8MxeoAe5S7vPFI7z0vp0pMXiA25S8IUJefImQ90FeJjl8fjEaQ==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@0.2.11': - resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==} - - '@napi-rs/wasm-runtime@1.0.1': - resolution: {integrity: sha512-KVlQ/jgywZpixGCKMNwxStmmbYEMyokZpCf2YuIChhfJA2uqfAKNEM8INz7zzTo55iEXfBhIIs3VqYyqzDLj8g==} - '@napi-rs/wasm-runtime@1.0.7': resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} - '@napi-rs/wasm-tools-android-arm-eabi@1.0.0': - resolution: {integrity: sha512-Ks0hplmrYatIjSi8XeTObCi0x13AOQD41IQXpBjrz+UK71gDkbxyLWO7B/ckuels3mC1DW3OCQCv+q0lPnaG/A==} + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': + resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/wasm-tools-android-arm64@1.0.0': - resolution: {integrity: sha512-Ppu1/YGLSC/ohkOA8R5YfDh1dCuCHWJObu/BTorAY55YDXIiWy400CoungbYwoRT53K+ixNrg8/zRHnpuqwkRg==} + '@napi-rs/wasm-tools-android-arm64@1.0.1': + resolution: {integrity: sha512-WDR7S+aRLV6LtBJAg5fmjKkTZIdrEnnQxgdsb7Cf8pYiMWBHLU+LC49OUVppQ2YSPY0+GeYm9yuZWW3kLjJ7Bg==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/wasm-tools-darwin-arm64@1.0.0': - resolution: {integrity: sha512-EUU7NvmmKASMLecu7hUHhv9XN2Thf8j+2/zCCMuFuAAlY+eZiOVfrajbZ/RE8CZ4oyfkb0bWFg/CQcmcXAatTw==} + '@napi-rs/wasm-tools-darwin-arm64@1.0.1': + resolution: {integrity: sha512-qWTI+EEkiN0oIn/N2gQo7+TVYil+AJ20jjuzD2vATS6uIjVz+Updeqmszi7zq7rdFTLp6Ea3/z4kDKIfZwmR9g==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/wasm-tools-darwin-x64@1.0.0': - resolution: {integrity: sha512-hlX21sqy0AEnmn2abarmCXV3fpyIQN+fKqeHNuawti9ZpaJCL6gZCtUGqpUxURjXNjXSI8rywInJE2YmeVQSJQ==} + '@napi-rs/wasm-tools-darwin-x64@1.0.1': + resolution: {integrity: sha512-bA6hubqtHROR5UI3tToAF/c6TDmaAgF0SWgo4rADHtQ4wdn0JeogvOk50gs2TYVhKPE2ZD2+qqt7oBKB+sxW3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/wasm-tools-freebsd-x64@1.0.0': - resolution: {integrity: sha512-T9SOSfIgrdEGQzzquKMOfD3PF6TxG5hL2o5voZtLUALA0yjO+GnpFyv8tAcxKYd7ngWzzK5Uwk7e1z9PcsQZMg==} + '@napi-rs/wasm-tools-freebsd-x64@1.0.1': + resolution: {integrity: sha512-90+KLBkD9hZEjPQW1MDfwSt5J1L46EUKacpCZWyRuL6iIEO5CgWU0V/JnEgFsDOGyyYtiTvHc5bUdUTWd4I9Vg==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.0': - resolution: {integrity: sha512-qHNLY0GLTZK8M/cQOy2OAaRDfk3YOlWAwlAO4KSIAseuXHAaGya3Ay//kbmwzzs8h6TKf/eAeXDwcGxze5ecxw==} + '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-rG0QlS65x9K/u3HrKafDf8cFKj5wV2JHGfl8abWgKew0GVPyp6vfsDweOwHbWAjcHtp2LHi6JHoW80/MTHm52Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/wasm-tools-linux-arm64-musl@1.0.0': - resolution: {integrity: sha512-54BWWTg5I9n77PRUKErBe3BKqkmbjm0GRpUKJgGdlcessC9Oxa/yVDy2BPtmJP1pQR3VabkXR63H+ZGaH5qKxw==} + '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-jAasbIvjZXCgX0TCuEFQr+4D6Lla/3AAVx2LmDuMjgG4xoIXzjKWl7c4chuaD+TI+prWT0X6LJcdzFT+ROKGHQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/wasm-tools-linux-x64-gnu@1.0.0': - resolution: {integrity: sha512-wpRkiy0QBM/zpaGAn5I1HfddQul0vGrdlindT2UHtOYK1zvam524M6LJXBtmhBkXS5a4F2HZiZXns8Wuc7dq4w==} + '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-Plgk5rPqqK2nocBGajkMVbGm010Z7dnUgq0wtnYRZbzWWxwWcXfZMPa8EYxrK4eE8SzpI7VlZP1tdVsdjgGwMw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/wasm-tools-linux-x64-musl@1.0.0': - resolution: {integrity: sha512-Ua94ruWB18uKyIz/nj+by2ZxfBbFzbqiiD564ocBHGbrUffpR6Us74uVwxO7rImc/WvCfJqap9ezqmaTvmK7SA==} + '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-GW7AzGuWxtQkyHknHWYFdR0CHmW6is8rG2Rf4V6GNmMpmwtXt/ItWYWtBe4zqJWycMNazpfZKSw/BpT7/MVCXQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/wasm-tools-wasm32-wasi@1.0.0': - resolution: {integrity: sha512-gWVdt1UK575VKTnFRcYTe0qMZA5bFV2w69qDAhX8hG6tajjxbVyvu4jgsYvv/bJrBrxFsNbXMlEU1d0X7iWziA==} + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-/nQVSTrqSsn7YdAc2R7Ips/tnw5SPUcl3D7QrXCNGPqjbatIspnaexvaOYNyKMU6xPu+pc0BTnKVmqhlJJCPLA==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.0': - resolution: {integrity: sha512-1kv+DM7z6c9OLcjMtO1/kfdxS5hwXtW1OLIHBU41dtKz5jD3quapYrCjB7AVEZh/JVM765UaLOl31huVucJjRw==} + '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-PFi7oJIBu5w7Qzh3dwFea3sHRO3pojMsaEnUIy22QvsW+UJfNQwJCryVrpoUt8m4QyZXI+saEq/0r4GwdoHYFQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.0': - resolution: {integrity: sha512-OwcyXtU2Zi3YVHYjmomM3u7jRNPY1j+IPehqCVEqd60jOTOXRZNPGoAvOC7Lw6HX/RGzOJnIcJZbVfKrz5WN1g==} + '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': + resolution: {integrity: sha512-gXkuYzxQsgkj05Zaq+KQTkHIN83dFAwMcTKa2aQcpYPRImFm2AQzEyLtpXmyCWzJ0F9ZYAOmbSyrNew8/us6bw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/wasm-tools-win32-x64-msvc@1.0.0': - resolution: {integrity: sha512-xat6gnp/G/WCe6U6HKzawotz9zpqsM5a+Dx+S0MPX4AKP7+oztC2/6tkp8KtOPT2bMRMekNntXadHKk0XqW61Q==} + '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-rEAf05nol3e3eei2sRButmgXP+6ATgm0/38MKhz9Isne82T4rPIMYsCIFj0kOisaGeVwoi2fnm7O9oWp5YVnYQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/wasm-tools@1.0.0': - resolution: {integrity: sha512-GL43zmDN6AFmomd7eTJOdZkXDvocucjqJcBs/IY51ZTxHvBeb1SXTM0/rI2VJ7C3FTiyATTt2D8chonCi0UTgw==} + '@napi-rs/wasm-tools@1.0.1': + resolution: {integrity: sha512-enkZYyuCdo+9jneCPE/0fjIta4wWnvVN9hBo2HuiMpRF0q3lzv1J6b/cl7i0mxZUKhBrV3aCKDBQnCOhwKbPmQ==} engines: {node: '>= 10'} '@octokit/auth-token@6.0.0': resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} - '@octokit/core@7.0.2': - resolution: {integrity: sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==} + '@octokit/core@7.0.5': + resolution: {integrity: sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.0': - resolution: {integrity: sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==} + '@octokit/endpoint@11.0.1': + resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==} engines: {node: '>= 20'} - '@octokit/graphql@9.0.1': - resolution: {integrity: sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==} + '@octokit/graphql@9.0.2': + resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==} engines: {node: '>= 20'} - '@octokit/openapi-types@25.1.0': - resolution: {integrity: sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==} + '@octokit/openapi-types@26.0.0': + resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/plugin-paginate-rest@13.1.0': - resolution: {integrity: sha512-16iNOa4rTTjaWtfsPGJcYYL79FJakseX8TQFIPfVuSPC3s5nkS/DSNQPFPc5lJHgEDBWNMxSApHrEymNblhA9w==} + '@octokit/plugin-paginate-rest@13.2.0': + resolution: {integrity: sha512-YuAlyjR8o5QoRSOvMHxSJzPtogkNMgeMv2mpccrvdUGeC3MKyfi/hS+KiFwyH/iRKIKyx+eIMsDjbt3p9r2GYA==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -530,26 +537,26 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.0.0': - resolution: {integrity: sha512-kJVUQk6/dx/gRNLWUnAWKFs1kVPn5O5CYZyssyEoNYaFedqZxsfYs7DwI3d67hGz4qOwaJ1dpm07hOAD1BXx6g==} + '@octokit/plugin-rest-endpoint-methods@16.1.0': + resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' - '@octokit/request-error@7.0.0': - resolution: {integrity: sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==} + '@octokit/request-error@7.0.1': + resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==} engines: {node: '>= 20'} - '@octokit/request@10.0.3': - resolution: {integrity: sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==} + '@octokit/request@10.0.5': + resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==} engines: {node: '>= 20'} '@octokit/rest@22.0.0': resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} engines: {node: '>= 20'} - '@octokit/types@14.1.0': - resolution: {integrity: sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==} + '@octokit/types@15.0.0': + resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} '@oxc-node/core-android-arm-eabi@0.0.32': resolution: {integrity: sha512-Ykkz+xYJ1Hd+vjVSXljyIFRW/ZRMp2tQfPy9T2jj9F2pm5CAchqJHSXEbB3FbhdUXusUqhWLmu70JdVhS4SBcQ==} @@ -685,8 +692,8 @@ packages: cpu: [arm64] os: [darwin] - '@platformatic/python-node-darwin-x64@0.1.4': - resolution: {integrity: sha512-fPpNKRycnpHjqyHnuX23qd/+UzT/4xab5hFotlrfIwqYErybZyCgJJv6zRugGzmw8pE0HkUzrnbeOzMw25jMvw==} + '@platformatic/python-node-darwin-x64@0.1.10': + resolution: {integrity: sha512-rs4STYb/2D6mV2duO7CCrmtf0/YjPTkn1IaIdxxSQGTVK0z+LONymCvS/TCdGK9mWdj9Y88ao66NIr/itlM73g==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] @@ -697,19 +704,9 @@ packages: cpu: [x64] os: [linux] - '@tybys/wasm-util@0.10.0': - resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} - '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@tybys/wasm-util@0.9.0': - resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -724,8 +721,8 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} - chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + chardet@2.1.0: + resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -746,8 +743,8 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -755,22 +752,25 @@ packages: supports-color: optional: true + emnapi@1.5.0: + resolution: {integrity: sha512-adAaiwTxMnHbq1u2LUf+AfDR5MYrxDVBtezGspxwk5e/Zb6KHkGNdfuMU4JBIVm6ASY06K8KalhOPUht92MsnA==} + peerDependencies: + node-addon-api: '>= 6.1.0' + peerDependenciesMeta: + node-addon-api: + optional: true + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} + es-toolkit@1.40.0: + resolution: {integrity: sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==} fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} is-fullwidth-code-point@3.0.0: @@ -781,13 +781,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -795,27 +788,11 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} - os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - oxlint@0.16.12: resolution: {integrity: sha512-1oN3P9bzE90zkbjLTc+uICVLwSR+eQaDaYVipS0BtmtmEd3ccQue0y7npCinb35YqKzIv1LZxhoU9nm5fgmQuw==} engines: {node: '>=8.*'} hasBin: true - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -823,8 +800,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -840,24 +817,12 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} typanion@3.14.0: resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} @@ -865,327 +830,305 @@ packages: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} - yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} - engines: {node: '>=12.20'} - - yoctocolors-cjs@2.1.2: - resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} snapshots: - '@emnapi/core@1.4.5': - dependencies: - '@emnapi/wasi-threads': 1.0.4 - tslib: 2.8.1 - optional: true - '@emnapi/core@1.5.0': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.5': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.5.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.0.4': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 optional: true - '@inquirer/checkbox@4.1.8': + '@inquirer/ansi@1.0.1': {} + + '@inquirer/checkbox@4.3.0': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7 - ansi-escapes: 4.3.2 - yoctocolors-cjs: 2.1.2 + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0 + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9 + yoctocolors-cjs: 2.1.3 - '@inquirer/confirm@5.1.12': + '@inquirer/confirm@5.1.19': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 - '@inquirer/core@10.1.13': + '@inquirer/core@10.3.0': dependencies: - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7 - ansi-escapes: 4.3.2 + '@inquirer/ansi': 1.0.1 + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9 cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.2 + yoctocolors-cjs: 2.1.3 - '@inquirer/editor@4.2.13': + '@inquirer/editor@4.2.21': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 - external-editor: 3.1.0 + '@inquirer/core': 10.3.0 + '@inquirer/external-editor': 1.0.2 + '@inquirer/type': 3.0.9 - '@inquirer/expand@4.0.15': + '@inquirer/expand@4.0.21': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 + yoctocolors-cjs: 2.1.3 - '@inquirer/figures@1.0.12': {} + '@inquirer/external-editor@1.0.2': + dependencies: + chardet: 2.1.0 + iconv-lite: 0.7.0 + + '@inquirer/figures@1.0.14': {} - '@inquirer/input@4.1.12': + '@inquirer/input@4.2.5': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 - '@inquirer/number@3.0.15': + '@inquirer/number@3.0.21': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 - '@inquirer/password@4.0.15': + '@inquirer/password@4.0.21': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 - ansi-escapes: 4.3.2 + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 - '@inquirer/prompts@7.5.3': + '@inquirer/prompts@7.9.0': dependencies: - '@inquirer/checkbox': 4.1.8 - '@inquirer/confirm': 5.1.12 - '@inquirer/editor': 4.2.13 - '@inquirer/expand': 4.0.15 - '@inquirer/input': 4.1.12 - '@inquirer/number': 3.0.15 - '@inquirer/password': 4.0.15 - '@inquirer/rawlist': 4.1.3 - '@inquirer/search': 3.0.15 - '@inquirer/select': 4.2.3 - - '@inquirer/rawlist@4.1.3': + '@inquirer/checkbox': 4.3.0 + '@inquirer/confirm': 5.1.19 + '@inquirer/editor': 4.2.21 + '@inquirer/expand': 4.0.21 + '@inquirer/input': 4.2.5 + '@inquirer/number': 3.0.21 + '@inquirer/password': 4.0.21 + '@inquirer/rawlist': 4.1.9 + '@inquirer/search': 3.2.0 + '@inquirer/select': 4.4.0 + + '@inquirer/rawlist@4.1.9': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/type': 3.0.7 - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.0 + '@inquirer/type': 3.0.9 + yoctocolors-cjs: 2.1.3 - '@inquirer/search@3.0.15': + '@inquirer/search@3.2.0': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7 - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.0 + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9 + yoctocolors-cjs: 2.1.3 - '@inquirer/select@4.2.3': + '@inquirer/select@4.4.0': dependencies: - '@inquirer/core': 10.1.13 - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7 - ansi-escapes: 4.3.2 - yoctocolors-cjs: 2.1.2 + '@inquirer/ansi': 1.0.1 + '@inquirer/core': 10.3.0 + '@inquirer/figures': 1.0.14 + '@inquirer/type': 3.0.9 + yoctocolors-cjs: 2.1.3 - '@inquirer/type@3.0.7': {} + '@inquirer/type@3.0.9': {} - '@napi-rs/cli@3.0.4(@emnapi/runtime@1.5.0)': + '@napi-rs/cli@3.3.1(@emnapi/runtime@1.5.0)': dependencies: - '@inquirer/prompts': 7.5.3 - '@napi-rs/cross-toolchain': 1.0.0 - '@napi-rs/wasm-tools': 1.0.0 + '@inquirer/prompts': 7.9.0 + '@napi-rs/cross-toolchain': 1.0.3 + '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - debug: 4.4.1 - find-up: 7.0.0 + debug: 4.4.3 + emnapi: 1.5.0 + es-toolkit: 1.40.0 js-yaml: 4.1.0 - lodash-es: 4.17.21 - semver: 7.7.2 + semver: 7.7.3 typanion: 3.14.0 optionalDependencies: '@emnapi/runtime': 1.5.0 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' + - '@napi-rs/cross-toolchain-arm64-target-ppc64le' + - '@napi-rs/cross-toolchain-arm64-target-s390x' - '@napi-rs/cross-toolchain-arm64-target-x86_64' - '@napi-rs/cross-toolchain-x64-target-aarch64' - '@napi-rs/cross-toolchain-x64-target-armv7' + - '@napi-rs/cross-toolchain-x64-target-ppc64le' + - '@napi-rs/cross-toolchain-x64-target-s390x' - '@napi-rs/cross-toolchain-x64-target-x86_64' - '@types/node' + - node-addon-api - supports-color - '@napi-rs/cross-toolchain@1.0.0': + '@napi-rs/cross-toolchain@1.0.3': dependencies: - '@napi-rs/lzma': 1.4.3 - '@napi-rs/tar': 1.0.0 - debug: 4.4.1 + '@napi-rs/lzma': 1.4.5 + '@napi-rs/tar': 1.1.0 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@napi-rs/lzma-android-arm-eabi@1.4.3': + '@napi-rs/lzma-android-arm-eabi@1.4.5': optional: true - '@napi-rs/lzma-android-arm64@1.4.3': + '@napi-rs/lzma-android-arm64@1.4.5': optional: true - '@napi-rs/lzma-darwin-arm64@1.4.3': + '@napi-rs/lzma-darwin-arm64@1.4.5': optional: true - '@napi-rs/lzma-darwin-x64@1.4.3': + '@napi-rs/lzma-darwin-x64@1.4.5': optional: true - '@napi-rs/lzma-freebsd-x64@1.4.3': + '@napi-rs/lzma-freebsd-x64@1.4.5': optional: true - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': optional: true - '@napi-rs/lzma-linux-arm64-gnu@1.4.3': + '@napi-rs/lzma-linux-arm64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-arm64-musl@1.4.3': + '@napi-rs/lzma-linux-arm64-musl@1.4.5': optional: true - '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': + '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': + '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-s390x-gnu@1.4.3': + '@napi-rs/lzma-linux-s390x-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-x64-gnu@1.4.3': + '@napi-rs/lzma-linux-x64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-x64-musl@1.4.3': + '@napi-rs/lzma-linux-x64-musl@1.4.5': optional: true - '@napi-rs/lzma-wasm32-wasi@1.4.3': + '@napi-rs/lzma-wasm32-wasi@1.4.5': dependencies: - '@napi-rs/wasm-runtime': 0.2.11 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/lzma-win32-arm64-msvc@1.4.3': + '@napi-rs/lzma-win32-arm64-msvc@1.4.5': optional: true - '@napi-rs/lzma-win32-ia32-msvc@1.4.3': + '@napi-rs/lzma-win32-ia32-msvc@1.4.5': optional: true - '@napi-rs/lzma-win32-x64-msvc@1.4.3': + '@napi-rs/lzma-win32-x64-msvc@1.4.5': optional: true - '@napi-rs/lzma@1.4.3': + '@napi-rs/lzma@1.4.5': optionalDependencies: - '@napi-rs/lzma-android-arm-eabi': 1.4.3 - '@napi-rs/lzma-android-arm64': 1.4.3 - '@napi-rs/lzma-darwin-arm64': 1.4.3 - '@napi-rs/lzma-darwin-x64': 1.4.3 - '@napi-rs/lzma-freebsd-x64': 1.4.3 - '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.3 - '@napi-rs/lzma-linux-arm64-gnu': 1.4.3 - '@napi-rs/lzma-linux-arm64-musl': 1.4.3 - '@napi-rs/lzma-linux-ppc64-gnu': 1.4.3 - '@napi-rs/lzma-linux-riscv64-gnu': 1.4.3 - '@napi-rs/lzma-linux-s390x-gnu': 1.4.3 - '@napi-rs/lzma-linux-x64-gnu': 1.4.3 - '@napi-rs/lzma-linux-x64-musl': 1.4.3 - '@napi-rs/lzma-wasm32-wasi': 1.4.3 - '@napi-rs/lzma-win32-arm64-msvc': 1.4.3 - '@napi-rs/lzma-win32-ia32-msvc': 1.4.3 - '@napi-rs/lzma-win32-x64-msvc': 1.4.3 + '@napi-rs/lzma-android-arm-eabi': 1.4.5 + '@napi-rs/lzma-android-arm64': 1.4.5 + '@napi-rs/lzma-darwin-arm64': 1.4.5 + '@napi-rs/lzma-darwin-x64': 1.4.5 + '@napi-rs/lzma-freebsd-x64': 1.4.5 + '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.5 + '@napi-rs/lzma-linux-arm64-gnu': 1.4.5 + '@napi-rs/lzma-linux-arm64-musl': 1.4.5 + '@napi-rs/lzma-linux-ppc64-gnu': 1.4.5 + '@napi-rs/lzma-linux-riscv64-gnu': 1.4.5 + '@napi-rs/lzma-linux-s390x-gnu': 1.4.5 + '@napi-rs/lzma-linux-x64-gnu': 1.4.5 + '@napi-rs/lzma-linux-x64-musl': 1.4.5 + '@napi-rs/lzma-wasm32-wasi': 1.4.5 + '@napi-rs/lzma-win32-arm64-msvc': 1.4.5 + '@napi-rs/lzma-win32-ia32-msvc': 1.4.5 + '@napi-rs/lzma-win32-x64-msvc': 1.4.5 - '@napi-rs/tar-android-arm-eabi@1.0.0': + '@napi-rs/tar-android-arm-eabi@1.1.0': optional: true - '@napi-rs/tar-android-arm64@1.0.0': + '@napi-rs/tar-android-arm64@1.1.0': optional: true - '@napi-rs/tar-darwin-arm64@1.0.0': + '@napi-rs/tar-darwin-arm64@1.1.0': optional: true - '@napi-rs/tar-darwin-x64@1.0.0': + '@napi-rs/tar-darwin-x64@1.1.0': optional: true - '@napi-rs/tar-freebsd-x64@1.0.0': + '@napi-rs/tar-freebsd-x64@1.1.0': optional: true - '@napi-rs/tar-linux-arm-gnueabihf@1.0.0': + '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': optional: true - '@napi-rs/tar-linux-arm64-gnu@1.0.0': + '@napi-rs/tar-linux-arm64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-arm64-musl@1.0.0': + '@napi-rs/tar-linux-arm64-musl@1.1.0': optional: true - '@napi-rs/tar-linux-ppc64-gnu@1.0.0': + '@napi-rs/tar-linux-ppc64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-s390x-gnu@1.0.0': + '@napi-rs/tar-linux-s390x-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-x64-gnu@1.0.0': + '@napi-rs/tar-linux-x64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-x64-musl@1.0.0': + '@napi-rs/tar-linux-x64-musl@1.1.0': optional: true - '@napi-rs/tar-wasm32-wasi@1.0.0': + '@napi-rs/tar-wasm32-wasi@1.1.0': dependencies: - '@napi-rs/wasm-runtime': 1.0.1 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/tar-win32-arm64-msvc@1.0.0': + '@napi-rs/tar-win32-arm64-msvc@1.1.0': optional: true - '@napi-rs/tar-win32-ia32-msvc@1.0.0': + '@napi-rs/tar-win32-ia32-msvc@1.1.0': optional: true - '@napi-rs/tar-win32-x64-msvc@1.0.0': + '@napi-rs/tar-win32-x64-msvc@1.1.0': optional: true - '@napi-rs/tar@1.0.0': + '@napi-rs/tar@1.1.0': optionalDependencies: - '@napi-rs/tar-android-arm-eabi': 1.0.0 - '@napi-rs/tar-android-arm64': 1.0.0 - '@napi-rs/tar-darwin-arm64': 1.0.0 - '@napi-rs/tar-darwin-x64': 1.0.0 - '@napi-rs/tar-freebsd-x64': 1.0.0 - '@napi-rs/tar-linux-arm-gnueabihf': 1.0.0 - '@napi-rs/tar-linux-arm64-gnu': 1.0.0 - '@napi-rs/tar-linux-arm64-musl': 1.0.0 - '@napi-rs/tar-linux-ppc64-gnu': 1.0.0 - '@napi-rs/tar-linux-s390x-gnu': 1.0.0 - '@napi-rs/tar-linux-x64-gnu': 1.0.0 - '@napi-rs/tar-linux-x64-musl': 1.0.0 - '@napi-rs/tar-wasm32-wasi': 1.0.0 - '@napi-rs/tar-win32-arm64-msvc': 1.0.0 - '@napi-rs/tar-win32-ia32-msvc': 1.0.0 - '@napi-rs/tar-win32-x64-msvc': 1.0.0 - - '@napi-rs/wasm-runtime@0.2.11': - dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.5 - '@tybys/wasm-util': 0.9.0 - optional: true - - '@napi-rs/wasm-runtime@1.0.1': - dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.5 - '@tybys/wasm-util': 0.10.0 - optional: true + '@napi-rs/tar-android-arm-eabi': 1.1.0 + '@napi-rs/tar-android-arm64': 1.1.0 + '@napi-rs/tar-darwin-arm64': 1.1.0 + '@napi-rs/tar-darwin-x64': 1.1.0 + '@napi-rs/tar-freebsd-x64': 1.1.0 + '@napi-rs/tar-linux-arm-gnueabihf': 1.1.0 + '@napi-rs/tar-linux-arm64-gnu': 1.1.0 + '@napi-rs/tar-linux-arm64-musl': 1.1.0 + '@napi-rs/tar-linux-ppc64-gnu': 1.1.0 + '@napi-rs/tar-linux-s390x-gnu': 1.1.0 + '@napi-rs/tar-linux-x64-gnu': 1.1.0 + '@napi-rs/tar-linux-x64-musl': 1.1.0 + '@napi-rs/tar-wasm32-wasi': 1.1.0 + '@napi-rs/tar-win32-arm64-msvc': 1.1.0 + '@napi-rs/tar-win32-ia32-msvc': 1.1.0 + '@napi-rs/tar-win32-x64-msvc': 1.1.0 '@napi-rs/wasm-runtime@1.0.7': dependencies: @@ -1194,124 +1137,124 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-tools-android-arm-eabi@1.0.0': + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': optional: true - '@napi-rs/wasm-tools-android-arm64@1.0.0': + '@napi-rs/wasm-tools-android-arm64@1.0.1': optional: true - '@napi-rs/wasm-tools-darwin-arm64@1.0.0': + '@napi-rs/wasm-tools-darwin-arm64@1.0.1': optional: true - '@napi-rs/wasm-tools-darwin-x64@1.0.0': + '@napi-rs/wasm-tools-darwin-x64@1.0.1': optional: true - '@napi-rs/wasm-tools-freebsd-x64@1.0.0': + '@napi-rs/wasm-tools-freebsd-x64@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.0': + '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-arm64-musl@1.0.0': + '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-x64-gnu@1.0.0': + '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-x64-musl@1.0.0': + '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-wasm32-wasi@1.0.0': + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': dependencies: - '@napi-rs/wasm-runtime': 1.0.1 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.0': + '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.0': + '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools-win32-x64-msvc@1.0.0': + '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools@1.0.0': + '@napi-rs/wasm-tools@1.0.1': optionalDependencies: - '@napi-rs/wasm-tools-android-arm-eabi': 1.0.0 - '@napi-rs/wasm-tools-android-arm64': 1.0.0 - '@napi-rs/wasm-tools-darwin-arm64': 1.0.0 - '@napi-rs/wasm-tools-darwin-x64': 1.0.0 - '@napi-rs/wasm-tools-freebsd-x64': 1.0.0 - '@napi-rs/wasm-tools-linux-arm64-gnu': 1.0.0 - '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.0 - '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.0 - '@napi-rs/wasm-tools-linux-x64-musl': 1.0.0 - '@napi-rs/wasm-tools-wasm32-wasi': 1.0.0 - '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.0 - '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.0 - '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.0 + '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1 + '@napi-rs/wasm-tools-android-arm64': 1.0.1 + '@napi-rs/wasm-tools-darwin-arm64': 1.0.1 + '@napi-rs/wasm-tools-darwin-x64': 1.0.1 + '@napi-rs/wasm-tools-freebsd-x64': 1.0.1 + '@napi-rs/wasm-tools-linux-arm64-gnu': 1.0.1 + '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1 + '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1 + '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1 + '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1 + '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1 + '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1 + '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1 '@octokit/auth-token@6.0.0': {} - '@octokit/core@7.0.2': + '@octokit/core@7.0.5': dependencies: '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.1 - '@octokit/request': 10.0.3 - '@octokit/request-error': 7.0.0 - '@octokit/types': 14.1.0 + '@octokit/graphql': 9.0.2 + '@octokit/request': 10.0.5 + '@octokit/request-error': 7.0.1 + '@octokit/types': 15.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.0': + '@octokit/endpoint@11.0.1': dependencies: - '@octokit/types': 14.1.0 + '@octokit/types': 15.0.0 universal-user-agent: 7.0.3 - '@octokit/graphql@9.0.1': + '@octokit/graphql@9.0.2': dependencies: - '@octokit/request': 10.0.3 - '@octokit/types': 14.1.0 + '@octokit/request': 10.0.5 + '@octokit/types': 15.0.0 universal-user-agent: 7.0.3 - '@octokit/openapi-types@25.1.0': {} + '@octokit/openapi-types@26.0.0': {} - '@octokit/plugin-paginate-rest@13.1.0(@octokit/core@7.0.2)': + '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': dependencies: - '@octokit/core': 7.0.2 - '@octokit/types': 14.1.0 + '@octokit/core': 7.0.5 + '@octokit/types': 15.0.0 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.2)': + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': dependencies: - '@octokit/core': 7.0.2 + '@octokit/core': 7.0.5 - '@octokit/plugin-rest-endpoint-methods@16.0.0(@octokit/core@7.0.2)': + '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)': dependencies: - '@octokit/core': 7.0.2 - '@octokit/types': 14.1.0 + '@octokit/core': 7.0.5 + '@octokit/types': 15.0.0 - '@octokit/request-error@7.0.0': + '@octokit/request-error@7.0.1': dependencies: - '@octokit/types': 14.1.0 + '@octokit/types': 15.0.0 - '@octokit/request@10.0.3': + '@octokit/request@10.0.5': dependencies: - '@octokit/endpoint': 11.0.0 - '@octokit/request-error': 7.0.0 - '@octokit/types': 14.1.0 + '@octokit/endpoint': 11.0.1 + '@octokit/request-error': 7.0.1 + '@octokit/types': 15.0.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 '@octokit/rest@22.0.0': dependencies: - '@octokit/core': 7.0.2 - '@octokit/plugin-paginate-rest': 13.1.0(@octokit/core@7.0.2) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.2) - '@octokit/plugin-rest-endpoint-methods': 16.0.0(@octokit/core@7.0.2) + '@octokit/core': 7.0.5 + '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) + '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) - '@octokit/types@14.1.0': + '@octokit/types@15.0.0': dependencies: - '@octokit/openapi-types': 25.1.0 + '@octokit/openapi-types': 26.0.0 '@oxc-node/core-android-arm-eabi@0.0.32': optional: true @@ -1415,31 +1358,17 @@ snapshots: '@platformatic/python-node-darwin-arm64@0.1.10': optional: true - '@platformatic/python-node-darwin-x64@0.1.4': + '@platformatic/python-node-darwin-x64@0.1.10': optional: true '@platformatic/python-node-linux-x64-gnu@0.1.10': optional: true - '@tybys/wasm-util@0.10.0': - dependencies: - tslib: 2.8.1 - optional: true - '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true - '@tybys/wasm-util@0.9.0': - dependencies: - tslib: 2.8.1 - optional: true - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - ansi-regex@5.0.1: {} ansi-styles@4.3.0: @@ -1450,7 +1379,7 @@ snapshots: before-after-hook@4.0.0: {} - chardet@0.7.0: {} + chardet@2.1.0: {} cli-width@4.1.0: {} @@ -1466,27 +1395,19 @@ snapshots: colorette@2.0.20: {} - debug@4.4.1: + debug@4.4.3: dependencies: ms: 2.1.3 + emnapi@1.5.0: {} + emoji-regex@8.0.0: {} - external-editor@3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 + es-toolkit@1.40.0: {} fast-content-type-parse@3.0.0: {} - find-up@7.0.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - unicorn-magic: 0.1.0 - - iconv-lite@0.4.24: + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 @@ -1496,18 +1417,10 @@ snapshots: dependencies: argparse: 2.0.1 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash-es@4.17.21: {} - ms@2.1.3: {} mute-stream@2.0.0: {} - os-tmpdir@1.0.2: {} - oxlint@0.16.12: optionalDependencies: '@oxlint/darwin-arm64': 0.16.12 @@ -1519,21 +1432,11 @@ snapshots: '@oxlint/win32-arm64': 0.16.12 '@oxlint/win32-x64': 0.16.12 - p-limit@4.0.0: - dependencies: - yocto-queue: 1.2.1 - - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - - path-exists@5.0.0: {} - pirates@4.0.7: {} safer-buffer@2.1.2: {} - semver@7.7.2: {} + semver@7.7.3: {} signal-exit@4.1.0: {} @@ -1547,19 +1450,11 @@ snapshots: dependencies: ansi-regex: 5.0.1 - tmp@0.0.33: - dependencies: - os-tmpdir: 1.0.2 - tslib@2.8.1: optional: true typanion@3.14.0: {} - type-fest@0.21.3: {} - - unicorn-magic@0.1.0: {} - universal-user-agent@7.0.3: {} wrap-ansi@6.2.0: @@ -1568,6 +1463,4 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - yocto-queue@1.2.1: {} - - yoctocolors-cjs@2.1.2: {} + yoctocolors-cjs@2.1.3: {} From fbcaa942ac5e195d70bfcf319b67f1f73b1a65bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 03:03:52 +0000 Subject: [PATCH 05/25] Lock file maintenance (#31) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cd1de5..71e7117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -380,7 +380,7 @@ dependencies = [ [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#b32e0e1f529b28785623d93806775df3b3eb3201" +source = "git+https://github.com/platformatic/http-handler#3899d3ed32afb3830b650fbf468f0a84231bbd27" dependencies = [ "async-trait", "bytes", @@ -881,9 +881,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", From 7dd01269ac469220f1d69cee82d984ba25ef46bf Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Thu, 23 Oct 2025 00:49:10 +0800 Subject: [PATCH 06/25] Follow changes to http-handler and http-rewriter (#32) --- Cargo.lock | 41 +++++++++++++++++++++++++---------------- Cargo.toml | 2 ++ src/lib.rs | 9 +++------ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71e7117..82830bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,9 +99,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bytes" @@ -117,9 +117,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -380,7 +380,7 @@ dependencies = [ [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#3899d3ed32afb3830b650fbf468f0a84231bbd27" +source = "git+https://github.com/platformatic/http-handler#f60dbc830e12b1cedae4c8a4f370bc4133a868fc" dependencies = [ "async-trait", "bytes", @@ -393,7 +393,7 @@ dependencies = [ [[package]] name = "http-rewriter" version = "1.0.0" -source = "git+https://github.com/platformatic/http-rewriter#d31cd99f759bf15fa4d441e31b920bcc09c2ac2d" +source = "git+https://github.com/platformatic/http-rewriter#2c2319e6721f20a0eebcb37904d15aa411cc668f" dependencies = [ "bytes", "http", @@ -416,15 +416,18 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" @@ -584,9 +587,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "parking_lot" @@ -789,6 +792,12 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ruzstd" version = "0.7.3" @@ -956,9 +965,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-segmentation" diff --git a/Cargo.toml b/Cargo.toml index d1ba268..c17217a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,9 @@ crate-type = ["cdylib"] async-trait = "0.1.88" bytes = "1.10.1" http-handler = { git = "https://github.com/platformatic/http-handler" } +# http-handler = { path = "../http-handler" } http-rewriter = { git = "https://github.com/platformatic/http-rewriter" } +# http-rewriter = { path = "../http-rewriter" } # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { version = "3", default-features = false, features = ["napi4", "tokio_rt", "async"], optional = true } napi-derive = { version = "3", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 2dea575..f6830a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,10 +233,9 @@ impl PythonHandler { /// ``` #[napi] pub async fn handle_request(&self, request: &NapiRequest) -> Result { - use std::ops::Deref; let response = self .asgi - .handle(request.deref().clone()) + .handle(request.clone().into_inner()) .await .map_err(|e| Error::from_reason(e.to_string()))?; Ok(response.into()) @@ -246,11 +245,10 @@ impl PythonHandler { // request: &NapiRequest, // signal: Option, // ) -> AsyncTask { - // use std::ops::Deref; // AsyncTask::with_optional_signal( // PythonRequestTask { // asgi: self.asgi.clone(), - // request: request.deref().clone(), + // request: request.clone().into_inner(), // }, // signal, // ) @@ -276,10 +274,9 @@ impl PythonHandler { /// ``` #[napi] pub fn handle_request_sync(&self, request: &NapiRequest) -> Result { - use std::ops::Deref; let mut task = PythonRequestTask { asgi: self.asgi.clone(), - request: request.deref().clone(), + request: request.clone().into_inner(), }; task.compute().map(Into::::into) From a593c85a2bbbe15bff12a7433c70848c31c5e5f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 26 Oct 2025 02:51:33 +0000 Subject: [PATCH 07/25] Update dependency @napi-rs/cli to v3.4.1 (#35) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 60 +++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8a1b314..b87cfac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.3.1(@emnapi/runtime@1.5.0) + version: 3.4.1(@emnapi/runtime@1.5.0) '@oxc-node/core': specifier: ^0.0.32 version: 0.0.32 @@ -173,8 +173,8 @@ packages: '@types/node': optional: true - '@napi-rs/cli@3.3.1': - resolution: {integrity: sha512-KVO9tLhtOtDc8iMUJYRkj6WZcYmV6+fhXbLa1Qstrm6ZQa9McIsqjFH7PLx3BnEWwejjJrenrCX5JENwl0MpKg==} + '@napi-rs/cli@3.4.1': + resolution: {integrity: sha512-ayhm+NfrP5Hmh7vy5pfyYm/ktYtLh2PrgdLuqHTAubO7RoO2JkUE4F991AtgYxNewwXI8+guZLxU8itV7QnDrQ==} engines: {node: '>= 16'} hasBin: true peerDependencies: @@ -525,8 +525,8 @@ packages: '@octokit/openapi-types@26.0.0': resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} - '@octokit/plugin-paginate-rest@13.2.0': - resolution: {integrity: sha512-YuAlyjR8o5QoRSOvMHxSJzPtogkNMgeMv2mpccrvdUGeC3MKyfi/hS+KiFwyH/iRKIKyx+eIMsDjbt3p9r2GYA==} + '@octokit/plugin-paginate-rest@13.2.1': + resolution: {integrity: sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -537,8 +537,8 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.1.0': - resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==} + '@octokit/plugin-rest-endpoint-methods@16.1.1': + resolution: {integrity: sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -555,8 +555,8 @@ packages: resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} engines: {node: '>= 20'} - '@octokit/types@15.0.0': - resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@octokit/types@15.0.1': + resolution: {integrity: sha512-sdiirM93IYJ9ODDCBgmRPIboLbSkpLa5i+WLuXH8b8Atg+YMLAyLvDDhNWLV4OYd08tlvYfVm/dw88cqHWtw1Q==} '@oxc-node/core-android-arm-eabi@0.0.32': resolution: {integrity: sha512-Ykkz+xYJ1Hd+vjVSXljyIFRW/ZRMp2tQfPy9T2jj9F2pm5CAchqJHSXEbB3FbhdUXusUqhWLmu70JdVhS4SBcQ==} @@ -752,8 +752,8 @@ packages: supports-color: optional: true - emnapi@1.5.0: - resolution: {integrity: sha512-adAaiwTxMnHbq1u2LUf+AfDR5MYrxDVBtezGspxwk5e/Zb6KHkGNdfuMU4JBIVm6ASY06K8KalhOPUht92MsnA==} + emnapi@1.6.0: + resolution: {integrity: sha512-Hx0FqhPchuwkDauQdgamWAn6MHbOX1CPIFfObXqxTEmngZUYM9mZLcPS/civeVT5x73xkBV1ZIwKWfessIFTgQ==} peerDependencies: node-addon-api: '>= 6.1.0' peerDependenciesMeta: @@ -763,8 +763,8 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - es-toolkit@1.40.0: - resolution: {integrity: sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==} + es-toolkit@1.41.0: + resolution: {integrity: sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==} fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -949,7 +949,7 @@ snapshots: '@inquirer/type@3.0.9': {} - '@napi-rs/cli@3.3.1(@emnapi/runtime@1.5.0)': + '@napi-rs/cli@3.4.1(@emnapi/runtime@1.5.0)': dependencies: '@inquirer/prompts': 7.9.0 '@napi-rs/cross-toolchain': 1.0.3 @@ -958,8 +958,8 @@ snapshots: clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 debug: 4.4.3 - emnapi: 1.5.0 - es-toolkit: 1.40.0 + emnapi: 1.6.0 + es-toolkit: 1.41.0 js-yaml: 4.1.0 semver: 7.7.3 typanion: 3.14.0 @@ -1202,57 +1202,57 @@ snapshots: '@octokit/graphql': 9.0.2 '@octokit/request': 10.0.5 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 '@octokit/endpoint@11.0.1': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/graphql@9.0.2': dependencies: '@octokit/request': 10.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 universal-user-agent: 7.0.3 '@octokit/openapi-types@26.0.0': {} - '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': + '@octokit/plugin-paginate-rest@13.2.1(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@16.1.1(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/request-error@7.0.1': dependencies: - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 '@octokit/request@10.0.5': dependencies: '@octokit/endpoint': 11.0.1 '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.0 + '@octokit/types': 15.0.1 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 '@octokit/rest@22.0.0': dependencies: '@octokit/core': 7.0.5 - '@octokit/plugin-paginate-rest': 13.2.0(@octokit/core@7.0.5) + '@octokit/plugin-paginate-rest': 13.2.1(@octokit/core@7.0.5) '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5) + '@octokit/plugin-rest-endpoint-methods': 16.1.1(@octokit/core@7.0.5) - '@octokit/types@15.0.0': + '@octokit/types@15.0.1': dependencies: '@octokit/openapi-types': 26.0.0 @@ -1399,11 +1399,11 @@ snapshots: dependencies: ms: 2.1.3 - emnapi@1.5.0: {} + emnapi@1.6.0: {} emoji-regex@8.0.0: {} - es-toolkit@1.40.0: {} + es-toolkit@1.41.0: {} fast-content-type-parse@3.0.0: {} From 0c2d972aaf82fc4759187f80cbff4992ee89fe80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 26 Oct 2025 06:54:20 +0000 Subject: [PATCH 08/25] Update Rust crate napi to v3.4.0 (#36) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82830bc..5939668 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,7 +185,17 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" dependencies = [ - "ctor-proc-macro", + "ctor-proc-macro 0.0.6", + "dtor", +] + +[[package]] +name = "ctor" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" +dependencies = [ + "ctor-proc-macro 0.0.7", "dtor", ] @@ -195,6 +205,12 @@ version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "dtor" version = "0.1.0" @@ -504,12 +520,12 @@ dependencies = [ [[package]] name = "napi" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b74e3dce5230795bb4d2821b941706dee733c7308752507254b0497f39cad7" +checksum = "c3a1135cfe16ca43ac82ac05858554fc39c037d8e4592f2b4a83d7ef8e822f43" dependencies = [ "bitflags", - "ctor", + "ctor 0.6.0", "napi-build", "napi-sys", "nohash-hasher", @@ -519,9 +535,9 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.2.3" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14" +checksum = "3ae82775d1b06f3f07efd0666e59bbc175da8383bc372051031d7a447e94fbea" [[package]] name = "napi-derive" @@ -530,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7552d5a579b834614bbd496db5109f1b9f1c758f08224b0dee1e408333adf0d0" dependencies = [ "convert_case", - "ctor", + "ctor 0.5.0", "napi-derive-backend", "proc-macro2", "quote", @@ -552,9 +568,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4e7135a8f97aa0f1509cce21a8a1f9dcec1b50d8dee006b48a5adb69a9d64d" +checksum = "1ed8f0e23a62a3ce0fbb6527cdc056e9282ddd9916b068c46f8923e18eed5ee6" dependencies = [ "libloading", ] From 8cd9b7c36e529763d09d5ab729e0b2d9fa790c4e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Nov 2025 06:52:16 +0000 Subject: [PATCH 09/25] Update Rust crate napi-derive to v3.3.0 (#37) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5939668..0d2dd19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,32 +179,16 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "ctor" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" -dependencies = [ - "ctor-proc-macro 0.0.6", - "dtor", -] - [[package]] name = "ctor" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" dependencies = [ - "ctor-proc-macro 0.0.7", + "ctor-proc-macro", "dtor", ] -[[package]] -name = "ctor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" - [[package]] name = "ctor-proc-macro" version = "0.0.7" @@ -525,7 +509,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3a1135cfe16ca43ac82ac05858554fc39c037d8e4592f2b4a83d7ef8e822f43" dependencies = [ "bitflags", - "ctor 0.6.0", + "ctor", "napi-build", "napi-sys", "nohash-hasher", @@ -541,12 +525,12 @@ checksum = "3ae82775d1b06f3f07efd0666e59bbc175da8383bc372051031d7a447e94fbea" [[package]] name = "napi-derive" -version = "3.2.5" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7552d5a579b834614bbd496db5109f1b9f1c758f08224b0dee1e408333adf0d0" +checksum = "78665d6bdf10e9a4e6b38123efb0f66962e6197c1aea2f07cff3f159a374696d" dependencies = [ "convert_case", - "ctor 0.5.0", + "ctor", "napi-derive-backend", "proc-macro2", "quote", @@ -555,9 +539,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a81ac7486b70f2532a289603340862c06eea5a1e650c1ffeda2ce1238516a" +checksum = "42d55d01423e7264de3acc13b258fa48ca7cf38a4d25db848908ec3c1304a85a" dependencies = [ "convert_case", "proc-macro2", From 96eeac5a2df385b0cea1b8715833b2752891d514 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Wed, 5 Nov 2025 20:55:08 -0800 Subject: [PATCH 10/25] Stream and WebSocket support (#41) --- .github/workflows/CI.yml | 13 +- Cargo.lock | 84 +- Cargo.toml | 4 +- src/asgi/event_loop_handle.rs | 281 ++++ src/asgi/http.rs | 46 +- src/asgi/lifespan.rs | 1 + src/asgi/mod.rs | 1896 +++++++++++++++++++++++---- src/asgi/python_future_poller.rs | 190 +++ src/asgi/receiver.rs | 92 ++ src/asgi/runtime_handle.rs | 139 ++ src/asgi/sender.rs | 85 ++ src/asgi/websocket.rs | 100 +- src/lib.rs | 401 ++++-- test/concurrency.test.mjs | 5 +- test/fixtures/error_app.py | 6 +- test/fixtures/stream_app.py | 43 +- test/fixtures/stream_error_app.py | 34 + test/fixtures/websocket_app.py | 122 ++ test/handler.test.mjs | 4 +- test/streaming.test.mjs | 269 ++++ test/websocket-integration.test.mjs | 236 ++++ test/websocket.test.mjs | 215 +++ 22 files changed, 3819 insertions(+), 447 deletions(-) create mode 100644 src/asgi/event_loop_handle.rs create mode 100644 src/asgi/python_future_poller.rs create mode 100644 src/asgi/runtime_handle.rs create mode 100644 test/fixtures/stream_error_app.py create mode 100644 test/fixtures/websocket_app.py create mode 100644 test/streaming.test.mjs create mode 100644 test/websocket-integration.test.mjs create mode 100644 test/websocket.test.mjs diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f512f21..28d061b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -67,7 +67,7 @@ jobs: fail-fast: false matrix: settings: - - host: macos-latest + - host: macos-13 target: x86_64-apple-darwin build: pnpm run build --target x86_64-apple-darwin - host: macos-latest @@ -185,7 +185,6 @@ jobs: - '3.11' - '3.12' - '3.13' - # - '3.14-rc' runs-on: ${{ matrix.settings.host }} steps: - uses: actions/checkout@v4 @@ -206,6 +205,11 @@ jobs: with: name: bindings-${{ matrix.settings.target }} path: . + - name: Remove old prebuilt binaries + run: | + echo "Removing old prebuilt binaries from node_modules..." + rm -rf node_modules/@platformatic/python-node-* + shell: bash - name: List packages run: ls -R . shell: bash @@ -273,6 +277,11 @@ jobs: with: name: bindings-${{ matrix.settings.target }} path: . + - name: Remove old prebuilt binaries + run: | + echo "Removing old prebuilt binaries from node_modules..." + rm -rf node_modules/@platformatic/python-node-* + shell: bash - name: List packages run: ls -R . shell: bash diff --git a/Cargo.lock b/Cargo.lock index 0d2dd19..cae1b56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -117,9 +117,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" +checksum = "3ffc71fcdcdb40d6f087edddf7f8f1f8f79e6cf922f555a9ee8779752d4819bd" dependencies = [ "ctor-proc-macro", "dtor", @@ -197,9 +197,9 @@ checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" [[package]] name = "dtor" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" +checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" dependencies = [ "dtor-proc-macro", ] @@ -225,9 +225,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -377,23 +377,50 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#f60dbc830e12b1cedae4c8a4f370bc4133a868fc" +source = "git+https://github.com/platformatic/http-handler#f82b8791b8c2149739f63a55980398800fe9291e" dependencies = [ - "async-trait", "bytes", + "futures-core", "http", + "http-body", + "http-body-util", "napi", "napi-build", "napi-derive", + "tokio", + "tokio-util", ] [[package]] name = "http-rewriter" version = "1.0.0" -source = "git+https://github.com/platformatic/http-rewriter#2c2319e6721f20a0eebcb37904d15aa411cc668f" +source = "git+https://github.com/platformatic/http-rewriter#244abaece1bafa3225334030e2edcfe34a500d43" dependencies = [ "bytes", "http", @@ -640,9 +667,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -727,6 +754,8 @@ version = "1.0.0" dependencies = [ "async-trait", "bytes", + "http", + "http-body-util", "http-handler", "http-rewriter", "libc", @@ -890,9 +919,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -953,6 +982,19 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-util" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -965,9 +1007,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" diff --git a/Cargo.toml b/Cargo.toml index c17217a..ed6fb40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,13 @@ napi-support = ["dep:napi", "dep:napi-derive", "dep:napi-build", "http-handler/n [lib] name = "python_node" -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] [dependencies] async-trait = "0.1.88" bytes = "1.10.1" +http = "1.0" +http-body-util = "0.1" http-handler = { git = "https://github.com/platformatic/http-handler" } # http-handler = { path = "../http-handler" } http-rewriter = { git = "https://github.com/platformatic/http-rewriter" } diff --git a/src/asgi/event_loop_handle.rs b/src/asgi/event_loop_handle.rs new file mode 100644 index 0000000..396d203 --- /dev/null +++ b/src/asgi/event_loop_handle.rs @@ -0,0 +1,281 @@ +//! Python event loop handle management for Rust async integration. +//! +//! This module provides [`EventLoopHandle`], a type that wraps a Python asyncio +//! event loop and ensures proper cleanup when dropped, along with factory functions +//! for creating and managing the shared event loop. + +use std::sync::{Arc, Mutex, OnceLock, Weak}; + +use pyo3::prelude::*; + +use crate::HandlerError; + +/// Handle to a shared Python event loop. +/// +/// This handle manages a Python asyncio event loop that runs in a background thread. +/// When the last handle is dropped, the event loop is stopped. +/// +/// # Thread Safety +/// +/// This type implements `Send` and `Sync` to allow sharing across threads, though +/// the actual Python event loop runs in its own dedicated thread. +pub struct EventLoopHandle { + event_loop: Py, +} + +impl EventLoopHandle { + /// Create a new EventLoopHandle with a Python event loop. + /// + /// This constructor: + /// 1. Ensures Python is initialized with proper symbol visibility + /// 2. Creates a new Python asyncio event loop + /// 3. Starts a background thread to run the event loop + /// 4. Returns a handle to the event loop + /// + /// # Errors + /// + /// Returns `HandlerError` if: + /// - Python initialization fails + /// - Creating the event loop fails + /// - Starting the event loop thread fails + pub fn new() -> Result { + // Ensure Python is initialized with proper symbol visibility + crate::asgi::ensure_python_initialized(); + + // Create event loop + let event_loop = Python::attach(|py| -> Result, HandlerError> { + let asyncio = py.import("asyncio")?; + let event_loop = asyncio.call_method0("new_event_loop")?; + let event_loop_py = event_loop.unbind(); + + // Start Python thread that just runs the event loop + let loop_ = event_loop_py.clone_ref(py); + + // Spawn a dedicated std::thread for the Python event loop + // We cannot use tokio's spawn_blocking because: + // 1. It would attach to the current runtime (e.g., test runtime) + // 2. When that runtime drops, it waits for blocking tasks to complete + // 3. But the Python event loop runs forever, causing a deadlock + std::thread::Builder::new() + .name("python-event-loop".to_string()) + .spawn(move || { + Self::loop_thread(loop_); + }) + .expect("Failed to spawn Python event loop thread"); + + Ok(event_loop_py) + })?; + + Ok(Self::with_loop(event_loop)) + } + + /// Create an EventLoopHandle from an existing Python event loop object. + /// + /// # Arguments + /// + /// * `event_loop` - A Python `asyncio.AbstractEventLoop` object + /// + /// # Note + /// + /// The event loop should already be running in a background thread before + /// creating this handle. This handle only manages the lifecycle, it doesn't + /// start the event loop. + pub fn with_loop(event_loop: Py) -> Self { + Self { event_loop } + } + + /// Get or create a shared Python event loop. + /// + /// This method maintains a weak reference to the shared event loop. If the event loop + /// is still alive, it returns a strong reference to it. Otherwise, it creates a new + /// event loop. + /// + /// # Thread Safety + /// + /// This method is thread-safe and uses a mutex to protect concurrent access to + /// the weak reference. + /// + /// # Errors + /// + /// Returns `HandlerError` if: + /// - The mutex is poisoned + /// - Creating a new event loop fails + pub fn get_or_create() -> Result, HandlerError> { + let mut guard = PYTHON_EVENT_LOOP + .get_or_init(|| Mutex::new(Weak::new())) + .lock()?; + + // Try to upgrade the weak reference + if let Some(handle) = guard.upgrade() { + return Ok(handle); + } + + // Create new handle + let new_handle = Arc::new(Self::new()?); + *guard = Arc::downgrade(&new_handle); + + Ok(new_handle) + } + + /// Run a Python event loop forever in the current thread. + /// + /// This function sets the given event loop as the current event loop for the thread + /// and runs it forever. It's intended to be called in a blocking context (e.g., from + /// `tokio::task::spawn_blocking`). + /// + /// # Arguments + /// + /// * `event_loop` - A Python asyncio event loop object to run + /// + /// # Panics + /// + /// If the Python event loop encounters a fatal error, the error is printed to stderr + /// but the function does not panic. + pub fn loop_thread(event_loop: Py) { + Python::attach(|py| { + // Set the event loop for this thread and run it + let asyncio = py.import("asyncio")?; + asyncio.call_method1("set_event_loop", (event_loop.bind(py),))?; + + // Get the current event loop and run it forever + asyncio + .call_method0("get_event_loop")? + .call_method0("run_forever")?; + + Ok::<(), PyErr>(()) + }) + .unwrap_or_else(|e| { + eprintln!("Python event loop thread error: {e}"); + }); + } + + /// Get a reference to the Python event loop object. + /// + /// Returns a reference to the underlying `Py` that represents + /// the Python asyncio event loop. + pub fn event_loop(&self) -> &Py { + &self.event_loop + } +} + +impl Drop for EventLoopHandle { + fn drop(&mut self) { + // Stop the Python event loop when the last handle is dropped + Python::attach(|py| { + if let Err(e) = self.event_loop.bind(py).call_method0("stop") { + eprintln!("Failed to stop Python event loop: {e}"); + } + }); + } +} + +unsafe impl Send for EventLoopHandle {} +unsafe impl Sync for EventLoopHandle {} + +/// Global Python event loop handle storage +static PYTHON_EVENT_LOOP: OnceLock>> = OnceLock::new(); + +#[cfg(test)] +mod tests { + use super::*; + use crate::asgi::ensure_python_initialized; + + fn ensure_test_python() { + ensure_python_initialized(); + } + + #[test] + fn test_event_loop_handle_creation() { + ensure_test_python(); + + Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let event_loop = asyncio.call_method0("new_event_loop").unwrap(); + let event_loop_py = event_loop.unbind(); + + let _handle = EventLoopHandle::with_loop(event_loop_py); + // Just verify we can create it + }); + } + + #[test] + fn test_event_loop_handle_getter() { + ensure_test_python(); + + Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let event_loop = asyncio.call_method0("new_event_loop").unwrap(); + let event_loop_py = event_loop.unbind(); + let event_loop_clone = event_loop_py.clone_ref(py); + + let handle = EventLoopHandle::with_loop(event_loop_py); + + // Verify event_loop() returns the same event loop + assert!(handle.event_loop().is(&event_loop_clone)); + }); + } + + #[test] + fn test_event_loop_handle_is_running() { + ensure_test_python(); + + Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let event_loop = asyncio.call_method0("new_event_loop").unwrap(); + let event_loop_py = event_loop.unbind(); + + let handle = EventLoopHandle::with_loop(event_loop_py); + + // Verify we can check if the loop is running + let is_running: bool = handle + .event_loop() + .bind(py) + .call_method0("is_running") + .unwrap() + .extract() + .unwrap(); + + // Should not be running since we never started it + assert!(!is_running); + }); + } + + #[test] + fn test_event_loop_handle_drop_stops_loop() { + ensure_test_python(); + + let event_loop_py = Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let event_loop = asyncio.call_method0("new_event_loop").unwrap(); + event_loop.unbind() + }); + + let event_loop_clone = Python::attach(|py| event_loop_py.clone_ref(py)); + + { + let handle = EventLoopHandle::with_loop(event_loop_py); + drop(handle); // Explicitly drop to trigger stop() + } + + // After drop, calling stop again should be idempotent (or at least not crash) + Python::attach(|py| { + // The loop should still be accessible but calling stop again is fine + let result = event_loop_clone.bind(py).call_method0("stop"); + // Either it succeeds (idempotent) or it was already stopped + // We just verify it doesn't panic + let _ = result; + }); + } + + #[test] + fn test_event_loop_handle_send_sync() { + ensure_test_python(); + + // This test verifies that EventLoopHandle implements Send and Sync + fn is_send() {} + fn is_sync() {} + + is_send::(); + is_sync::(); + } +} diff --git a/src/asgi/http.rs b/src/asgi/http.rs index f47ee32..121fe6c 100644 --- a/src/asgi/http.rs +++ b/src/asgi/http.rs @@ -320,26 +320,26 @@ impl<'py> FromPyObject<'py> for HttpSendMessage { let mut headers: Vec<(String, String)> = Vec::new(); if let Ok(headers_list) = headers_py.downcast::() { for item in headers_list.iter() { - if let Ok(header_pair) = item.downcast::() { - if header_pair.len() == 2 { - let name = header_pair.get_item(0)?; - let value = header_pair.get_item(1)?; - - // Convert bytes to string - let name_str = if let Ok(bytes) = name.downcast::() { - String::from_utf8_lossy(bytes.as_bytes()).to_string() - } else { - name.extract::()? - }; - - let value_str = if let Ok(bytes) = value.downcast::() { - String::from_utf8_lossy(bytes.as_bytes()).to_string() - } else { - value.extract::()? - }; - - headers.push((name_str, value_str)); - } + if let Ok(header_pair) = item.downcast::() + && header_pair.len() == 2 + { + let name = header_pair.get_item(0)?; + let value = header_pair.get_item(1)?; + + // Convert bytes to string + let name_str = if let Ok(bytes) = name.downcast::() { + String::from_utf8_lossy(bytes.as_bytes()).to_string() + } else { + name.extract::()? + }; + + let value_str = if let Ok(bytes) = value.downcast::() { + String::from_utf8_lossy(bytes.as_bytes()).to_string() + } else { + value.extract::()? + }; + + headers.push((name_str, value_str)); } } } @@ -414,7 +414,7 @@ mod tests { .header("authorization", "Bearer token123") .header("user-agent", "test-client/1.0") .header("x-custom-header", "custom-value") - .body(bytes::BytesMut::from("request body")) + .body(http_handler::RequestBody::new()) .unwrap(); // Set socket info extension @@ -482,7 +482,7 @@ mod tests { let request = Builder::new() .method(Method::GET) .uri("/") - .body(bytes::BytesMut::new()) + .body(http_handler::RequestBody::new()) .unwrap(); let scope: HttpConnectionScope = (&request) @@ -509,7 +509,7 @@ mod tests { .method(Method::PUT) .uri("http://api.example.com/resource/123") .version(Version::HTTP_2) - .body(bytes::BytesMut::new()) + .body(http_handler::RequestBody::new()) .unwrap(); let scope: HttpConnectionScope = (&request) diff --git a/src/asgi/lifespan.rs b/src/asgi/lifespan.rs index 61c0490..fd61497 100644 --- a/src/asgi/lifespan.rs +++ b/src/asgi/lifespan.rs @@ -5,6 +5,7 @@ use pyo3::types::PyDict; use crate::asgi::AsgiInfo; /// The lifespan scope exists for the duration of the event loop. +#[allow(dead_code)] #[derive(Debug)] pub struct LifespanScope { /// An empty namespace where the application can persist state to be used diff --git a/src/asgi/mod.rs b/src/asgi/mod.rs index 7cf34b8..1c1699e 100644 --- a/src/asgi/mod.rs +++ b/src/asgi/mod.rs @@ -3,50 +3,46 @@ use std::{ ffi::CString, fs::{read_dir, read_to_string}, path::{Path, PathBuf}, - sync::{Arc, Mutex, OnceLock, Weak}, + sync::Arc, }; #[cfg(target_os = "linux")] use std::{ffi::CStr, mem}; use bytes::BytesMut; -use http_handler::{Handler, Request, RequestExt, Response, extensions::DocumentRoot}; +use http_handler::{ + Handler, Request, RequestBody, RequestExt, Response, ResponseException, WebSocketMode, + extensions::DocumentRoot, websocket::WebSocketEncoder, +}; use pyo3::prelude::*; use pyo3::types::PyModule; -use tokio::sync::oneshot; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::sync::{Mutex, oneshot}; use crate::{HandlerError, PythonHandlerTarget}; -/// HTTP response tuple: (status_code, headers, body) -type HttpResponse = (u16, Vec<(String, String)>, Vec); +/// HTTP response tuple: (status_code, headers) +type HttpResponse = (u16, Vec<(String, String)>); /// Result type for HTTP response operations type HttpResponseResult = Result; -/// Global runtime for when no tokio runtime is available -static FALLBACK_RUNTIME: OnceLock = OnceLock::new(); - -fn fallback_handle() -> tokio::runtime::Handle { - tokio::runtime::Handle::try_current().unwrap_or_else(|_| { - // No runtime exists, create a fallback one - let rt = FALLBACK_RUNTIME.get_or_init(|| { - tokio::runtime::Runtime::new().expect("Failed to create fallback tokio runtime") - }); - rt.handle().clone() - }) -} - -/// Global Python event loop handle storage -static PYTHON_EVENT_LOOP: OnceLock>> = OnceLock::new(); - +mod event_loop_handle; mod http; mod http_method; mod http_version; mod info; mod lifespan; +mod python_future_poller; mod receiver; +mod runtime_handle; mod sender; mod websocket; +use event_loop_handle::EventLoopHandle; +use python_future_poller::PythonFuturePoller; + +pub(crate) use runtime_handle::fallback_handle; + pub use http::{HttpConnectionScope, HttpReceiveMessage, HttpSendMessage}; pub use http_method::HttpMethod; pub use http_version::HttpVersion; @@ -60,79 +56,6 @@ pub use websocket::{ WebSocketConnectionScope, WebSocketReceiveMessage, WebSocketSendException, WebSocketSendMessage, }; -/// Handle to a shared Python event loop -pub struct EventLoopHandle { - event_loop: Py, -} - -impl EventLoopHandle { - /// Get the Python event loop object - pub fn event_loop(&self) -> &Py { - &self.event_loop - } -} - -impl Drop for EventLoopHandle { - fn drop(&mut self) { - // Stop the Python event loop when the last handle is dropped - Python::attach(|py| { - if let Err(e) = self.event_loop.bind(py).call_method0("stop") { - eprintln!("Failed to stop Python event loop: {e}"); - } - }); - } -} - -unsafe impl Send for EventLoopHandle {} -unsafe impl Sync for EventLoopHandle {} - -/// Ensure a Python event loop exists and return a handle to it -fn ensure_python_event_loop() -> Result, HandlerError> { - let mut guard = PYTHON_EVENT_LOOP - .get_or_init(|| Mutex::new(Weak::new())) - .lock()?; - - // Try to upgrade the weak reference - if let Some(handle) = guard.upgrade() { - return Ok(handle); - } - - // Create new handle - let new_handle = Arc::new(create_event_loop_handle()?); - *guard = Arc::downgrade(&new_handle); - - Ok(new_handle) -} - -/// Create a new EventLoopHandle with a Python event loop -fn create_event_loop_handle() -> Result { - // Ensure Python symbols are globally available before initializing - #[cfg(target_os = "linux")] - ensure_python_symbols_global(); - - // Initialize Python if not already initialized - Python::initialize(); - - // Create event loop - let event_loop = Python::attach(|py| -> Result, HandlerError> { - let asyncio = py.import("asyncio")?; - let event_loop = asyncio.call_method0("new_event_loop")?; - let event_loop_py = event_loop.unbind(); - - // Start Python thread that just runs the event loop - let loop_ = event_loop_py.clone_ref(py); - - // Try to use current runtime, fallback to creating a new one - fallback_handle().spawn_blocking(move || { - start_python_event_loop_thread(loop_); - }); - - Ok(event_loop_py) - })?; - - Ok(EventLoopHandle { event_loop }) -} - /// Core ASGI handler that loads and manages a Python ASGI application pub struct Asgi { docroot: PathBuf, @@ -152,12 +75,13 @@ impl Asgi { app_target: Option, ) -> Result { let target = app_target.unwrap_or_default(); + let docroot = docroot .map(|d| Ok(PathBuf::from(d))) .unwrap_or_else(|| current_dir().map_err(HandlerError::CurrentDirectoryError))?; // Get or create shared Python event loop - let event_loop_handle = ensure_python_event_loop()?; + let event_loop_handle = EventLoopHandle::get_or_create()?; // Load Python app let app_function = Python::attach(|py| -> Result, HandlerError> { @@ -198,117 +122,549 @@ impl Asgi { pub fn docroot(&self) -> &Path { &self.docroot } - - /// Handle a request synchronously - pub fn handle_sync(&self, request: Request) -> Result { - fallback_handle().block_on(self.handle(request)) - } } -#[async_trait::async_trait] -impl Handler for Asgi { - type Error = HandlerError; - - async fn handle(&self, request: Request) -> Result { - // Set document root extension - let mut request = request; - request.set_document_root(DocumentRoot { - path: self.docroot.clone(), - }); +// Helper function: Forward HTTP request data from DuplexStream to Python +// Returns when stream ends or error occurs +async fn forward_http_request( + mut request_stream: R, + rx: tokio::sync::mpsc::UnboundedSender, +) where + R: tokio::io::AsyncRead + Unpin, +{ + const BUFFER_SIZE: usize = 64 * 1024; // 64KB buffer + let mut buffer = BytesMut::with_capacity(BUFFER_SIZE); + loop { + let n = match request_stream.read_buf(&mut buffer).await { + Ok(n) => n, + Err(_) => break, + }; - // Create ASGI scope - let scope: HttpConnectionScope = (&request).try_into()?; + if n == 0 { + // EOF - send final message + let _ = rx.send(HttpReceiveMessage::Request { + body: vec![], + more_body: false, + }); + break; + } - // Create channels for ASGI communication - let (rx_receiver, rx) = Receiver::http(); - let (tx_sender, tx_receiver) = Sender::http(); + // Send the data we read + let data = buffer.split_to(n).to_vec(); + if rx + .send(HttpReceiveMessage::Request { + body: data, + more_body: true, + }) + .is_err() + { + // Python dropped receiver + break; + } + } +} - // Send request body - let request_message = HttpReceiveMessage::Request { - body: request.body().to_vec(), - more_body: false, - }; - rx.send(request_message).map_err(|_| { - HandlerError::PythonError(PyErr::new::( - "Failed to send request", - )) - })?; +// Helper function: Forward WebSocket request data from DuplexStream to Python +// Returns when stream ends or error occurs +async fn forward_websocket_request( + request_stream: R, + rx: tokio::sync::mpsc::UnboundedSender, +) where + R: tokio::io::AsyncRead + Unpin + Send + 'static, +{ + // JavaScript now sends WebSocket frames (auto-encoded by Request::write()) + // Use WebSocketDecoder to decode them + let mut decoder = http_handler::websocket::WebSocketDecoder::new(request_stream); - // Create response channel - let (response_tx, response_rx) = oneshot::channel(); + loop { + match decoder.read_message().await { + Ok(Some(frame)) => { + // Got a WebSocket frame - forward to Python based on type + if frame.is_text() { + if let Some(text) = frame.payload_as_text() + && rx + .send(WebSocketReceiveMessage::Receive { + text: Some(text), + bytes: None, + }) + .is_err() + { + // Python receiver dropped + break; + } + } else if frame.is_binary() { + if rx + .send(WebSocketReceiveMessage::Receive { + text: None, + bytes: Some(frame.payload), + }) + .is_err() + { + // Python receiver dropped + break; + } + } else if frame.is_close() { + // Got close frame - send disconnect to Python + let (code, reason) = frame.parse_close_payload().unzip(); + let _ = rx.send(WebSocketReceiveMessage::Disconnect { code, reason }); + break; + } + // Ignore ping/pong frames (handled automatically) + } + Ok(None) => { + // Stream ended - send disconnect + let _ = rx.send(WebSocketReceiveMessage::Disconnect { + code: Some(1000), + reason: None, + }); + break; + } + Err(_) => { + // Error reading - send disconnect + let _ = rx.send(WebSocketReceiveMessage::Disconnect { + code: Some(1006), // Abnormal closure + reason: None, + }); + break; + } + } + } +} - // Submit the ASGI app call to Python event loop - let future = Python::attach(|py| { - let scope_py = scope.into_pyobject(py)?; - let coro = self - .app_function - .call1(py, (scope_py, rx_receiver, tx_sender))?; +// Helper function: Handle HTTP response message from Python and write to DuplexStream +// Returns true if the loop should break +async fn handle_http_response_message( + msg: Option>, + response_tx: &mut Option>, + response_stream: &mut W, +) -> bool +where + W: tokio::io::AsyncWrite + Unpin, +{ + match msg { + Some(AcknowledgedMessage { + message: HttpSendMessage::HttpResponseStart { + status, headers, .. + }, + ack, + }) if response_tx.is_some() => { + // Send response.start back to main task (oneshot - only once) + if let Some(tx) = response_tx.take() + && tx.send(Ok((status, headers))).is_err() + { + // Main task dropped receiver - stop forwarding + return true; + } + if ack.send(()).is_err() { + // Python dropped receiver - stop forwarding + return true; + } + } + Some(AcknowledgedMessage { + message: HttpSendMessage::HttpResponseBody { body, more_body }, + ack, + }) => { + // Acknowledge receipt + if ack.send(()).is_err() { + // Python dropped receiver - stop forwarding + return true; + } - let asyncio = py.import("asyncio")?; - let future = asyncio.call_method1( - "run_coroutine_threadsafe", - (coro, self.event_loop_handle.event_loop()), - )?; + // Write body data if not empty + if !body.is_empty() { + if response_stream.write_all(&body).await.is_err() { + // Client disconnected + return true; + } + } - Ok::, HandlerError>(future.unbind()) - })?; + // Check if this was the final chunk + if !more_body { + // Close the write side + let _ = response_stream.shutdown().await; + return true; + } + } + None => { + // Python sender closed + return true; + } + _ => { + // Ignore other message types (e.g., duplicate response.start) + } + } + false +} - // Spawn task to collect response and monitor for Python exceptions - tokio::spawn(collect_response_with_exception_handling( - tx_receiver, - response_tx, - future, - )); +// Helper function: Handle WebSocket response message from Python and write to DuplexStream +// Returns true if the loop should break +async fn handle_websocket_response_message( + msg: Option>, + encoder: &http_handler::websocket::WebSocketEncoder, +) -> bool +where + W: tokio::io::AsyncWrite + Unpin + Send, +{ + match msg { + Some(ack_msg) => { + match ack_msg.message { + WebSocketSendMessage::Send { text, bytes } => { + // Send WebSocket frames to JavaScript (will be auto-decoded by Response::next()) + let result = if let Some(text) = text { + encoder.write_text(&text, false).await + } else if let Some(bytes) = bytes { + encoder.write_binary(&bytes, false).await + } else { + Ok(()) + }; + + if result.is_err() { + // Client disconnected or write error + return true; + } + } + WebSocketSendMessage::Close { code, reason } => { + // Send close frame + let reason_str = reason.as_deref(); + let _ = encoder.write_close(code, reason_str).await; + return true; + } + _ => {} + } + // Acknowledge receipt + if ack_msg.ack.send(()).is_err() { + // Python dropped receiver - stop forwarding + return true; + } + } + None => { + // Python sender closed + return true; + } + } + false +} - // Wait for response - let (status, headers, body) = response_rx.await??; +// Helper function: Handle Python exception +// Returns true if the loop should break +async fn handle_python_exception( + result: Result, PyErr>, + response_tx: Option>, + response_stream: Option<&mut W>, + response_exception: Option<&Arc>>>, +) -> bool +where + W: tokio::io::AsyncWrite + Unpin, +{ + if let Err(py_err) = result { + let error_msg = py_err.to_string(); + + // Python exception - send error via oneshot if response not yet started + if let Some(tx) = response_tx { + let _ = tx.send(Err(HandlerError::PythonError(py_err))); + } else { + // Response already started - store error for later retrieval and close stream + if let Some(exception_holder) = response_exception { + let mut exc = exception_holder.lock().await; + *exc = Some(ResponseException::new(error_msg)); + } - // Build response - let mut builder = http_handler::response::Builder::new().status(status); - for (name, value) in headers { - builder = builder.header(name.as_bytes(), value.as_bytes()); + if let Some(stream) = response_stream { + use tokio::io::AsyncWriteExt; + let _ = stream.shutdown().await; + } } + } + // Always return true when Python future completes (success or error) + // to exit the forwarding loop + true +} - builder - .body(BytesMut::from(&body[..])) - .map_err(HandlerError::HttpHandlerError) +// Helper function: Handle response timeout +// Returns true if the loop should break +fn handle_response_timeout(response_tx: Option>) -> bool { + // Send timeout error via oneshot + if let Some(tx) = response_tx { + let _ = tx.send(Err(HandlerError::NoResponse)); } + true } -/// Load Python library with RTLD_GLOBAL on Linux to expose interpreter symbols -#[cfg(target_os = "linux")] -fn ensure_python_symbols_global() { - // Only perform the promotion once per process - static GLOBALIZE_ONCE: OnceLock<()> = OnceLock::new(); - - GLOBALIZE_ONCE.get_or_init(|| unsafe { - let mut info: libc::Dl_info = mem::zeroed(); - if libc::dladdr(pyo3::ffi::Py_Initialize as *const _, &mut info) == 0 - || info.dli_fname.is_null() - { - eprintln!("unable to locate libpython for RTLD_GLOBAL promotion"); - return; +// Spawn HTTP forwarding task +fn spawn_http_forwarding_task( + request_stream: R, + mut tx_receiver: tokio::sync::mpsc::UnboundedReceiver>, + rx: tokio::sync::mpsc::UnboundedSender, + response_stream: W, + response_tx: oneshot::Sender, + future: Py, + response_exception: Arc>>, +) where + R: tokio::io::AsyncRead + Unpin + Send + 'static, + W: tokio::io::AsyncWrite + Unpin + Send + 'static, +{ + tokio::spawn(async move { + let mut response_tx = Some(response_tx); + let mut future_poller = PythonFuturePoller::new(future); + let timeout = tokio::time::sleep(tokio::time::Duration::from_secs(30)); + tokio::pin!(timeout); + + // Spawn request forwarding as separate task + let mut request_done = Some(tokio::spawn(forward_http_request(request_stream, rx))); + let mut response_stream = response_stream; + + loop { + tokio::select! { + // Forward response messages from Python to Node.js + response_msg = tx_receiver.recv() => { + if handle_http_response_message( + response_msg, + &mut response_tx, + &mut response_stream, + ).await { + break; + } + } + + // Monitor Python future for exceptions + result = Pin::new(&mut future_poller) => { + if handle_python_exception(result, response_tx.take(), Some(&mut response_stream), Some(&response_exception)).await { + break; + } + } + + // Timeout after 30 seconds without response.start + _ = &mut timeout, if response_tx.is_some() => { + if handle_response_timeout(response_tx.take()) { + break; + } + } + + // Wait for request forwarding to complete (only poll once) + _ = async { request_done.as_mut().unwrap().await }, if request_done.is_some() => { + request_done = None; + } + + // Exit loop if all branches are done + else => break, + } } + }); +} + +// Spawn WebSocket forwarding task +fn spawn_websocket_forwarding_task( + request_stream: R, + mut tx_receiver: tokio::sync::mpsc::UnboundedReceiver>, + rx: tokio::sync::mpsc::UnboundedSender, + response_stream: W, + future: Py, +) where + R: tokio::io::AsyncRead + Unpin + Send + 'static, + W: tokio::io::AsyncWrite + Unpin + Send + 'static, +{ + tokio::spawn(async move { + let mut future_poller = PythonFuturePoller::new(future); + + // Create WebSocket encoder for sending frames to client + let encoder = WebSocketEncoder::new(response_stream); + + // Spawn request forwarding as separate task + let mut request_done = Some(tokio::spawn(forward_websocket_request(request_stream, rx))); + + // Track if close frame was sent (write_close also closes the stream) + let mut close_sent = false; + + loop { + tokio::select! { + // Forward WebSocket messages from Python to client + response_msg = tx_receiver.recv() => { + if handle_websocket_response_message(response_msg, &encoder).await { + close_sent = true; + break; + } + } - let path_cstr = CStr::from_ptr(info.dli_fname); - let path_str = path_cstr.to_string_lossy(); + // Monitor Python future for exceptions + result = Pin::new(&mut future_poller) => { + if handle_python_exception::(result, None, None, None).await { + break; + } + } - // Clear any prior dlerror state before attempting to reopen - libc::dlerror(); + // Wait for request forwarding to complete (only poll once) + _ = async { request_done.as_mut().unwrap().await }, if request_done.is_some() => { + request_done = None; + } - let handle = libc::dlopen(info.dli_fname, libc::RTLD_NOW | libc::RTLD_GLOBAL); - if handle.is_null() { - let error = libc::dlerror(); - if !error.is_null() { - let msg = CStr::from_ptr(error).to_string_lossy(); - eprintln!("dlopen({path_str}) failed with RTLD_GLOBAL: {msg}",); - } else { - eprintln!("dlopen({path_str}) returned null without dlerror",); + // Exit loop if all branches complete + else => break, } } + + // Close the response stream only if close frame wasn't sent + // (write_close already closes the stream) + if !close_sent { + let _ = encoder.end().await; + } }); } +impl Handler for Asgi { + type Error = HandlerError; + + async fn handle(&self, request: Request) -> Result { + // Set document root extension + let mut request = request; + request.set_document_root(DocumentRoot { + path: self.docroot.clone(), + }); + + // Check if this is a WebSocket request + let is_websocket = request.extensions().get::().is_some(); + + // Extract parts + let (parts, body) = request.into_parts(); + + // Create response body + let response_body = body.create_response(); + + // Clone bodies for bidirectional forwarding + // RequestBody implements AsyncRead (reads from read_side) + // ResponseBody implements AsyncWrite (writes to write_side) + let request_reader = body.clone(); + let response_writer = response_body.clone(); + + if is_websocket { + // WebSocket mode + // Create WebSocket scope from parts by temporarily reconstructing a request + let temp_request = Request::from_parts(parts.clone(), RequestBody::new()); + let scope: WebSocketConnectionScope = (&temp_request).try_into()?; + + // Create channels for ASGI communication + let (rx_receiver, rx) = Receiver::websocket(); + let (tx_sender, mut tx_receiver) = Sender::websocket(); + + // Send connect + rx.send(WebSocketReceiveMessage::Connect) + .map_err(|_| HandlerError::NoResponse)?; + + // Submit ASGI app to Python + let future = Python::attach(|py| { + let scope_py = scope.into_pyobject(py)?; + let coro = self + .app_function + .call1(py, (scope_py, rx_receiver, tx_sender))?; + + let asyncio = py.import("asyncio")?; + let future = asyncio.call_method1( + "run_coroutine_threadsafe", + (coro, self.event_loop_handle.event_loop()), + )?; + + Ok::, HandlerError>(future.unbind()) + })?; + + // Wait for accept + match tx_receiver.recv().await { + Some(AcknowledgedMessage { + message: WebSocketSendMessage::Accept { .. }, + ack, + }) => { + // Acknowledge receipt + if ack.send(()).is_err() { + // Python dropped receiver - cannot continue + return Err(HandlerError::WebSocketNotAccepted); + } + } + _ => return Err(HandlerError::WebSocketNotAccepted), + } + + // Spawn WebSocket forwarding task + spawn_websocket_forwarding_task(request_reader, tx_receiver, rx, response_writer, future); + + // Return 101 Switching Protocols response with WebSocket body + http_handler::response::Builder::new() + .status(101) + .extension(WebSocketMode) // Mark response as WebSocket for auto-decoding + .body(response_body) + .map_err(HandlerError::HttpHandlerError) + } else { + // HTTP mode + // Create HTTP scope from parts by temporarily reconstructing a request + let temp_request = Request::from_parts(parts.clone(), RequestBody::new()); + let scope: HttpConnectionScope = (&temp_request).try_into()?; + + // Create ASGI channels + let (rx_receiver, rx) = Receiver::http(); + let (tx_sender, tx_receiver) = Sender::http(); + + // Create oneshot channel for sending response.start (or error) back to main task + let (response_tx, response_rx) = oneshot::channel::(); + + // Submit ASGI app to Python to get the future + let future = Python::attach(|py| { + let scope_py = scope.into_pyobject(py)?; + let coro = self + .app_function + .call1(py, (scope_py, rx_receiver, tx_sender))?; + + let asyncio = py.import("asyncio")?; + let future = asyncio.call_method1( + "run_coroutine_threadsafe", + (coro, self.event_loop_handle.event_loop()), + )?; + + Ok::, HandlerError>(future.unbind()) + })?; + + // Create exception holder to capture errors that occur after response.start + let response_exception = Arc::new(Mutex::new(None)); + let response_exception_clone = Arc::clone(&response_exception); + + // Spawn HTTP forwarding task + spawn_http_forwarding_task( + request_reader, + tx_receiver, + rx, + response_writer, + response_tx, + future, + response_exception_clone, + ); + + // Wait for response.start (errors are propagated from the forwarding task) + let (status, headers) = response_rx + .await + .map_err(|_| HandlerError::NoResponse)? // Channel closed without sending + ?; // Unwrap Result from the task + + // Build and return response with headers and streaming body + let mut builder = http_handler::response::Builder::new().status(status); + for (name, value) in headers { + builder = builder.header(name.as_bytes(), value.as_bytes()); + } + + let mut response = builder + .body(response_body) + .map_err(HandlerError::HttpHandlerError)?; + + // Insert response exception extension so NAPI layer can check for errors after stream ends + // The exception will be set if a Python error occurs during streaming + response.extensions_mut().insert(response_exception); + + Ok(response) + } + } +} + +impl Asgi { + /// Handle a request synchronously (continued for compatibility) + pub fn handle_sync(&self, request: Request) -> Result { + fallback_handle().block_on(self.handle(request)) + } +} + /// Find all Python site-packages directories in a virtual environment fn find_python_site_packages(venv_path: &Path) -> Vec { let mut site_packages_paths = Vec::new(); @@ -319,14 +675,14 @@ fn find_python_site_packages(venv_path: &Path) -> Vec { if let Ok(entries) = read_dir(lib_path) { for entry in entries.flatten() { let entry_path = entry.path(); - if entry_path.is_dir() { - if let Some(dir_name) = entry_path.file_name().and_then(|n| n.to_str()) { - // Look for directories matching python3.* pattern - if dir_name.starts_with("python3.") { - let site_packages = entry_path.join("site-packages"); - if site_packages.exists() { - site_packages_paths.push(site_packages); - } + if entry_path.is_dir() + && let Some(dir_name) = entry_path.file_name().and_then(|n| n.to_str()) + { + // Look for directories matching python3.* pattern + if dir_name.starts_with("python3.") { + let site_packages = entry_path.join("site-packages"); + if site_packages.exists() { + site_packages_paths.push(site_packages); } } } @@ -364,111 +720,1085 @@ fn setup_python_paths(py: Python, docroot: &Path) -> PyResult<()> { Ok(()) } -/// Start a Python thread that runs the event loop forever -fn start_python_event_loop_thread(event_loop: Py) { - Python::attach(|py| { - // Set the event loop for this thread and run it - let asyncio = py.import("asyncio")?; - asyncio.call_method1("set_event_loop", (event_loop.bind(py),))?; - - // Get the current event loop and run it forever - asyncio - .call_method0("get_event_loop")? - .call_method0("run_forever")?; - - Ok::<(), PyErr>(()) - }) - .unwrap_or_else(|e| { - eprintln!("Python event loop thread error: {e}"); +/// Ensure Python is initialized exactly once with proper symbol visibility. +/// +/// This function uses a OnceLock to ensure Python initialization happens only once +/// per process, even when called from multiple threads or tests. +pub(crate) fn ensure_python_initialized() { + use std::sync::OnceLock; + static INIT: OnceLock<()> = OnceLock::new(); + INIT.get_or_init(|| { + // On Linux, load Python library with RTLD_GLOBAL to expose interpreter symbols + #[cfg(target_os = "linux")] + unsafe { + let mut info: libc::Dl_info = mem::zeroed(); + if libc::dladdr(pyo3::ffi::Py_Initialize as *const _, &mut info) == 0 + || info.dli_fname.is_null() + { + eprintln!("unable to locate libpython for RTLD_GLOBAL promotion"); + } else { + let path_cstr = CStr::from_ptr(info.dli_fname); + let path_str = path_cstr.to_string_lossy(); + + // Clear any prior dlerror state before attempting to reopen + libc::dlerror(); + + let handle = libc::dlopen(info.dli_fname, libc::RTLD_NOW | libc::RTLD_GLOBAL); + if handle.is_null() { + let error = libc::dlerror(); + if !error.is_null() { + let msg = CStr::from_ptr(error).to_string_lossy(); + eprintln!("dlopen({path_str}) failed with RTLD_GLOBAL: {msg}",); + } else { + eprintln!("dlopen({path_str}) returned null without dlerror",); + } + } + } + } + + Python::initialize(); }); } -/// Collect ASGI response messages while monitoring for Python exceptions -async fn collect_response_with_exception_handling( - mut tx_receiver: tokio::sync::mpsc::UnboundedReceiver>, - response_tx: oneshot::Sender, - python_future: Py, -) { - let mut status = 500u16; - let mut headers = Vec::new(); - let mut body = Vec::new(); - let mut response_started = false; - - // Spawn a task to monitor the Python future for exceptions - let future_clone = Python::attach(|py| python_future.clone_ref(py)); - let mut exception_handle = tokio::task::spawn_blocking(move || { +#[cfg(test)] +mod tests { + use super::*; + use std::env; + use std::fs; + use std::sync::Arc; + use tokio::io::DuplexStream; + + /// Helper to create a test duplex stream pair + fn create_test_streams() -> (DuplexStream, DuplexStream) { + tokio::io::duplex(1024) + } + + #[test] + fn test_find_python_site_packages_empty() { + // Test with a non-existent directory + let temp_dir = std::env::temp_dir().join("nonexistent_venv"); + let result = find_python_site_packages(&temp_dir); + assert_eq!(result.len(), 0); + } + + #[test] + fn test_find_python_site_packages_with_structure() { + // Create a temporary directory structure that mimics a virtual environment + let temp_dir = std::env::temp_dir().join("test_venv_structure"); + let lib_dir = temp_dir.join("lib"); + let python_dir = lib_dir.join("python3.12"); + let site_packages = python_dir.join("site-packages"); + + // Create the directory structure + fs::create_dir_all(&site_packages).ok(); + + let result = find_python_site_packages(&temp_dir); + + // Verify we found at least one site-packages directory + assert!(!result.is_empty()); + assert!(result.iter().any(|p| p.ends_with("site-packages"))); + + // Cleanup + fs::remove_dir_all(&temp_dir).ok(); + } + + #[test] + fn test_find_python_site_packages_multiple_versions() { + // Create a temporary directory with multiple Python versions + let temp_dir = std::env::temp_dir().join("test_venv_multi"); + + for version in &["python3.11", "python3.12"] { + let lib_dir = temp_dir.join("lib"); + let python_dir = lib_dir.join(version); + let site_packages = python_dir.join("site-packages"); + fs::create_dir_all(&site_packages).ok(); + } + + let result = find_python_site_packages(&temp_dir); + + // Should find both site-packages directories + assert!(result.len() >= 1); + + // Cleanup + fs::remove_dir_all(&temp_dir).ok(); + } + + #[tokio::test] + async fn test_setup_python_paths() { + ensure_python_initialized(); + + Python::attach(|py| { + let docroot = PathBuf::from("/test/docroot"); + let result = setup_python_paths(py, &docroot); + + // Should succeed + assert!(result.is_ok()); + + // Verify sys.path was modified + let sys = py.import("sys").unwrap(); + let path = sys.getattr("path").unwrap(); + let path_list: Vec = path.extract().unwrap(); + + // The docroot should be in the path + assert!(path_list.iter().any(|p| p.contains("test/docroot"))); + }); + } + + #[tokio::test] + async fn test_setup_python_paths_with_venv() { + ensure_python_initialized(); + + // Create a test virtual environment structure + let temp_venv = std::env::temp_dir().join("test_venv_for_paths"); + let lib_dir = temp_venv.join("lib"); + let python_dir = lib_dir.join("python3.12"); + let site_packages = python_dir.join("site-packages"); + fs::create_dir_all(&site_packages).ok(); + + // Set VIRTUAL_ENV + unsafe { + env::set_var("VIRTUAL_ENV", temp_venv.to_string_lossy().to_string()); + } + + Python::attach(|py| { + let docroot = PathBuf::from("/test/docroot"); + let result = setup_python_paths(py, &docroot); + assert!(result.is_ok()); + }); + + // Cleanup + unsafe { + env::remove_var("VIRTUAL_ENV"); + } + fs::remove_dir_all(&temp_venv).ok(); + } + + #[tokio::test] + async fn test_handle_python_exception_with_error() { + ensure_python_initialized(); + + let (tx, mut rx) = oneshot::channel::(); + + let py_err = Python::attach(|_py| { + // Create a Python exception + pyo3::exceptions::PyValueError::new_err("Test error") + }); + + let should_break = + handle_python_exception::(Err(py_err), Some(tx), None, None).await; + + // Should return true to break the loop + assert!(should_break); + + // Should have sent an error + let result = rx.try_recv(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_handle_python_exception_without_tx() { + ensure_python_initialized(); + + let py_err = Python::attach(|_py| pyo3::exceptions::PyValueError::new_err("Test error")); + + // Should handle gracefully when no sender is provided + let should_break = + handle_python_exception::(Err(py_err), None, None, None).await; + assert!(should_break); + } + + #[tokio::test] + async fn test_handle_python_exception_with_success() { + ensure_python_initialized(); + + let (tx, _rx) = oneshot::channel::(); + + let py_obj = Python::attach(|py| py.None()); + + let should_break = + handle_python_exception::(Ok(py_obj), Some(tx), None, None).await; + + // Should still return true (Python future completed) + assert!(should_break); + } + + #[test] + fn test_handle_response_timeout() { + let (tx, mut rx) = oneshot::channel::(); + + let should_break = handle_response_timeout(Some(tx)); + + // Should return true to break the loop + assert!(should_break); + + // Should have sent a timeout error + let result = rx.try_recv(); + assert!(result.is_ok()); + let result = result.unwrap(); + assert!(result.is_err()); + + match result { + Err(HandlerError::NoResponse) => (), + _ => panic!("Expected NoResponse error"), + } + } + + #[test] + fn test_handle_response_timeout_no_tx() { + // Should handle gracefully when no sender is provided + let should_break = handle_response_timeout(None); + assert!(should_break); + } + + #[tokio::test] + async fn test_handle_http_response_message_start() { + let (_request_stream, mut response_stream) = create_test_streams(); + + let (tx, mut rx) = oneshot::channel::(); + let mut response_tx = Some(tx); + + let (ack_tx, mut ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: HttpSendMessage::HttpResponseStart { + status: 200, + headers: vec![("content-type".to_string(), "text/plain".to_string())], + trailers: false, + }, + ack: ack_tx, + }); + + let should_break = + handle_http_response_message(msg, &mut response_tx, &mut response_stream).await; + + // Should not break yet + assert!(!should_break); + + // Response should have been sent + assert!(response_tx.is_none()); + + let result = rx.try_recv(); + assert!(result.is_ok()); + let (status, headers) = result.unwrap().unwrap(); + assert_eq!(status, 200); + assert_eq!(headers.len(), 1); + + // Ack should have been sent + assert!(ack_rx.try_recv().is_ok()); + } + + #[tokio::test] + async fn test_handle_http_response_message_body() { + let (_request_stream, mut response_stream) = create_test_streams(); + + let mut response_tx = None; // Already sent + + let (ack_tx, mut ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: HttpSendMessage::HttpResponseBody { + body: b"Hello, World!".to_vec(), + more_body: true, + }, + ack: ack_tx, + }); + + let should_break = + handle_http_response_message(msg, &mut response_tx, &mut response_stream).await; + + // Should not break (more_body is true) + assert!(!should_break); + + // Ack should have been sent + assert!(ack_rx.try_recv().is_ok()); + } + + #[tokio::test] + async fn test_handle_http_response_message_body_final() { + let (_request_stream, mut response_stream) = create_test_streams(); + + let mut response_tx = None; + + let (ack_tx, mut ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: HttpSendMessage::HttpResponseBody { + body: b"Final chunk".to_vec(), + more_body: false, // Final chunk + }, + ack: ack_tx, + }); + + let should_break = + handle_http_response_message(msg, &mut response_tx, &mut response_stream).await; + + // Should break (final chunk) + assert!(should_break); + + // Ack should have been sent + assert!(ack_rx.try_recv().is_ok()); + } + + #[tokio::test] + async fn test_handle_http_response_message_none() { + let (_request_stream, mut response_stream) = create_test_streams(); + + let mut response_tx = None; + + let should_break = + handle_http_response_message(None, &mut response_tx, &mut response_stream).await; + + // Should break (channel closed) + assert!(should_break); + } + + #[tokio::test] + async fn test_handle_websocket_response_message_send_text() { + let (_request_stream, response_stream) = create_test_streams(); + let encoder = WebSocketEncoder::new(response_stream); + + let (ack_tx, mut ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: WebSocketSendMessage::Send { + text: Some("Hello, WebSocket!".to_string()), + bytes: None, + }, + ack: ack_tx, + }); + + let should_break = handle_websocket_response_message(msg, &encoder).await; + + // Should not break + assert!(!should_break); + + // Ack should have been sent + assert!(ack_rx.try_recv().is_ok()); + } + + #[tokio::test] + async fn test_handle_websocket_response_message_send_bytes() { + let (_request_stream, response_stream) = create_test_streams(); + let encoder = WebSocketEncoder::new(response_stream); + + let (ack_tx, mut ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: WebSocketSendMessage::Send { + text: None, + bytes: Some(vec![1, 2, 3, 4]), + }, + ack: ack_tx, + }); + + let should_break = handle_websocket_response_message(msg, &encoder).await; + + // Should not break + assert!(!should_break); + + // Ack should have been sent + assert!(ack_rx.try_recv().is_ok()); + } + + #[tokio::test] + async fn test_handle_websocket_response_message_close() { + let (_request_stream, response_stream) = create_test_streams(); + let encoder = WebSocketEncoder::new(response_stream); + + let (ack_tx, _ack_rx) = oneshot::channel::<()>(); + + let msg = Some(AcknowledgedMessage { + message: WebSocketSendMessage::Close { + code: Some(1000), + reason: Some("Normal closure".to_string()), + }, + ack: ack_tx, + }); + + let should_break = handle_websocket_response_message(msg, &encoder).await; + + // Should break (close message) + assert!(should_break); + } + + #[tokio::test] + async fn test_handle_websocket_response_message_none() { + let (_request_stream, response_stream) = create_test_streams(); + let encoder = WebSocketEncoder::new(response_stream); + + let should_break = handle_websocket_response_message(None, &encoder).await; + + // Should break (channel closed) + assert!(should_break); + } + + #[tokio::test] + async fn test_forward_http_request_with_data() { + let (request_stream, write_stream) = create_test_streams(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Write some data to the stream + tokio::spawn(async move { + let mut stream = write_stream; + stream.write_all(b"Test data").await.unwrap(); + stream.shutdown().await.unwrap(); + }); + + // Start forwarding + tokio::spawn(forward_http_request(request_stream, tx)); + + // Should receive the data + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + HttpReceiveMessage::Request { body, more_body } => { + assert_eq!(body, b"Test data"); + assert!(more_body); + } + HttpReceiveMessage::Disconnect => panic!("Expected Request message"), + } + + // Should receive EOF + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + HttpReceiveMessage::Request { body, more_body } => { + assert!(body.is_empty()); + assert!(!more_body); + } + HttpReceiveMessage::Disconnect => panic!("Expected Request message"), + } + } + + #[tokio::test] + async fn test_forward_http_request_empty_stream() { + let (request_stream, write_stream) = create_test_streams(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Close the stream immediately + drop(write_stream); + + // Start forwarding + tokio::spawn(forward_http_request(request_stream, tx)); + + // Should receive EOF immediately + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + HttpReceiveMessage::Request { body, more_body } => { + assert!(body.is_empty()); + assert!(!more_body); + } + HttpReceiveMessage::Disconnect => panic!("Expected Request message"), + } + } + + #[tokio::test] + async fn test_forward_websocket_request_text_frame() { + use http_handler::websocket::WebSocketEncoder; + + let (request_stream, write_stream) = create_test_streams(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Write a text frame + tokio::spawn(async move { + let encoder = WebSocketEncoder::new(write_stream); + encoder + .write_text("Hello, WebSocket!", false) + .await + .unwrap(); + encoder.end().await.unwrap(); + }); + + // Start forwarding + tokio::spawn(forward_websocket_request(request_stream, tx)); + + // Should receive the text message + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + WebSocketReceiveMessage::Receive { text, bytes } => { + assert_eq!(text, Some("Hello, WebSocket!".to_string())); + assert!(bytes.is_none()); + } + _ => panic!("Expected Receive message"), + } + } + + #[tokio::test] + async fn test_forward_websocket_request_binary_frame() { + use http_handler::websocket::WebSocketEncoder; + + let (request_stream, write_stream) = create_test_streams(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Write a binary frame + tokio::spawn(async move { + let encoder = WebSocketEncoder::new(write_stream); + encoder.write_binary(&[1, 2, 3, 4], false).await.unwrap(); + encoder.end().await.unwrap(); + }); + + // Start forwarding + tokio::spawn(forward_websocket_request(request_stream, tx)); + + // Should receive the binary message + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + WebSocketReceiveMessage::Receive { text, bytes } => { + assert!(text.is_none()); + assert_eq!(bytes, Some(vec![1, 2, 3, 4])); + } + _ => panic!("Expected Receive message"), + } + } + + #[tokio::test] + async fn test_forward_websocket_request_close_frame() { + use http_handler::websocket::WebSocketEncoder; + + let (request_stream, write_stream) = create_test_streams(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Write a close frame + tokio::spawn(async move { + let encoder = WebSocketEncoder::new(write_stream); + encoder + .write_close(Some(1000), Some("Normal closure")) + .await + .unwrap(); + }); + + // Start forwarding + tokio::spawn(forward_websocket_request(request_stream, tx)); + + // Should receive the disconnect message + let msg = rx.recv().await; + assert!(msg.is_some()); + + match msg.unwrap() { + WebSocketReceiveMessage::Disconnect { code, reason } => { + assert_eq!(code, Some(1000)); + assert!(reason.is_some()); + } + _ => panic!("Expected Disconnect message"), + } + } + + #[test] + fn test_ensure_python_initialized_idempotent() { + // Should be safe to call multiple times + ensure_python_initialized(); + ensure_python_initialized(); + ensure_python_initialized(); + + // Python should be initialized Python::attach(|py| { - let future_bound = future_clone.bind(py); - // Wait for the future to complete (with 30 second timeout) - match future_bound.call_method1("result", (30.0,)) { - Ok(_) => None, // Success - no exception - Err(e) => Some(e), // Exception occurred + // Should be able to use Python + let sys = py.import("sys").unwrap(); + assert!(sys.hasattr("version").unwrap()); + }); + } + + // ===== Integration Tests ===== + // These tests verify the full Asgi handler flow end-to-end + + /// Helper to create a test request and spawn body writing task + /// Returns the request immediately while body writing happens concurrently + fn create_test_request(method: &str, path: &str, body: Vec) -> Request { + use http_handler::{Method, Uri, Version}; + use tokio::io::AsyncWriteExt; + + let method_enum = match method { + "GET" => Method::GET, + "POST" => Method::POST, + "PUT" => Method::PUT, + "DELETE" => Method::DELETE, + _ => Method::GET, + }; + + let uri: Uri = path.parse().unwrap(); + + // Build a basic HTTP request using ::http::Request builder + let http_request = ::http::Request::builder() + .method(method_enum) + .uri(uri) + .version(Version::HTTP_11) + .body(()) + .unwrap(); + + // Split into parts and body + let (parts, _) = http_request.into_parts(); + + // Create request from parts with proper body + let request = Request::from_parts(parts, RequestBody::new()); + + // Spawn a task to write body data to the request stream + // This allows the request to be returned immediately while body writing happens concurrently + let mut body_writer = request.body().clone(); + tokio::spawn(async move { + if !body.is_empty() { + body_writer.write_all(&body).await.unwrap(); } - }) - }); - loop { - tokio::select! { - // Check for messages from the ASGI app - msg = tx_receiver.recv() => { - match msg { - Some(ack_msg) => { - let AcknowledgedMessage { message, ack } = ack_msg; - - match message { - HttpSendMessage::HttpResponseStart { - status: s, - headers: h, - .. - } => { - status = s; - headers = h; - response_started = true; - } - HttpSendMessage::HttpResponseBody { body: b, more_body } => { - if response_started { - body.extend_from_slice(&b); - if !more_body { - let _ = ack.send(()); - let _ = response_tx.send(Ok((status, headers, body))); - return; - } - } - } - } + // Always close the stream when done + body_writer.shutdown().await.unwrap(); + }); - let _ = ack.send(()); - } - None => { - // Channel closed without a complete response - let _ = response_tx.send(Err(if response_started { - HandlerError::ResponseInterrupted - } else { - HandlerError::NoResponse - })); - return; - } + request + } + + /// Helper to read full response body + async fn read_response_body(response: Response) -> (u16, Vec<(String, String)>, Vec) { + use http_body_util::BodyExt; + + let (parts, mut body) = response.into_parts(); + let status = parts.status.as_u16(); + + let headers: Vec<(String, String)> = parts + .headers + .iter() + .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string())) + .collect(); + + let mut body_bytes = Vec::new(); + while let Some(result) = body.frame().await { + if let Ok(frame) = result { + if let Ok(data) = frame.into_data() { + body_bytes.extend_from_slice(&data); } } - // Check if the Python coroutine raised an exception - exception_result = &mut exception_handle => { - match exception_result { - Ok(Some(py_err)) => { - // Python exception occurred - let _ = response_tx.send(Err(HandlerError::PythonError(py_err))); - return; - } - Ok(None) => { - // Python coroutine completed successfully - // Continue waiting for response messages - } - Err(e) => { - // Tokio task error - let _ = response_tx.send(Err(HandlerError::TokioError(e.to_string()))); - return; - } - } + } + + (status, headers, body_bytes) + } + + #[tokio::test] + async fn test_asgi_integration_basic_request() { + ensure_python_initialized(); + + // Create Asgi handler with echo_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "echo_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create a simple POST request with body + let request = create_test_request("POST", "/test/path", b"Hello, World!".to_vec()); + + // Handle the request + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + + // Read the full response + let (status, headers, body) = read_response_body(response).await; + + // Verify response + assert_eq!(status, 200); + assert!( + headers + .iter() + .any(|(k, v)| k == "content-type" && v.contains("application/json")) + ); + assert!( + headers + .iter() + .any(|(k, v)| k == "x-echo-method" && v == "POST") + ); + assert!( + headers + .iter() + .any(|(k, v)| k == "x-echo-path" && v == "/test/path") + ); + + let body_str = String::from_utf8(body).unwrap(); + assert!(body_str.contains("Hello, World!")); + assert!(body_str.contains("POST")); + assert!(body_str.contains("/test/path")); + } + + #[tokio::test] + async fn test_asgi_integration_streaming_response() { + ensure_python_initialized(); + + // Create Asgi handler with stream_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "stream_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create a GET request to streaming endpoint + let request = create_test_request("GET", "/stream?count=3", vec![]); + + // Handle the request - this should return IMMEDIATELY after headers are ready + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + + // Verify we got headers back (status code available) + let status = response.status().as_u16(); + assert_eq!(status, 200, "Should get 200 status immediately"); + + // Now read the streaming body + let (_, headers, body) = read_response_body(response).await; + + // Verify response headers + assert!( + headers + .iter() + .any(|(k, v)| k == "content-type" && v.contains("text/plain")) + ); + + // Verify we got all chunks + let body_str = String::from_utf8(body).unwrap(); + assert!(body_str.contains("Chunk 1")); + assert!(body_str.contains("Chunk 2")); + assert!(body_str.contains("Chunk 3")); + } + + #[tokio::test] + async fn test_asgi_integration_early_header_return() { + ensure_python_initialized(); + + // Create Asgi handler with stream_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "stream_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create request + let request = create_test_request("GET", "/stream?count=5", vec![]); + + // Track timing - handle() should return quickly with just headers + let start = std::time::Instant::now(); + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + let header_time = start.elapsed(); + + // Headers should be available almost immediately (well before all chunks) + // The stream_app has 0.01s delay per chunk, so 5 chunks = ~50ms + // We should get headers back in much less time + assert!( + header_time.as_millis() < 30, + "Headers should return quickly, took {}ms", + header_time.as_millis() + ); + + // Verify we have a valid response with headers + assert_eq!(response.status().as_u16(), 200); + assert!(response.headers().get("content-type").is_some()); + + // The body stream should still be available for reading + let (_, _, body) = read_response_body(response).await; + let body_str = String::from_utf8(body).unwrap(); + + // Verify all chunks arrived + for i in 1..=5 { + assert!(body_str.contains(&format!("Chunk {}", i))); + } + } + + #[tokio::test] + async fn test_asgi_integration_streaming_request_body() { + ensure_python_initialized(); + + // Create Asgi handler with echo_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "echo_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create request with body + let large_body = "x".repeat(10000); // 10KB body + let request = create_test_request("POST", "/test", large_body.as_bytes().to_vec()); + + // Handle request + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + + // Verify response + let (status, _, body) = read_response_body(response).await; + assert_eq!(status, 200); + + let body_str = String::from_utf8(body).unwrap(); + // The echo app should echo back our large body + assert!( + body_str.contains(&large_body[..100]), + "Should contain start of body" + ); + } + + #[tokio::test] + async fn test_asgi_integration_websocket_connection() { + ensure_python_initialized(); + + // Create Asgi handler with websocket_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "websocket_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create WebSocket upgrade request + let mut request = create_test_request("GET", "/echo", vec![]); + + // Add WebSocket mode extension + request.extensions_mut().insert(http_handler::WebSocketMode); + + // Handle request + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + + // Verify we got 101 Switching Protocols + assert_eq!( + response.status().as_u16(), + 101, + "Should get 101 for WebSocket upgrade" + ); + + // Response body should be the WebSocket stream + // We can't easily test the full WebSocket flow here without more infrastructure, + // but we've verified the upgrade works + } + + #[tokio::test] + async fn test_asgi_integration_error_handling() { + ensure_python_initialized(); + + // Create Asgi handler with error_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "error_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create request that should trigger error + let request = create_test_request("GET", "/error", vec![]); + + // Handle request - should return error + let result = asgi.handle(request).await; + + // Should get an error + assert!(result.is_err(), "Error path should return an error"); + + match result { + Err(HandlerError::PythonError(_)) => { + // Expected - Python raised an exception } + Err(e) => panic!("Expected PythonError, got: {:?}", e), + Ok(_) => panic!("Expected error but got success"), + } + } + + #[tokio::test] + async fn test_asgi_integration_status_codes() { + ensure_python_initialized(); + + // Create Asgi handler with status_app + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "status_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Test different status codes + for status_code in &[200, 201, 404, 500] { + let request = create_test_request("GET", &format!("/status/{}", status_code), vec![]); + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + + assert_eq!( + response.status().as_u16(), + *status_code, + "Should return status code {}", + status_code + ); + } + } + + #[tokio::test] + async fn test_asgi_integration_concurrent_requests() { + ensure_python_initialized(); + + // Create Asgi handler + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Arc::new( + Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "echo_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"), + ); + + // Launch multiple concurrent requests + let mut handles = vec![]; + + for i in 0..10 { + let asgi = Arc::clone(&asgi); + let handle = tokio::spawn(async move { + let body = format!("Request {}", i); + let request = create_test_request("POST", "/test", body.as_bytes().to_vec()); + + let response = asgi + .handle(request) + .await + .expect("Failed to handle request"); + let (status, _, response_body) = read_response_body(response).await; + + assert_eq!(status, 200); + let response_str = String::from_utf8(response_body).unwrap(); + assert!(response_str.contains(&format!("Request {}", i))); + }); + handles.push(handle); } + + // Wait for all requests to complete + for handle in handles { + handle.await.expect("Task failed"); + } + } + + #[tokio::test] + async fn test_asgi_docroot() { + ensure_python_initialized(); + + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "echo_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Verify docroot is set correctly + assert_eq!(asgi.docroot(), test_fixtures.as_path()); + } + + /// Test that replicates the exact NAPI layer pattern to see if we can reproduce the hang + #[test] + fn test_asgi_integration_napi_pattern() { + use tokio::io::AsyncWriteExt; + + ensure_python_initialized(); + + // Create Asgi handler + let test_fixtures = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test/fixtures"); + let asgi = Asgi::new( + Some(test_fixtures.to_string_lossy().to_string()), + Some(PythonHandlerTarget { + file: "echo_app".to_string(), + function: "app".to_string(), + }), + ) + .expect("Failed to create Asgi handler"); + + // Create request without spawning concurrent body writer + let method_enum = http_handler::Method::POST; + let uri: http_handler::Uri = "/test/path".parse().unwrap(); + let http_request = ::http::Request::builder() + .method(method_enum) + .uri(uri) + .version(http_handler::Version::HTTP_11) + .body(()) + .unwrap(); + let (parts, _) = http_request.into_parts(); + let mut request = Request::from_parts(parts, RequestBody::new()); + + // Replicate the NAPI pattern: use fallback_handle().block_on() + let response = super::fallback_handle().block_on(async { + let body_data = b"Hello, World!"; + + // Write body data synchronously (like NAPI layer does) + { + let body = request.body_mut(); + body + .write_all(body_data) + .await + .expect("Failed to write body"); + } + + // Shutdown stream (like NAPI layer does for non-WebSocket) + { + let body = request.body_mut(); + body.shutdown().await.expect("Failed to shutdown stream"); + } + + // Now call handle + asgi + .handle(request) + .await + .expect("Failed to handle request") + }); + + // Read and verify response + let (status, headers, body) = fallback_handle().block_on(read_response_body(response)); + assert_eq!(status, 200); + assert!( + headers + .iter() + .any(|(k, v)| k == "content-type" && v.contains("application/json")) + ); + + let body_str = String::from_utf8(body).expect("Invalid UTF-8 in response body"); + assert!( + body_str.contains("Hello, World!"), + "Response should echo the request body" + ); } } diff --git a/src/asgi/python_future_poller.rs b/src/asgi/python_future_poller.rs new file mode 100644 index 0000000..9429f70 --- /dev/null +++ b/src/asgi/python_future_poller.rs @@ -0,0 +1,190 @@ +//! Python Future polling implementation for Rust async integration. +//! +//! This module provides [`PythonFuturePoller`], a type that implements the Rust +//! [`Future`] trait by polling a Python `concurrent.futures.Future` object. + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use pyo3::prelude::*; + +/// Future that polls a Python concurrent.futures.Future for completion. +/// +/// This future polls a Python concurrent.futures.Future and returns a Result +/// containing either the success value or the exception when the future completes. +pub struct PythonFuturePoller(Py); + +impl PythonFuturePoller { + /// Create a new `PythonFuturePoller` from a Python future object. + /// + /// # Arguments + /// + /// * `future` - A Python `concurrent.futures.Future` or `asyncio.Future` object + pub fn new(future: Py) -> Self { + Self(future) + } +} + +impl Future for PythonFuturePoller { + type Output = Result, PyErr>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Python::attach(|py| { + let future_bound = self.0.bind(py); + + // First check if future is done + let is_done: bool = future_bound + .call_method0("done") + .ok() + .and_then(|result| result.extract().ok()) + .unwrap_or(false); + + if is_done { + // Future is done - get the result (Ok for success, Err for exception) + Poll::Ready(match future_bound.call_method0("result") { + Ok(value) => Ok(value.unbind()), + Err(err) => Err(err), + }) + } else { + // Not done yet, wake the task to poll again + cx.waker().wake_by_ref(); + Poll::Pending + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::asgi::ensure_python_initialized; + + /// Ensure Python is initialized for tests (only once) + fn ensure_test_python() { + ensure_python_initialized(); + } + + #[test] + fn test_python_future_poller_creation() { + ensure_test_python(); + + Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let loop_ = asyncio.call_method0("new_event_loop").unwrap(); + let future = loop_.call_method0("create_future").unwrap(); + + let _poller = PythonFuturePoller::new(future.unbind()); + // Just verify we can create it + }); + } + + #[tokio::test] + async fn test_python_future_poller_with_completed_future() { + ensure_test_python(); + + let future = Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let loop_ = asyncio.call_method0("new_event_loop").unwrap(); + let future = loop_.call_method0("create_future").unwrap(); + + // Immediately complete the future with a result + future.call_method1("set_result", (42,)).unwrap(); + + future.unbind() + }); + + let poller = PythonFuturePoller::new(future); + let result = poller.await; + + assert!(result.is_ok()); + Python::attach(|py| { + let value: i32 = result.unwrap().extract(py).unwrap(); + assert_eq!(value, 42); + }); + } + + #[tokio::test] + async fn test_python_future_poller_with_exception() { + ensure_test_python(); + + let future = Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let loop_ = asyncio.call_method0("new_event_loop").unwrap(); + let future = loop_.call_method0("create_future").unwrap(); + + // Set an exception on the future + let exception = py + .import("builtins") + .unwrap() + .getattr("ValueError") + .unwrap() + .call1(("test error",)) + .unwrap(); + future.call_method1("set_exception", (exception,)).unwrap(); + + future.unbind() + }); + + let poller = PythonFuturePoller::new(future); + let result = poller.await; + + assert!(result.is_err()); + let err = result.unwrap_err(); + let err_str = format!("{:?}", err); + assert!( + err_str.contains("ValueError") || err_str.contains("test error"), + "Expected ValueError with 'test error', got: {}", + err_str + ); + } + + #[tokio::test] + async fn test_python_future_poller_with_string_result() { + ensure_test_python(); + + let future = Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let loop_ = asyncio.call_method0("new_event_loop").unwrap(); + let future = loop_.call_method0("create_future").unwrap(); + + // Complete with a string + future.call_method1("set_result", ("hello world",)).unwrap(); + + future.unbind() + }); + + let poller = PythonFuturePoller::new(future); + let result = poller.await; + + assert!(result.is_ok()); + Python::attach(|py| { + let value: String = result.unwrap().extract(py).unwrap(); + assert_eq!(value, "hello world"); + }); + } + + #[tokio::test] + async fn test_python_future_poller_with_none() { + ensure_test_python(); + + let future = Python::attach(|py| { + let asyncio = py.import("asyncio").unwrap(); + let loop_ = asyncio.call_method0("new_event_loop").unwrap(); + let future = loop_.call_method0("create_future").unwrap(); + + // Complete with None + future.call_method1("set_result", (py.None(),)).unwrap(); + + future.unbind() + }); + + let poller = PythonFuturePoller::new(future); + let result = poller.await; + + assert!(result.is_ok()); + Python::attach(|py| { + assert!(result.unwrap().is_none(py)); + }); + } +} diff --git a/src/asgi/receiver.rs b/src/asgi/receiver.rs index e8c9622..2dbe3d6 100644 --- a/src/asgi/receiver.rs +++ b/src/asgi/receiver.rs @@ -74,3 +74,95 @@ impl Receiver { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::asgi::ensure_python_initialized; + use crate::asgi::http::HttpReceiveMessage; + use crate::asgi::lifespan::LifespanReceiveMessage; + use crate::asgi::websocket::WebSocketReceiveMessage; + + #[test] + fn test_receiver_http_creation() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::http(); + // Verify we can send a message + let result = tx.send(HttpReceiveMessage::Request { + body: vec![], + more_body: false, + }); + assert!(result.is_ok(), "Should be able to send message"); + } + + #[test] + fn test_receiver_websocket_creation() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::websocket(); + // Verify we can send a message + let result = tx.send(WebSocketReceiveMessage::Connect); + assert!(result.is_ok(), "Should be able to send message"); + } + + #[test] + fn test_receiver_lifespan_creation() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::lifespan(); + // Verify we can send a message + let result = tx.send(LifespanReceiveMessage::LifespanStartup); + assert!(result.is_ok(), "Should be able to send message"); + } + + #[tokio::test] + async fn test_receiver_http_message_flow() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::http(); + + // Send a message and verify it succeeds + let message = HttpReceiveMessage::Request { + body: b"test body".to_vec(), + more_body: false, + }; + let result = tx.send(message); + assert!( + result.is_ok(), + "Should be able to send message through channel" + ); + } + + #[tokio::test] + async fn test_receiver_websocket_message_flow() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::websocket(); + + // Send a message and verify it succeeds + let message = WebSocketReceiveMessage::Receive { + bytes: None, + text: Some("test message".to_string()), + }; + let result = tx.send(message); + assert!( + result.is_ok(), + "Should be able to send message through channel" + ); + } + + #[tokio::test] + async fn test_receiver_lifespan_message_flow() { + ensure_python_initialized(); + + let (_receiver, tx) = Receiver::lifespan(); + + // Send multiple messages and verify they succeed + let result1 = tx.send(LifespanReceiveMessage::LifespanStartup); + assert!(result1.is_ok(), "Should be able to send startup message"); + + let result2 = tx.send(LifespanReceiveMessage::LifespanShutdown); + assert!(result2.is_ok(), "Should be able to send shutdown message"); + } +} diff --git a/src/asgi/runtime_handle.rs b/src/asgi/runtime_handle.rs new file mode 100644 index 0000000..1941283 --- /dev/null +++ b/src/asgi/runtime_handle.rs @@ -0,0 +1,139 @@ +//! Tokio runtime handle management for async operations. +//! +//! This module provides [`fallback_handle()`], a function that ensures a Tokio +//! runtime handle is available for async operations, creating a fallback runtime +//! if necessary. + +use std::sync::OnceLock; + +/// Global fallback runtime for when no tokio runtime is available +static FALLBACK_RUNTIME: OnceLock = OnceLock::new(); + +/// Get a tokio runtime handle, creating a fallback if needed. +/// +/// This function attempts to get the handle of the current tokio runtime. +/// If no runtime is available (i.e., not running within a tokio context), +/// it creates and returns a handle to a global fallback runtime. +/// +/// # Returns +/// +/// A `tokio::runtime::Handle` that can be used to spawn tasks and perform +/// async operations. +/// +/// # Panics +/// +/// Panics if creating the fallback runtime fails, though this is extremely +/// unlikely in normal operation. +/// +/// # Thread Safety +/// +/// This function is thread-safe. The fallback runtime is created once and +/// shared across all threads that need it. +pub(crate) fn fallback_handle() -> tokio::runtime::Handle { + tokio::runtime::Handle::try_current().unwrap_or_else(|_| { + // No runtime exists, create a fallback one + let rt = FALLBACK_RUNTIME.get_or_init(|| { + tokio::runtime::Runtime::new().expect("Failed to create fallback tokio runtime") + }); + rt.handle().clone() + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_fallback_handle_outside_runtime() { + // This test runs outside a tokio runtime + // Should create and use the fallback runtime + let handle = fallback_handle(); + + // Verify we can use the handle to block_on a future + handle.block_on(async { + // Simple async operation + let value = 42; + assert_eq!(value, 42); + }); + } + + #[tokio::test] + async fn test_fallback_handle_inside_runtime() { + // This test runs inside a tokio runtime + // Should use the current runtime's handle + let handle = fallback_handle(); + + // Verify we can spawn a task + let result = handle + .spawn(async { + // Simple async operation + 42 + }) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 42); + } + + #[test] + fn test_fallback_handle_is_consistent() { + // Calling fallback_handle multiple times outside a runtime + // should return handles to the same fallback runtime + let handle1 = fallback_handle(); + let handle2 = fallback_handle(); + + // Both handles should work + handle1.block_on(async { + assert!(true); + }); + + handle2.block_on(async { + assert!(true); + }); + } + + #[test] + fn test_fallback_handle_can_spawn_blocking() { + // Test that we can use spawn_blocking with the handle + let handle = fallback_handle(); + + let result = handle.block_on(async { + handle + .spawn_blocking(|| { + // CPU-bound work + let mut sum = 0; + for i in 0..100 { + sum += i; + } + sum + }) + .await + }); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 4950); + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_fallback_handle_multi_thread() { + // Test that fallback_handle works correctly in a multi-threaded runtime + let handle = fallback_handle(); + + // Spawn multiple tasks concurrently + let tasks: Vec<_> = (0..10) + .map(|i| { + handle.spawn(async move { + // Simple async work + i * 2 + }) + }) + .collect(); + + // Wait for all tasks to complete + for (i, task) in tasks.into_iter().enumerate() { + let result = task.await; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), i * 2); + } + } +} diff --git a/src/asgi/sender.rs b/src/asgi/sender.rs index 602eeb6..4be5946 100644 --- a/src/asgi/sender.rs +++ b/src/asgi/sender.rs @@ -100,3 +100,88 @@ impl Sender { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::asgi::ensure_python_initialized; + + #[test] + fn test_sender_http_creation() { + ensure_python_initialized(); + + let (_sender, mut rx) = Sender::http(); + // Verify receiver is open + assert!(rx.try_recv().is_err(), "Channel should be empty but open"); + } + + #[test] + fn test_sender_websocket_creation() { + ensure_python_initialized(); + + let (_sender, mut rx) = Sender::websocket(); + // Verify receiver is open + assert!(rx.try_recv().is_err(), "Channel should be empty but open"); + } + + #[test] + fn test_sender_lifespan_creation() { + ensure_python_initialized(); + + let (_sender, mut rx) = Sender::lifespan(); + // Verify receiver is open + assert!(rx.try_recv().is_err(), "Channel should be empty but open"); + } + + #[test] + fn test_sender_http_channel_closed() { + ensure_python_initialized(); + + let (sender, rx) = Sender::http(); + + // Drop the receiver to close the channel + drop(rx); + + // Sender should still exist but attempts to send will fail + // We can't easily test the __call__ method without Python, but we've verified + // the channel setup works + drop(sender); + } + + #[test] + fn test_sender_websocket_channel_closed() { + ensure_python_initialized(); + + let (sender, rx) = Sender::websocket(); + + // Drop the receiver to close the channel + drop(rx); + + // Sender should still exist + drop(sender); + } + + #[test] + fn test_sender_lifespan_channel_closed() { + ensure_python_initialized(); + + let (sender, rx) = Sender::lifespan(); + + // Drop the receiver to close the channel + drop(rx); + + // Sender should still exist + drop(sender); + } + + #[tokio::test] + async fn test_acknowledged_message_structure() { + ensure_python_initialized(); + + let (_sender, mut rx) = Sender::http(); + + // We can't easily send through the sender without Python, but we can verify + // the receiver side works + assert!(rx.try_recv().is_err(), "Channel should be empty initially"); + } +} diff --git a/src/asgi/websocket.rs b/src/asgi/websocket.rs index b2aa8fd..3cc9db2 100644 --- a/src/asgi/websocket.rs +++ b/src/asgi/websocket.rs @@ -1,6 +1,8 @@ +use http_handler::{Request, RequestExt, Version}; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::types::PyDict; +use std::net::SocketAddr; use crate::asgi::{AsgiInfo, HttpVersion}; @@ -58,6 +60,99 @@ pub struct WebSocketConnectionScope { state: Option>, } +impl TryFrom<&Request> for WebSocketConnectionScope { + type Error = PyErr; + + fn try_from(request: &Request) -> Result { + // Extract HTTP version + let http_version = match request.version() { + Version::HTTP_10 => HttpVersion::V1_0, + Version::HTTP_11 => HttpVersion::V1_1, + Version::HTTP_2 => HttpVersion::V2_0, + Version::HTTP_3 => HttpVersion::V2_0, // treat HTTP/3 as HTTP/2 for ASGI + _ => HttpVersion::V1_1, // default fallback + }; + + // Extract scheme from URI (typically wss or ws for WebSocket) + let scheme = request + .uri() + .scheme_str() + .map(|s| { + if s == "https" || s == "wss" { + "wss" + } else { + "ws" + } + }) + .unwrap_or("ws") + .to_string(); + + // Extract path + let path = request.uri().path().to_string(); + + // Extract raw path (same as path for now, as we don't have the raw bytes) + let raw_path = path.clone(); + + // Extract query string + let query_string = request.uri().query().unwrap_or("").to_string(); + + // Extract root path from DocumentRoot extension + let root_path = request + .document_root() + .map(|doc_root| doc_root.path.to_string_lossy().to_string()) + .unwrap_or_default(); + + // Convert headers + let headers: Vec<(String, String)> = request + .headers() + .iter() + .map(|(name, value)| { + ( + name.as_str().to_lowercase(), + value.to_str().unwrap_or("").to_string(), + ) + }) + .collect(); + + // Extract client and server from socket info if available + let (client, server) = if let Some(socket_info) = request.socket_info() { + let client = socket_info.remote.map(|addr| match addr { + SocketAddr::V4(v4) => (v4.ip().to_string(), v4.port()), + SocketAddr::V6(v6) => (v6.ip().to_string(), v6.port()), + }); + let server = socket_info.local.map(|addr| match addr { + SocketAddr::V4(v4) => (v4.ip().to_string(), v4.port()), + SocketAddr::V6(v6) => (v6.ip().to_string(), v6.port()), + }); + (client, server) + } else { + (None, None) + }; + + // Extract subprotocols from Sec-WebSocket-Protocol header + let subprotocols: Vec = request + .headers() + .get("sec-websocket-protocol") + .and_then(|h| h.to_str().ok()) + .map(|protocols| protocols.split(',').map(|p| p.trim().to_string()).collect()) + .unwrap_or_default(); + + Ok(WebSocketConnectionScope { + http_version, + scheme, + path, + raw_path, + query_string, + root_path, + headers, + client, + server, + subprotocols, + state: None, + }) + } +} + impl<'py> IntoPyObject<'py> for WebSocketConnectionScope { type Target = PyDict; type Output = Bound<'py, Self::Target>; @@ -234,10 +329,7 @@ impl<'py> FromPyObject<'py> for WebSocketSendMessage { let headers: Vec<(String, String)> = dict .get_item("headers")? - .ok_or_else(|| { - PyValueError::new_err("Missing 'headers' key in WebSocket accept message") - })? - .extract()?; + .map_or(Ok(vec![]), |v| v.extract())?; Ok(WebSocketSendMessage::Accept { subprotocol, diff --git a/src/lib.rs b/src/lib.rs index f6830a0..1c7dc97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,13 @@ #[cfg(feature = "napi-support")] use std::{ffi::c_char, sync::Arc}; +#[cfg(feature = "napi-support")] +use bytes::{Bytes, BytesMut}; + #[cfg(feature = "napi-support")] use http_handler::napi::{Request as NapiRequest, Response as NapiResponse}; #[cfg(feature = "napi-support")] -use http_handler::{Handler, Request, Response}; +use http_handler::{BodyBuffer, Handler, Request, Response, ResponseBody}; #[cfg(feature = "napi-support")] #[allow(unused_imports)] use http_rewriter::napi::Rewriter; @@ -213,7 +216,11 @@ impl PythonHandler { self.asgi.docroot().display().to_string() } - /// Handle a Python request. + /// Handle a Python request with buffered response (backward compatible). + /// + /// This method uses the same asgi.handle() as handleStream, but buffers the + /// response body before returning. The body is available synchronously via + /// response.body getter. /// /// # Examples /// @@ -229,30 +236,60 @@ impl PythonHandler { /// })); /// /// console.log(response.status); - /// console.log(response.body); + /// console.log(response.body.toString()); // Body is buffered and ready /// ``` #[napi] - pub async fn handle_request(&self, request: &NapiRequest) -> Result { - let response = self - .asgi - .handle(request.clone().into_inner()) - .await - .map_err(|e| Error::from_reason(e.to_string()))?; - Ok(response.into()) + pub fn handle_request( + &self, + request: NapiRequest, + signal: Option, + ) -> AsyncTask { + AsyncTask::with_optional_signal( + PythonRequestTask { + asgi: self.asgi.clone(), + request: Some(request.into_inner()), + }, + signal, + ) + } + + /// Handle a Python request with streaming response. + /// + /// This method uses the same asgi.handle() as handleRequest, but returns + /// immediately with a streaming response. Use AsyncIterator to read chunks. + /// + /// # Examples + /// + /// ```js + /// const python = new Python({ + /// docroot: process.cwd(), + /// argv: process.argv + /// }); + /// + /// const response = await python.handleStream(new Request({ + /// method: 'GET', + /// url: 'http://example.com' + /// })); + /// + /// // Read response via AsyncIterator + /// for await (const chunk of response) { + /// console.log(chunk.toString()); + /// } + /// ``` + #[napi] + pub fn handle_stream( + &self, + request: NapiRequest, + signal: Option, + ) -> AsyncTask { + AsyncTask::with_optional_signal( + PythonStreamTask { + asgi: self.asgi.clone(), + request: Some(request.into_inner()), + }, + signal, + ) } - // pub fn handle_request( - // &self, - // request: &NapiRequest, - // signal: Option, - // ) -> AsyncTask { - // AsyncTask::with_optional_signal( - // PythonRequestTask { - // asgi: self.asgi.clone(), - // request: request.clone().into_inner(), - // }, - // signal, - // ) - // } /// Handle a PHP request synchronously. /// @@ -273,107 +310,198 @@ impl PythonHandler { /// console.log(response.body); /// ``` #[napi] - pub fn handle_request_sync(&self, request: &NapiRequest) -> Result { + pub fn handle_request_sync(&self, request: NapiRequest) -> Result { let mut task = PythonRequestTask { asgi: self.asgi.clone(), - request: request.clone().into_inner(), + request: Some(request.into_inner()), }; task.compute().map(Into::::into) } } -/// Task container to run a Python request in a worker thread. +/// Task for buffered request handling. +/// Uses identical asgi.handle() call, just buffers the body afterward. #[cfg(feature = "napi-support")] pub struct PythonRequestTask { asgi: Arc, - request: Request, + request: Option, } -/// Error types for the Python request handler. -#[allow(clippy::large_enum_variant)] -#[derive(thiserror::Error, Debug)] -pub enum HandlerError { - /// IO errors that may occur during file operations. - #[error("IO Error: {0}")] - IoError(#[from] std::io::Error), - - /// Error when the current directory cannot be determined. - #[error("Failed to get current directory: {0}")] - CurrentDirectoryError(std::io::Error), - - /// Error when the entry point for the Python application is not found. - #[error("Entry point not found: {0}")] - EntrypointNotFoundError(std::io::Error), - - /// Error when converting a string to a C-compatible string. - #[error("Failed to convert string: {0}")] - StringCovertError(#[from] std::ffi::NulError), - - /// Error when a Python operation fails. - #[error("Python error: {0}")] - PythonError(#[from] pyo3::prelude::PyErr), - - /// Error when response channel is closed before sending a response. - #[error("No response sent")] - NoResponse, - - /// Error when response is interrupted. - #[error("Response interrupted")] - ResponseInterrupted, - - /// Error when response channel is closed. - #[error("Response channel closed: {0}")] - ResponseChannelClosed(#[from] RecvError), - - /// Error when unable to send message to Python. - #[error("Unable to send message to Python: {0}")] - UnableToSendMessageToPython(#[from] SendError), - - /// Error when creating an HTTP response fails. - #[error("Failed to create response: {0}")] - HttpHandlerError(#[from] http_handler::Error), - - /// Error when event loop is closed. - #[error("Event loop closed")] - EventLoopClosed, - - /// Error when PYTHON_NODE_WORKERS is invalid - #[error("Invalid PYTHON_NODE_WORKERS count: {0}")] - InvalidWorkerCount(#[from] std::num::ParseIntError), +#[cfg(feature = "napi-support")] +impl Task for PythonRequestTask { + type Output = Response; + type JsValue = NapiResponse; - /// Error when a lock is poisoned - #[error("Lock poisoned: {0}")] - LockPoisoned(String), + fn compute(&mut self) -> Result { + // Take ownership of the request (FromNapiValue already created fresh body with BodyBuffer) + let request = self + .request + .take() + .ok_or_else(|| Error::from_reason("Request already consumed"))?; + + // Use the shared fallback runtime handle + asgi::fallback_handle().block_on(async { + // Spawn task to send pending body data if present (from Request constructor) + // This prevents deadlock when body size exceeds duplex buffer size + let body_writer = if let Some(body_buffer) = request.extensions().get::() { + let data = Bytes::copy_from_slice(body_buffer.as_bytes()); + let mut body = request.body().clone(); + + Some(tokio::spawn(async move { + use tokio::io::AsyncWriteExt; + + body.write_all(&data).await?; + body.shutdown().await?; + Ok::<(), std::io::Error>(()) + })) + } else { + // No body provided - close stream immediately + let mut body = request.body().clone(); + Some(tokio::spawn(async move { + use tokio::io::AsyncWriteExt; + + body.shutdown().await?; + Ok::<(), std::io::Error>(()) + })) + }; + + // Invoke handler immediately (starts reader task) + // Handler returns when headers are ready, body streaming continues in background + let response = self + .asgi + .handle(request) + .await + .map_err(|e| Error::from_reason(e.to_string()))?; + + // Wait for body writing to complete + if let Some(writer) = body_writer { + writer + .await + .map_err(|e| Error::from_reason(format!("Body writer task failed: {}", e)))? + .map_err(|e| Error::from_reason(e.to_string()))?; + } + + // Extract parts to buffer the body + let (mut parts, mut body) = response.into_parts(); + + // Buffer all body chunks - consuming starts immediately after headers + use http_body_util::BodyExt; + let mut buf = BytesMut::new(); + while let Some(result) = body.frame().await { + match result { + Ok(frame) => { + if let Ok(data) = frame.into_data() { + buf.extend_from_slice(&data); + } + } + Err(e) => { + return Err(Error::from_reason(e)); + } + } + } + let bytes = buf.freeze(); + + // Store buffered body in extension + parts.extensions.insert(BodyBuffer::from_bytes(bytes)); + + // Create a dummy ResponseBody since body is buffered in extension + let dummy_body = ResponseBody::new(); + let buffered_response = http::Response::from_parts(parts, dummy_body); + + Ok::, Error>(buffered_response) + }) + } - /// Error when a Tokio task fails - #[error("Tokio task error: {0}")] - TokioError(String), + fn resolve(&mut self, _env: Env, output: Self::Output) -> Result { + Ok(output.into()) + } } -impl From> for HandlerError { - fn from(err: std::sync::PoisonError) -> Self { - HandlerError::LockPoisoned(err.to_string()) - } +/// Task container to run a Python streaming request in a worker thread. +#[cfg(feature = "napi-support")] +pub struct PythonStreamTask { + asgi: Arc, + request: Option, } #[cfg(feature = "napi-support")] -#[cfg_attr(feature = "napi-support", napi)] -impl Task for PythonRequestTask { +#[napi] +impl Task for PythonStreamTask { type Output = Response; - type JsValue = NapiResponse; + type JsValue = Object<'static>; - // Handle the Python request in the worker thread. + // Handle the Python streaming request in the worker thread. fn compute(&mut self) -> Result { - self - .asgi - .handle_sync(self.request.clone()) - .map_err(|err| Error::from_reason(err.to_string())) + // Take ownership of the request to avoid cloning + let request = self + .request + .take() + .ok_or_else(|| Error::from_reason("Request already consumed"))?; + + // Get the current runtime handle or use the global fallback runtime + // This ensures background tasks stay alive even after compute() returns + asgi::fallback_handle().block_on(async { + // Check if this is a WebSocket request + let is_websocket = request + .extensions() + .get::() + .is_some(); + + // Spawn task to send pending body data if present (from Request constructor) + // This prevents deadlock when body size exceeds duplex buffer size + let body_writer = if let Some(body_buffer) = request.extensions().get::() { + let data = Bytes::copy_from_slice(body_buffer.as_bytes()); + let mut body = request.body().clone(); + let should_close = !is_websocket; + + Some(tokio::spawn(async move { + use tokio::io::AsyncWriteExt; + + body.write_all(&data).await?; + if should_close { + body.shutdown().await?; + } + Ok::<(), std::io::Error>(()) + })) + } else if !is_websocket { + // No body provided - close stream immediately for non-WebSocket requests + let mut body = request.body().clone(); + Some(tokio::spawn(async move { + use tokio::io::AsyncWriteExt; + + body.shutdown().await?; + Ok::<(), std::io::Error>(()) + })) + } else { + None + }; + + // Invoke handler immediately (starts reader task) + // For streaming responses, returns when headers are ready + let response = self + .asgi + .handle(request) + .await + .map_err(|e| Error::from_reason(e.to_string()))?; + + // Wait for body writing to complete + if let Some(writer) = body_writer { + writer + .await + .map_err(|e| Error::from_reason(format!("Body writer task failed: {}", e)))? + .map_err(|e| Error::from_reason(e.to_string()))?; + } + + Ok(response) + }) } - // Handle converting the PHP response to a JavaScript response in the main thread. - fn resolve(&mut self, _env: Env, output: Self::Output) -> Result { - Ok(Into::::into(output)) + // Handle converting the Python response to a JavaScript response in the main thread. + fn resolve(&mut self, env: Env, output: Self::Output) -> Result { + // Convert to NapiResponse and set up async iterator + let response: NapiResponse = output.into(); + response.make_streamable(env) } } @@ -488,3 +616,78 @@ mod tests { assert_eq!(set.len(), 1); } } + +/// Error types for the Python request handler. +#[allow(clippy::large_enum_variant)] +#[derive(thiserror::Error, Debug)] +pub enum HandlerError { + /// IO errors that may occur during file operations. + #[error("IO Error: {0}")] + IoError(#[from] std::io::Error), + + /// Error when the current directory cannot be determined. + #[error("Failed to get current directory: {0}")] + CurrentDirectoryError(std::io::Error), + + /// Error when the entry point for the Python application is not found. + #[error("Entry point not found: {0}")] + EntrypointNotFoundError(std::io::Error), + + /// Error when converting a string to a C-compatible string. + #[error("Failed to convert string: {0}")] + StringCovertError(#[from] std::ffi::NulError), + + /// Error when a Python operation fails. + #[error("Python error: {0}")] + PythonError(#[from] pyo3::prelude::PyErr), + + /// Error when response channel is closed before sending a response. + #[error("No response sent")] + NoResponse, + + /// Error when response is interrupted. + #[error("Response interrupted")] + ResponseInterrupted, + + /// Error when response channel is closed. + #[error("Response channel closed: {0}")] + ResponseChannelClosed(#[from] RecvError), + + /// Error when unable to send message to Python. + #[error("Unable to send message to Python: {0}")] + UnableToSendMessageToPython(#[from] SendError), + + /// Error when creating an HTTP response fails. + #[error("Failed to create response: {0}")] + HttpHandlerError(#[from] http_handler::Error), + + /// Error when event loop is closed. + #[error("Event loop closed")] + EventLoopClosed, + + /// Error when PYTHON_NODE_WORKERS is invalid + #[error("Invalid PYTHON_NODE_WORKERS count: {0}")] + InvalidWorkerCount(#[from] std::num::ParseIntError), + + /// Error when a lock is poisoned + #[error("Lock poisoned: {0}")] + LockPoisoned(String), + + /// Error when a Tokio task fails + #[error("Tokio task error: {0}")] + TokioError(String), + + /// Error when request stream has already been consumed + #[error("Request stream already consumed")] + StreamAlreadyConsumed, + + /// Error when WebSocket connection was not accepted + #[error("WebSocket connection not accepted")] + WebSocketNotAccepted, +} + +impl From> for HandlerError { + fn from(err: std::sync::PoisonError) -> Self { + HandlerError::LockPoisoned(err.to_string()) + } +} diff --git a/test/concurrency.test.mjs b/test/concurrency.test.mjs index 74928f4..fea00a1 100644 --- a/test/concurrency.test.mjs +++ b/test/concurrency.test.mjs @@ -136,12 +136,13 @@ test('Python - concurrent handleRequest calls', async (t) => { if (index % 2 === 0) { assert.strictEqual(response.body.toString(), 'Hello, world!'); } else { - assert.strictEqual(response.body.toString(), 'Chunk 1\nChunk 2\nChunk 3\n'); + assert.strictEqual(response.body.toString(), 'Chunk 1\nChunk 2\nChunk 3\nChunk 4\nChunk 5\n'); } }); // Should complete reasonably quickly (streaming requests have 30ms delay) - assert.ok(duration < 200, `Requests took too long: ${duration}ms`); + // Allow 1500ms to account for system load variations and overhead + assert.ok(duration < 2500, `Requests took too long: ${duration}ms`); }); await t.test('handles requests with large payloads concurrently', async () => { diff --git a/test/fixtures/error_app.py b/test/fixtures/error_app.py index 773487d..df69af3 100644 --- a/test/fixtures/error_app.py +++ b/test/fixtures/error_app.py @@ -1,16 +1,16 @@ async def app(scope, receive, send): # Read request to consume it await receive() - + if scope['path'] == '/error': raise Exception('Test error') - + await send({ 'type': 'http.response.start', 'status': 200, 'headers': [], }) - + await send({ 'type': 'http.response.body', 'body': b'OK', diff --git a/test/fixtures/stream_app.py b/test/fixtures/stream_app.py index 0c13cf5..69964a1 100644 --- a/test/fixtures/stream_app.py +++ b/test/fixtures/stream_app.py @@ -1,20 +1,49 @@ import asyncio async def app(scope, receive, send): + path = scope['path'] + query_string = scope.get('query_string', b'').decode('utf-8') + + # Parse simple query parameters + params = {} + if query_string: + for param in query_string.split('&'): + if '=' in param: + key, value = param.split('=', 1) + params[key] = value + # Read request to consume it await receive() - + await send({ 'type': 'http.response.start', 'status': 200, 'headers': [[b'content-type', b'text/plain']], }) - - # Send response in chunks - for i in range(3): + + # Handle different paths + if path == '/empty': + # Send empty response await send({ 'type': 'http.response.body', - 'body': f'Chunk {i + 1}\n'.encode(), - 'more_body': i < 2, + 'body': b'', + 'more_body': False, }) - await asyncio.sleep(0.01) # Small delay to simulate streaming \ No newline at end of file + else: + # Send response in chunks + # Support 'count' parameter to control number of chunks (default: 5) + # Support 'newlines' parameter to control newlines (default: true) + count = int(params.get('count', '5')) + use_newlines = params.get('newlines', 'true').lower() != 'false' + + for i in range(count): + chunk_text = f'Chunk {i + 1}' + if use_newlines: + chunk_text += '\n' + + await send({ + 'type': 'http.response.body', + 'body': chunk_text.encode(), + 'more_body': i < count - 1, + }) + await asyncio.sleep(0.01) # Small delay to simulate streaming \ No newline at end of file diff --git a/test/fixtures/stream_error_app.py b/test/fixtures/stream_error_app.py new file mode 100644 index 0000000..613f880 --- /dev/null +++ b/test/fixtures/stream_error_app.py @@ -0,0 +1,34 @@ +async def app(scope, receive, send): + # Read request to consume it + await receive() + + # Send response start + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [], + }) + + if scope['path'] == '/error-during-stream': + # Send some chunks before error + await send({ + 'type': 'http.response.body', + 'body': b'Chunk 1\n', + 'more_body': True, + }) + + await send({ + 'type': 'http.response.body', + 'body': b'Chunk 2\n', + 'more_body': True, + }) + + # Now raise an error during streaming + raise Exception('Error during streaming') + + # Normal response + await send({ + 'type': 'http.response.body', + 'body': b'OK', + 'more_body': False, + }) diff --git a/test/fixtures/websocket_app.py b/test/fixtures/websocket_app.py new file mode 100644 index 0000000..2b6317b --- /dev/null +++ b/test/fixtures/websocket_app.py @@ -0,0 +1,122 @@ +async def app(scope, receive, send): + """ + WebSocket ASGI application for testing. + + Supports various test scenarios based on the path: + - /echo: Echo back received messages + - /uppercase: Convert text messages to uppercase + - /close: Accept connection then immediately close + - /ping-pong: Respond to 'ping' with 'pong' + """ + + if scope['type'] == 'websocket': + # Accept the WebSocket connection + await send({ + 'type': 'websocket.accept', + }) + + path = scope.get('path', '/') + + if path == '/close': + # Immediately close after accepting + await send({ + 'type': 'websocket.close', + 'code': 1000, + 'reason': 'Normal closure', + }) + return + + # Handle messages until disconnect + while True: + message = await receive() + + if message['type'] == 'websocket.disconnect': + # Client disconnected + break + + if message['type'] == 'websocket.receive': + text = message.get('text') + bytes_data = message.get('bytes') + + if path == '/echo': + # Echo back the message + if text is not None: + await send({ + 'type': 'websocket.send', + 'text': text, + }) + elif bytes_data is not None: + await send({ + 'type': 'websocket.send', + 'bytes': bytes_data, + }) + + elif path == '/uppercase': + # Convert to uppercase (text only) + if text is not None: + await send({ + 'type': 'websocket.send', + 'text': text.upper(), + }) + elif bytes_data is not None: + # For binary, convert to uppercase if valid UTF-8 + try: + text = bytes_data.decode('utf-8') + await send({ + 'type': 'websocket.send', + 'text': text.upper(), + }) + except UnicodeDecodeError: + # Send back as-is if not valid UTF-8 + await send({ + 'type': 'websocket.send', + 'bytes': bytes_data, + }) + + elif path == '/ping-pong': + # Respond to 'ping' with 'pong' + if text == 'ping': + await send({ + 'type': 'websocket.send', + 'text': 'pong', + }) + else: + # Echo other messages + if text is not None: + await send({ + 'type': 'websocket.send', + 'text': text, + }) + elif bytes_data is not None: + await send({ + 'type': 'websocket.send', + 'bytes': bytes_data, + }) + + else: + # Default: echo + if text is not None: + await send({ + 'type': 'websocket.send', + 'text': text, + }) + elif bytes_data is not None: + await send({ + 'type': 'websocket.send', + 'bytes': bytes_data, + }) + + else: + # Not a WebSocket request - return 426 Upgrade Required + await send({ + 'type': 'http.response.start', + 'status': 426, + 'headers': [ + (b'upgrade', b'WebSocket'), + ], + }) + await send({ + 'type': 'http.response.body', + 'body': b'Upgrade Required', + 'more_body': False, + }) diff --git a/test/handler.test.mjs b/test/handler.test.mjs index d72dca5..3b5f45f 100644 --- a/test/handler.test.mjs +++ b/test/handler.test.mjs @@ -120,12 +120,12 @@ test('Python', async t => { const request = new Request({ method: 'GET', - url: '/stream' + url: '/' }) const response = await python.handleRequest(request) strictEqual(response.status, 200, 'should return 200 status') - strictEqual(response.body.toString(), 'Chunk 1\nChunk 2\nChunk 3\n', 'should concatenate all chunks') + strictEqual(response.body.toString(), 'Chunk 1\nChunk 2\nChunk 3\nChunk 4\nChunk 5\n', 'should concatenate all chunks') }) await t.test('handleRequest - root_path', async () => { diff --git a/test/streaming.test.mjs b/test/streaming.test.mjs new file mode 100644 index 0000000..b1895e2 --- /dev/null +++ b/test/streaming.test.mjs @@ -0,0 +1,269 @@ +import { test } from 'node:test' +import assert, { strictEqual, deepStrictEqual } from 'node:assert' +import { join } from 'node:path' + +import { Python, Request } from '../index.js' + +const fixturesDir = join(import.meta.dirname, 'fixtures') + +test('Python - streaming', async (t) => { + await t.test('handleStream - basic response', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'main:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/' + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + // Collect streaming body + let body = '' + for await (const chunk of res) { + body += chunk.toString('utf8') + } + strictEqual(body, 'Hello, world!') + }) + + await t.test('handleStream - chunked output', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'stream_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/?count=3&newlines=false' + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + // Collect all chunks + const chunks = [] + for await (const chunk of res) { + chunks.push(chunk.toString('utf8')) + } + + // Verify complete body (chunks may be combined) + const body = chunks.join('') + strictEqual(body, 'Chunk 1Chunk 2Chunk 3') + + // Verify we received at least one chunk (streaming is working) + assert.ok(chunks.length > 0, 'should receive at least one chunk') + assert.ok(chunks.length <= 3, 'should not receive more than 3 chunks') + }) + + await t.test('handleStream - headers available immediately', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'echo_app:app' + }) + + const req = new Request({ + method: 'POST', + url: 'http://example.com/test', + headers: { + 'Content-Type': 'application/json' + }, + body: Buffer.from(JSON.stringify({ status: 'ok' })) + }) + + const res = await python.handleStream(req) + + // Headers should be available immediately + strictEqual(res.status, 200) + strictEqual(res.headers.get('content-type'), 'application/json') + + // Body can be consumed after + let body = '' + for await (const chunk of res) { + body += chunk.toString('utf8') + } + + const responseBody = JSON.parse(body) + strictEqual(responseBody.method, 'POST') + strictEqual(responseBody.path, '/test') + }) + + await t.test('handleStream - POST with buffered body', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'echo_app:app' + }) + + const req = new Request({ + method: 'POST', + url: 'http://example.com/echo', + headers: { + 'Content-Type': 'text/plain' + }, + body: Buffer.from('Hello from client!') + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + let body = '' + for await (const chunk of res) { + body += chunk.toString('utf8') + } + + const responseBody = JSON.parse(body) + strictEqual(responseBody.body, 'Hello from client!') + }) + + await t.test('handleStream - POST with streamed body', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'echo_app:app' + }) + + const req = new Request({ + method: 'POST', + url: 'http://example.com/echo', + headers: { + 'Content-Type': 'text/plain' + } + }) + + // Stream the body in chunks using write() and end() + await req.write('Hello ') + await req.write('from ') + await req.write('streaming!') + await req.end() + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + let body = '' + for await (const chunk of res) { + body += chunk.toString('utf8') + } + + const responseBody = JSON.parse(body) + strictEqual(responseBody.body, 'Hello from streaming!') + }) + + await t.test('handleStream - empty response', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'stream_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/empty' + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + let body = '' + for await (const chunk of res) { + body += chunk.toString('utf8') + } + strictEqual(body, '') + }) + + await t.test('handleStream - large streaming response', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'stream_app:app' + }) + + const chunkCount = 100 + const req = new Request({ + method: 'GET', + url: `http://example.com/?count=${chunkCount}` + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200) + + // Collect all chunks + const chunks = [] + for await (const chunk of res) { + chunks.push(chunk.toString('utf8')) + } + + // Join all chunks to get complete body + const body = chunks.join('') + + // Generate expected body - all chunks concatenated + const expectedBody = Array.from({ length: chunkCount }, (_, i) => `Chunk ${i + 1}\n`).join('') + + // Verify we received all expected data in correct order + strictEqual(body, expectedBody, 'should receive all chunks in correct order') + + // Verify we received at least some chunks (streaming is working) + assert.ok(chunks.length > 0, 'should receive at least one chunk') + assert.ok(chunks.length <= chunkCount, 'should not receive more chunks than sent') + }) + + await t.test('handleStream - error handling', async (t) => { + await t.test('exception before response.start', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'error_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/error' + }) + + // Should throw error before response.start is sent + await assert.rejects( + async () => await python.handleStream(req), + (err) => { + // Verify error message contains "Test error" + return err.message.includes('Test error') + }, + 'Should throw Python exception before response.start' + ) + }) + + await t.test('exception after response.start during streaming', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'stream_error_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/error-during-stream' + }) + + const res = await python.handleStream(req) + strictEqual(res.status, 200, 'should return 200 status (response.start sent)') + + // Collect chunks until error + const chunks = [] + await assert.rejects( + async () => { + for await (const chunk of res) { + chunks.push(chunk.toString('utf8')) + } + }, + (err) => { + // Verify error message contains "Error during streaming" + // err might be a string or Error object + const errorMsg = typeof err === 'string' ? err : err.message + return errorMsg.includes('Error during streaming') + }, + 'Should propagate exception as error in stream' + ) + + // Verify we received data before the error (chunks may be combined) + const body = chunks.join('') + strictEqual(body, 'Chunk 1\nChunk 2\n', 'should receive expected data before error') + assert.ok(chunks.length > 0, 'should receive at least one chunk before error') + assert.ok(chunks.length <= 2, 'should not receive more than 2 chunks') + }) + }) +}) diff --git a/test/websocket-integration.test.mjs b/test/websocket-integration.test.mjs new file mode 100644 index 0000000..e31dae4 --- /dev/null +++ b/test/websocket-integration.test.mjs @@ -0,0 +1,236 @@ +import { test } from 'node:test' +import { strictEqual } from 'node:assert' +import { join } from 'node:path' +import { createServer, request as httpRequest } from 'node:http' +import { once } from 'node:events' + +import { Python, Request } from '../index.js' + +const fixturesDir = join(import.meta.dirname, 'fixtures') + +test('Python - WebSocket Integration', async (t) => { + await t.test('HTTP upgrade to WebSocket simulation', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + // Create a simple HTTP server + const server = createServer(async (nodeReq, nodeRes) => { + // Check if this is a WebSocket upgrade request + const isUpgrade = nodeReq.headers.upgrade?.toLowerCase() === 'websocket' + + if (isUpgrade) { + // In a real implementation, you'd: + // 1. Perform WebSocket handshake + // 2. Switch protocols + // 3. Forward socket data to Python + + // For this test, we simulate by creating a WebSocket request + const req = new Request({ + method: nodeReq.method, + url: `http://${nodeReq.headers.host}${nodeReq.url}`, + headers: nodeReq.headers, + websocket: true + }) + + const res = await python.handleStream(req) + + // Simulate sending a message through the WebSocket + await req.write('Integration test message') + + // Read response + const chunk = await res.next() + const response = chunk.toString('utf8') + + await req.end() + + // Send response back through HTTP for test purposes + nodeRes.writeHead(200, { 'Content-Type': 'text/plain' }) + nodeRes.end(response) + } else { + // Regular HTTP request + const req = new Request({ + method: nodeReq.method, + url: `http://${nodeReq.headers.host}${nodeReq.url}`, + headers: nodeReq.headers, + websocket: false + }) + + const res = await python.handleRequest(req) + nodeRes.writeHead(res.status, Object.fromEntries(res.headers.entries())) + nodeRes.end(res.body) + } + }) + + server.listen(0) + await once(server, 'listening') + + const { port } = server.address() + + try { + // Test WebSocket upgrade request using http.request (fetch doesn't support upgrade headers) + const upgradeResponse = await new Promise((resolve, reject) => { + const req = httpRequest({ + hostname: 'localhost', + port, + path: '/echo', + method: 'GET', + headers: { + 'Upgrade': 'websocket', + 'Connection': 'Upgrade', + 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Version': '13' + } + }, (res) => { + let data = '' + res.on('data', chunk => { data += chunk }) + res.on('end', () => { + resolve({ status: res.statusCode, body: data }) + }) + }) + req.on('error', reject) + req.end() + }) + + strictEqual(upgradeResponse.body, 'Integration test message', 'Should echo the message through WebSocket') + + // Test regular HTTP request (should get 426 Upgrade Required) + const httpResponse = await fetch(`http://localhost:${port}/echo`) + strictEqual(httpResponse.status, 426, 'Should require upgrade for WebSocket app') + const body = await httpResponse.text() + strictEqual(body, 'Upgrade Required') + } finally { + server.close() + } + }) + + await t.test('Bidirectional communication simulation', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + // Simulate a bidirectional WebSocket connection + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + // Simulate multiple back-and-forth messages + const messages = [ + { send: 'Message 1', expect: 'Message 1' }, + { send: 'Message 2', expect: 'Message 2' }, + { send: 'Message 3', expect: 'Message 3' } + ] + + for (const { send, expect } of messages) { + // Client sends message + await req.write(send) + + // Server responds + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), expect) + } + + await req.end() + }) + + await t.test('Concurrent WebSocket connections', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + // Create multiple concurrent WebSocket connections + const connections = [] + const numConnections = 10 + + for (let i = 0; i < numConnections; i++) { + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = python.handleStream(req) + connections.push({ req, res, id: i }) + } + + // Wait for all connections to establish + await Promise.all(connections.map(c => c.res)) + + // Send messages on all connections concurrently + const sendPromises = connections.map(async ({ req, res, id }) => { + const message = `Connection ${id}` + await req.write(message) + + const awaitedRes = await res + const chunk = await awaitedRes.next() + strictEqual(chunk.toString('utf8'), message) + + await req.end() + }) + + await Promise.all(sendPromises) + }) + + await t.test('WebSocket with large message payload', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + // Send a large message (1MB) + const largeMessage = 'x'.repeat(1024 * 1024) + await req.write(largeMessage) + + // Receive and verify + const chunk = await res.next() + strictEqual(chunk.toString('utf8').length, largeMessage.length) + strictEqual(chunk.toString('utf8'), largeMessage) + + await req.end() + }) + + await t.test('WebSocket message buffering', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + // Send multiple messages quickly without waiting for responses + const messages = ['fast1', 'fast2', 'fast3', 'fast4', 'fast5'] + + for (const msg of messages) { + await req.write(msg) + } + + // Now read all responses + for (const msg of messages) { + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), msg) + } + + await req.end() + }) +}) diff --git a/test/websocket.test.mjs b/test/websocket.test.mjs new file mode 100644 index 0000000..6c1947e --- /dev/null +++ b/test/websocket.test.mjs @@ -0,0 +1,215 @@ +import { test } from 'node:test' +import { strictEqual } from 'node:assert' +import { join } from 'node:path' + +import { Python, Request } from '../index.js' + +const fixturesDir = join(import.meta.dirname, 'fixtures') + +test('Python - WebSocket', async (t) => { + await t.test('basic WebSocket echo', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + // WebSocket accepts don't have traditional HTTP status codes + // The response iterator handles the WebSocket messages + + // Send a text message + await req.write('Hello WebSocket!') + + // Read the echo response + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), 'Hello WebSocket!') + + // Send another message + await req.write('Second message') + + const chunk2 = await res.next() + strictEqual(chunk2.toString('utf8'), 'Second message') + + // Close the connection + await req.end() + }) + + await t.test('WebSocket binary messages', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + // Send binary data + const binaryData = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05]) + await req.write(binaryData) + + // Read the echo response + const chunk = await res.next() + strictEqual(Buffer.compare(chunk, binaryData), 0, 'Binary data should match') + + await req.end() + }) + + await t.test('WebSocket uppercase transformation', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/uppercase', + websocket: true + }) + + const res = await python.handleStream(req) + + // Send lowercase text + await req.write('hello world') + + // Should receive uppercase + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), 'HELLO WORLD') + + await req.end() + }) + + await t.test('WebSocket ping-pong', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/ping-pong', + websocket: true + }) + + const res = await python.handleStream(req) + + // Send ping + await req.write('ping') + + // Should receive pong + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), 'pong') + + // Send other message + await req.write('hello') + + // Should be echoed + const chunk2 = await res.next() + strictEqual(chunk2.toString('utf8'), 'hello') + + await req.end() + }) + + await t.test('WebSocket immediate close', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/close', + websocket: true + }) + + const res = await python.handleStream(req) + + // Server immediately closes after accepting + const chunk = await res.next() + + // Should receive null/undefined indicating connection closed + strictEqual(chunk, null, 'Connection should be closed') + }) + + await t.test('WebSocket multiple messages in sequence', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: true + }) + + const res = await python.handleStream(req) + + const messages = ['msg1', 'msg2', 'msg3', 'msg4', 'msg5'] + + for (const msg of messages) { + await req.write(msg) + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), msg, `Should echo ${msg}`) + } + + await req.end() + }) + + await t.test('WebSocket with headers', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + headers: { + 'Sec-WebSocket-Protocol': 'chat', + 'Sec-WebSocket-Version': '13', + 'Origin': 'http://example.com' + }, + websocket: true + }) + + const res = await python.handleStream(req) + + // Send and receive a message to verify connection works + await req.write('test') + const chunk = await res.next() + strictEqual(chunk.toString('utf8'), 'test') + + await req.end() + }) + + await t.test('Non-WebSocket request to WebSocket app', async () => { + const python = new Python({ + docroot: fixturesDir, + appTarget: 'websocket_app:app' + }) + + const req = new Request({ + method: 'GET', + url: 'http://example.com/echo', + websocket: false // Regular HTTP request + }) + + const res = await python.handleRequest(req) + + // Should receive 426 Upgrade Required + strictEqual(res.status, 426) + strictEqual(res.body.toString('utf8'), 'Upgrade Required') + }) +}) From 890dc2bca6172827dba77d5193dc3f1469f6eb98 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Thu, 6 Nov 2025 01:47:37 -0800 Subject: [PATCH 11/25] v2.0.0 (#42) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b8636d..2c16a68 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@platformatic/python-node", "description": "Run ASGI-compatible Python apps in Node.js", - "version": "1.0.0", + "version": "2.0.0", "main": "index.js", "types": "index.d.ts", "napi": { From c2262d0a627635ad2d1a93bcc6e27997f2a1c042 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:48:13 +0000 Subject: [PATCH 12/25] Lock file maintenance (#40) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 144 ++++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b87cfac..e7522e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.4.1(@emnapi/runtime@1.5.0) + version: 3.4.1(@emnapi/runtime@1.7.0) '@oxc-node/core': specifier: ^0.0.32 version: 0.0.32 @@ -30,11 +30,11 @@ importers: packages: - '@emnapi/core@1.5.0': - resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + '@emnapi/core@1.7.0': + resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + '@emnapi/runtime@1.7.0': + resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} @@ -510,23 +510,23 @@ packages: resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} - '@octokit/core@7.0.5': - resolution: {integrity: sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==} + '@octokit/core@7.0.6': + resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} engines: {node: '>= 20'} - '@octokit/endpoint@11.0.1': - resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==} + '@octokit/endpoint@11.0.2': + resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==} engines: {node: '>= 20'} - '@octokit/graphql@9.0.2': - resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==} + '@octokit/graphql@9.0.3': + resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} engines: {node: '>= 20'} - '@octokit/openapi-types@26.0.0': - resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==} + '@octokit/openapi-types@27.0.0': + resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} - '@octokit/plugin-paginate-rest@13.2.1': - resolution: {integrity: sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw==} + '@octokit/plugin-paginate-rest@14.0.0': + resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' @@ -537,26 +537,26 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/plugin-rest-endpoint-methods@16.1.1': - resolution: {integrity: sha512-VztDkhM0ketQYSh5Im3IcKWFZl7VIrrsCaHbDINkdYeiiAsJzjhS2xRFCSJgfN6VOcsoW4laMtsmf3HcNqIimg==} + '@octokit/plugin-rest-endpoint-methods@17.0.0': + resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} engines: {node: '>= 20'} peerDependencies: '@octokit/core': '>=6' - '@octokit/request-error@7.0.1': - resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==} + '@octokit/request-error@7.0.2': + resolution: {integrity: sha512-U8piOROoQQUyExw5c6dTkU3GKxts5/ERRThIauNL7yaRoeXW0q/5bgHWT7JfWBw1UyrbK8ERId2wVkcB32n0uQ==} engines: {node: '>= 20'} - '@octokit/request@10.0.5': - resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==} + '@octokit/request@10.0.6': + resolution: {integrity: sha512-FO+UgZCUu+pPnZAR+iKdUt64kPE7QW7ciqpldaMXaNzixz5Jld8dJ31LAUewk0cfSRkNSRKyqG438ba9c/qDlQ==} engines: {node: '>= 20'} - '@octokit/rest@22.0.0': - resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==} + '@octokit/rest@22.0.1': + resolution: {integrity: sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==} engines: {node: '>= 20'} - '@octokit/types@15.0.1': - resolution: {integrity: sha512-sdiirM93IYJ9ODDCBgmRPIboLbSkpLa5i+WLuXH8b8Atg+YMLAyLvDDhNWLV4OYd08tlvYfVm/dw88cqHWtw1Q==} + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} '@oxc-node/core-android-arm-eabi@0.0.32': resolution: {integrity: sha512-Ykkz+xYJ1Hd+vjVSXljyIFRW/ZRMp2tQfPy9T2jj9F2pm5CAchqJHSXEbB3FbhdUXusUqhWLmu70JdVhS4SBcQ==} @@ -721,8 +721,8 @@ packages: before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} - chardet@2.1.0: - resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -752,8 +752,8 @@ packages: supports-color: optional: true - emnapi@1.6.0: - resolution: {integrity: sha512-Hx0FqhPchuwkDauQdgamWAn6MHbOX1CPIFfObXqxTEmngZUYM9mZLcPS/civeVT5x73xkBV1ZIwKWfessIFTgQ==} + emnapi@1.7.0: + resolution: {integrity: sha512-d/RB4oJJu56sOxx+ooK4978jUvnoUo3iRob1/U3N+QnCr91IRQ2QNpAGa3/ZSEZqDWgdhfB1Er5jarfYzjvghg==} peerDependencies: node-addon-api: '>= 6.1.0' peerDependenciesMeta: @@ -836,13 +836,13 @@ packages: snapshots: - '@emnapi/core@1.5.0': + '@emnapi/core@1.7.0': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.5.0': + '@emnapi/runtime@1.7.0': dependencies: tslib: 2.8.1 optional: true @@ -892,7 +892,7 @@ snapshots: '@inquirer/external-editor@1.0.2': dependencies: - chardet: 2.1.0 + chardet: 2.1.1 iconv-lite: 0.7.0 '@inquirer/figures@1.0.14': {} @@ -949,22 +949,22 @@ snapshots: '@inquirer/type@3.0.9': {} - '@napi-rs/cli@3.4.1(@emnapi/runtime@1.5.0)': + '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.0)': dependencies: '@inquirer/prompts': 7.9.0 '@napi-rs/cross-toolchain': 1.0.3 '@napi-rs/wasm-tools': 1.0.1 - '@octokit/rest': 22.0.0 + '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 debug: 4.4.3 - emnapi: 1.6.0 + emnapi: 1.7.0 es-toolkit: 1.41.0 js-yaml: 4.1.0 semver: 7.7.3 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.5.0 + '@emnapi/runtime': 1.7.0 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -1132,8 +1132,8 @@ snapshots: '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.5.0 - '@emnapi/runtime': 1.5.0 + '@emnapi/core': 1.7.0 + '@emnapi/runtime': 1.7.0 '@tybys/wasm-util': 0.10.1 optional: true @@ -1196,65 +1196,65 @@ snapshots: '@octokit/auth-token@6.0.0': {} - '@octokit/core@7.0.5': + '@octokit/core@7.0.6': dependencies: '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.2 - '@octokit/request': 10.0.5 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.1 + '@octokit/graphql': 9.0.3 + '@octokit/request': 10.0.6 + '@octokit/request-error': 7.0.2 + '@octokit/types': 16.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 - '@octokit/endpoint@11.0.1': + '@octokit/endpoint@11.0.2': dependencies: - '@octokit/types': 15.0.1 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 - '@octokit/graphql@9.0.2': + '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.5 - '@octokit/types': 15.0.1 + '@octokit/request': 10.0.6 + '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 - '@octokit/openapi-types@26.0.0': {} + '@octokit/openapi-types@27.0.0': {} - '@octokit/plugin-paginate-rest@13.2.1(@octokit/core@7.0.5)': + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 - '@octokit/types': 15.0.1 + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)': + '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 + '@octokit/core': 7.0.6 - '@octokit/plugin-rest-endpoint-methods@16.1.1(@octokit/core@7.0.5)': + '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': dependencies: - '@octokit/core': 7.0.5 - '@octokit/types': 15.0.1 + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 - '@octokit/request-error@7.0.1': + '@octokit/request-error@7.0.2': dependencies: - '@octokit/types': 15.0.1 + '@octokit/types': 16.0.0 - '@octokit/request@10.0.5': + '@octokit/request@10.0.6': dependencies: - '@octokit/endpoint': 11.0.1 - '@octokit/request-error': 7.0.1 - '@octokit/types': 15.0.1 + '@octokit/endpoint': 11.0.2 + '@octokit/request-error': 7.0.2 + '@octokit/types': 16.0.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 - '@octokit/rest@22.0.0': + '@octokit/rest@22.0.1': dependencies: - '@octokit/core': 7.0.5 - '@octokit/plugin-paginate-rest': 13.2.1(@octokit/core@7.0.5) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5) - '@octokit/plugin-rest-endpoint-methods': 16.1.1(@octokit/core@7.0.5) + '@octokit/core': 7.0.6 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) - '@octokit/types@15.0.1': + '@octokit/types@16.0.0': dependencies: - '@octokit/openapi-types': 26.0.0 + '@octokit/openapi-types': 27.0.0 '@oxc-node/core-android-arm-eabi@0.0.32': optional: true @@ -1379,7 +1379,7 @@ snapshots: before-after-hook@4.0.0: {} - chardet@2.1.0: {} + chardet@2.1.1: {} cli-width@4.1.0: {} @@ -1399,7 +1399,7 @@ snapshots: dependencies: ms: 2.1.3 - emnapi@1.6.0: {} + emnapi@1.7.0: {} emoji-regex@8.0.0: {} From fdf279c91188592e6a968c92852defa3543638a7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 03:14:38 +0000 Subject: [PATCH 13/25] Update Rust crate napi-derive to v3.3.2 (#43) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cae1b56..dfef1e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,9 +552,9 @@ checksum = "3ae82775d1b06f3f07efd0666e59bbc175da8383bc372051031d7a447e94fbea" [[package]] name = "napi-derive" -version = "3.3.0" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78665d6bdf10e9a4e6b38123efb0f66962e6197c1aea2f07cff3f159a374696d" +checksum = "ffc92539b472a0df8137f76cd4d3736e7d738e320449724de3d582f0b950354e" dependencies = [ "convert_case", "ctor", @@ -566,9 +566,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d55d01423e7264de3acc13b258fa48ca7cf38a4d25db848908ec3c1304a85a" +checksum = "3a850a802342ed3883121e016c63e2ed625df24c36ef2b0920ca114469311f95" dependencies = [ "convert_case", "proc-macro2", From e17cb98b2e4e50bf93b8e622784e02abd00012c7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:51:12 +0000 Subject: [PATCH 14/25] Update Rust crate napi to v3.5.2 (#44) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dfef1e2..3a5827d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -470,9 +470,9 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", "windows-link", @@ -531,12 +531,13 @@ dependencies = [ [[package]] name = "napi" -version = "3.4.0" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a1135cfe16ca43ac82ac05858554fc39c037d8e4592f2b4a83d7ef8e822f43" +checksum = "4e917a98ac74187a5d486604a269ed69cd7901dd4824453d5573fb051f69b1b3" dependencies = [ "bitflags", "ctor", + "futures", "napi-build", "napi-sys", "nohash-hasher", @@ -546,9 +547,9 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.2.4" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae82775d1b06f3f07efd0666e59bbc175da8383bc372051031d7a447e94fbea" +checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" [[package]] name = "napi-derive" @@ -579,9 +580,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.0.1" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed8f0e23a62a3ce0fbb6527cdc056e9282ddd9916b068c46f8923e18eed5ee6" +checksum = "50ef9c1086f16aea2417c3788dbefed7591c3bccd800b827f4dfb271adff1149" dependencies = [ "libloading", ] From a82ad7cf37544d91c8ba63aab2b665ab4bd9a1d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 05:46:52 +0000 Subject: [PATCH 15/25] Update dependency oxlint to ^0.18.0 (#29) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 74 +++++++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/package.json b/package.json index 2c16a68..725fed4 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@napi-rs/cli": "^3.0.4", "@oxc-node/core": "^0.0.32", - "oxlint": "^0.16.0" + "oxlint": "^0.18.0" }, "engines": { "node": ">= 20" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7522e6..8ae834d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^0.0.32 version: 0.0.32 oxlint: - specifier: ^0.16.0 - version: 0.16.12 + specifier: ^0.18.0 + version: 0.18.1 optionalDependencies: '@platformatic/python-node-darwin-arm64': specifier: ^0.1.4 @@ -646,43 +646,43 @@ packages: '@oxc-node/core@0.0.32': resolution: {integrity: sha512-2lbEquSd7qU5SZwbu2ngxs/vaa5sgRB5FE6TSPIPp6wfy7+11M0OrzD3g9TxH5CcsawecF2pC8nNpRVjBgBhOg==} - '@oxlint/darwin-arm64@0.16.12': - resolution: {integrity: sha512-G7phYhlIA4ke2nW7tHLl+E5+rvdzgGA6830D+e+y1RGllT0w2ONGdKcVTj+2pXGCw6yPmCC5fDsDEn2+RPTfxg==} + '@oxlint/darwin-arm64@0.18.1': + resolution: {integrity: sha512-FqDrcQJmEGNkgmZgI4wbCrGyJl1tiRZa3udxvyYaXag8W80A0zLFNCyWVvHIgUJ0DHlZjRc7O72xUGjiyvQrqQ==} cpu: [arm64] os: [darwin] - '@oxlint/darwin-x64@0.16.12': - resolution: {integrity: sha512-P/LSOgJ6SzQ3OKEIf3HsebgokZiZ5nDuTgIL4LpNCHlkOLDu/fT8XL9pSkR5y+60v0SOxUF/+aN0Q8EmxblrCw==} + '@oxlint/darwin-x64@0.18.1': + resolution: {integrity: sha512-YUcyWBJdNuMcJxAwdV/i25/kvnKrVsA+vLn7SsL87cAwiD//rqGdOixk0r8sKUYa71Kx3h0Fg2ToUOjdE6ddYw==} cpu: [x64] os: [darwin] - '@oxlint/linux-arm64-gnu@0.16.12': - resolution: {integrity: sha512-0N/ZsW+cL7ZAUvOHbzMp3iApt5b/Q81q2e9RgEzkI6gUDCJK8/blWg0se/i6y9e24WH0ZC4bcxY1+Qz4ZQ+mFw==} + '@oxlint/linux-arm64-gnu@0.18.1': + resolution: {integrity: sha512-ol3jhmUv5VI/omMrt6DkwY/jVTSVJlflFyU1SnSb/BuVVf3TyBiCHmZ4wVtcrcT5k3sWjrvYWw2kSozvmuE4tg==} cpu: [arm64] os: [linux] - '@oxlint/linux-arm64-musl@0.16.12': - resolution: {integrity: sha512-MoG1SIw4RGowsOsPjm5HjRWymisRZWBea7ewMoXA5xIVQ3eqECifG0KJW0OZp96Ad8DFBEavdlNuImB2uXsMwg==} + '@oxlint/linux-arm64-musl@0.18.1': + resolution: {integrity: sha512-iKDj1ZwlU4KpXuIL1qkVP6NJzri2VSJreqXCIAe1Bf5RZXMAGSO3xjldgiX+HBvFOKSBIarLcqONYDbYco9uaQ==} cpu: [arm64] os: [linux] - '@oxlint/linux-x64-gnu@0.16.12': - resolution: {integrity: sha512-STho8QdMLfn/0lqRU94tGPaYX8lGJccPbqeUcEr3eK5gZ5ZBdXmiHlvkcngXFEXksYC8/5VoJN7Vf3HsmkEskw==} + '@oxlint/linux-x64-gnu@0.18.1': + resolution: {integrity: sha512-A3g+fZhlOivUdK7xU/IrbhBcMHig5GLrfMX0HYjXL1fiSqKYu9n1o1p42WpT6KfPL3L2uncSg/iyg7hspcN6qA==} cpu: [x64] os: [linux] - '@oxlint/linux-x64-musl@0.16.12': - resolution: {integrity: sha512-i7pzSoj9nCg/ZzOe8dCZeFWyRRWDylR9tIX04xRTq3G6PBLm6i9VrOdEkxbgM9+pCkRzUc0a9D7rbtCF34TQUA==} + '@oxlint/linux-x64-musl@0.18.1': + resolution: {integrity: sha512-LA02SdATWZEZBy8ZZpR2GlUbDg7+Jq1/WKkywMXqxdClkcoyyFozj8aQD2iTMKELSra4OSyqqZpOYroqjSSKmw==} cpu: [x64] os: [linux] - '@oxlint/win32-arm64@0.16.12': - resolution: {integrity: sha512-wcxq3IBJ7ZlONlXJxQM+7EMx+LX1nkz3ZS3R0EtDM76EOZaqe8BMkW5cXVhF8jarZTZC18oKAckW4Ng9d8adBg==} + '@oxlint/win32-arm64@0.18.1': + resolution: {integrity: sha512-FNL+OxDflqLGXRgLxfBM/X4RnLYgtOKTsb1mNSqsjSCEfUi1Oqivh7KvZ09IfAMZeJ85/fL6EI6hSOyY7nNYUg==} cpu: [arm64] os: [win32] - '@oxlint/win32-x64@0.16.12': - resolution: {integrity: sha512-Ae1fx7wmAcMVqzS8rLINaFRpAdh29QzHh133bEYMHzfWBYyK/hLu9g4GLwC/lEIVQu9884b8qutGfdOk6Qia3w==} + '@oxlint/win32-x64@0.18.1': + resolution: {integrity: sha512-W+aVE9Siqs6Oe3NDaDOTTOYsN9X3znl+whfqWK1EcLpqJXX1kdB8Hf45HkGjqnHoFoP96GRgUnXQHQvmUybjvg==} cpu: [x64] os: [win32] @@ -788,8 +788,8 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} - oxlint@0.16.12: - resolution: {integrity: sha512-1oN3P9bzE90zkbjLTc+uICVLwSR+eQaDaYVipS0BtmtmEd3ccQue0y7npCinb35YqKzIv1LZxhoU9nm5fgmQuw==} + oxlint@0.18.1: + resolution: {integrity: sha512-JGcQvbhd00Qb+nq4f9sYYRh7mZIb0K/7rbMepNdJDMzo8pbmBpx1N2XOG61RjHDsNnY6ImAmVk3h4QVwFenwUQ==} engines: {node: '>=8.*'} hasBin: true @@ -1331,28 +1331,28 @@ snapshots: '@oxc-node/core-win32-ia32-msvc': 0.0.32 '@oxc-node/core-win32-x64-msvc': 0.0.32 - '@oxlint/darwin-arm64@0.16.12': + '@oxlint/darwin-arm64@0.18.1': optional: true - '@oxlint/darwin-x64@0.16.12': + '@oxlint/darwin-x64@0.18.1': optional: true - '@oxlint/linux-arm64-gnu@0.16.12': + '@oxlint/linux-arm64-gnu@0.18.1': optional: true - '@oxlint/linux-arm64-musl@0.16.12': + '@oxlint/linux-arm64-musl@0.18.1': optional: true - '@oxlint/linux-x64-gnu@0.16.12': + '@oxlint/linux-x64-gnu@0.18.1': optional: true - '@oxlint/linux-x64-musl@0.16.12': + '@oxlint/linux-x64-musl@0.18.1': optional: true - '@oxlint/win32-arm64@0.16.12': + '@oxlint/win32-arm64@0.18.1': optional: true - '@oxlint/win32-x64@0.16.12': + '@oxlint/win32-x64@0.18.1': optional: true '@platformatic/python-node-darwin-arm64@0.1.10': @@ -1421,16 +1421,16 @@ snapshots: mute-stream@2.0.0: {} - oxlint@0.16.12: + oxlint@0.18.1: optionalDependencies: - '@oxlint/darwin-arm64': 0.16.12 - '@oxlint/darwin-x64': 0.16.12 - '@oxlint/linux-arm64-gnu': 0.16.12 - '@oxlint/linux-arm64-musl': 0.16.12 - '@oxlint/linux-x64-gnu': 0.16.12 - '@oxlint/linux-x64-musl': 0.16.12 - '@oxlint/win32-arm64': 0.16.12 - '@oxlint/win32-x64': 0.16.12 + '@oxlint/darwin-arm64': 0.18.1 + '@oxlint/darwin-x64': 0.18.1 + '@oxlint/linux-arm64-gnu': 0.18.1 + '@oxlint/linux-arm64-musl': 0.18.1 + '@oxlint/linux-x64-gnu': 0.18.1 + '@oxlint/linux-x64-musl': 0.18.1 + '@oxlint/win32-arm64': 0.18.1 + '@oxlint/win32-x64': 0.18.1 pirates@4.0.7: {} From 5edbd9f379f3c46475b114a695d2c37a23ae0eda Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 15 Nov 2025 07:43:24 +0000 Subject: [PATCH 16/25] Update dependency @oxc-node/core to ^0.0.34 (#47) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 146 ++++++++++++++++++++++++------------------------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index 725fed4..e8ba756 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "license": "MIT", "devDependencies": { "@napi-rs/cli": "^3.0.4", - "@oxc-node/core": "^0.0.32", + "@oxc-node/core": "^0.0.34", "oxlint": "^0.18.0" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ae834d..ddf3ed7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^3.0.4 version: 3.4.1(@emnapi/runtime@1.7.0) '@oxc-node/core': - specifier: ^0.0.32 - version: 0.0.32 + specifier: ^0.0.34 + version: 0.0.34 oxlint: specifier: ^0.18.0 version: 0.18.1 @@ -558,93 +558,93 @@ packages: '@octokit/types@16.0.0': resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - '@oxc-node/core-android-arm-eabi@0.0.32': - resolution: {integrity: sha512-Ykkz+xYJ1Hd+vjVSXljyIFRW/ZRMp2tQfPy9T2jj9F2pm5CAchqJHSXEbB3FbhdUXusUqhWLmu70JdVhS4SBcQ==} + '@oxc-node/core-android-arm-eabi@0.0.34': + resolution: {integrity: sha512-35pNjrAzxHxY5J3rjiXLfySE6be0g9Y05CHMkBODjM7hGSSKmdHMXmaxf/RgfI+UoMtg4jZhhAryf8ly1yijtw==} cpu: [arm] os: [android] - '@oxc-node/core-android-arm64@0.0.32': - resolution: {integrity: sha512-csPEZPGTlPtkoMnDeG+hrYX2AJIh8dPKW7TW5E0MdNMIkJ8aFIymBH2QF+xSMsFl9Gpbl5ZxYLkRIrth+Mhzhg==} + '@oxc-node/core-android-arm64@0.0.34': + resolution: {integrity: sha512-oEuR1eHNDyxbc7DiU89IrN79SkPVWM8bjdxubXqydQ9pVhnOeo5+1KlCGVBOuHrSHpN+aTSJQWeShl4ct6gk7A==} cpu: [arm64] os: [android] - '@oxc-node/core-darwin-arm64@0.0.32': - resolution: {integrity: sha512-wlURG+gBge3ovdBtMQ/KvyFsLVXnQ4h5vlIxBYMCTkwCzwvfXbcSOLLZMxypOeXPlH/cdVqOigvh9XBbc3KAfg==} + '@oxc-node/core-darwin-arm64@0.0.34': + resolution: {integrity: sha512-cX/wvXYYn3KhoIj/Z2qtjfGkYUOU/Gx5mjJ3ej4HVqbigV+qMx/08xZb1BPrOnNpeGHKX8UmtvzRKHlNcPfQEA==} cpu: [arm64] os: [darwin] - '@oxc-node/core-darwin-x64@0.0.32': - resolution: {integrity: sha512-tFlUz54cemNp6N7+suP+uwCXErzol7ibMslxOHbXtGWwRVckV3Bb1rQyCajFSQYCr/du1ZdDCVsTfuPmXQlejg==} + '@oxc-node/core-darwin-x64@0.0.34': + resolution: {integrity: sha512-qaqI7wti2RV9VLINnSL+9m2LIJxqAt+QGZmEsY4b/xTewPoDtv934Ic6XTp5cX9kOAUymddx8YgGva68qSwESg==} cpu: [x64] os: [darwin] - '@oxc-node/core-freebsd-x64@0.0.32': - resolution: {integrity: sha512-yqikvHq0VbnPasRwOkDiMe5dhLZexvZSBzNroBVGbMWNaHBvkP+GP4EFZ3Y5pcNPC3og3xP4J6+N8bbbEZk3vg==} + '@oxc-node/core-freebsd-x64@0.0.34': + resolution: {integrity: sha512-tF1f5l6DywX+o5hVt59sDJs4057q6GNEt42NHEIl77yoAbcY+vG6bt06ie/2mu974rGOSXj9dDV8AVSXasYuHw==} cpu: [x64] os: [freebsd] - '@oxc-node/core-linux-arm-gnueabihf@0.0.32': - resolution: {integrity: sha512-Qbv937NEH4gNNC1W3Lx6G4Mh5mETMYSf2jbTxCzcfng74BVorpQd0pKB72bvEA0RQtIkXoEfCW24VeyR3yA84Q==} + '@oxc-node/core-linux-arm-gnueabihf@0.0.34': + resolution: {integrity: sha512-fGhgxyqawBehGsMobSp0gHiTxJ9aWlW0JaRZiqMHbx1P2JrxBXV5EJJ/mZ3gMObeLU2ARf+vW8Ps4+l/T8Qryg==} cpu: [arm] os: [linux] - '@oxc-node/core-linux-arm64-gnu@0.0.32': - resolution: {integrity: sha512-w+6SmMWEaVap5RC9axCvg1ZOFdQsNLlLYrYrKX5siZvcVs6jPNyg3O9rbO85tBFPvuAvSLr66mBJwW70MQJv0w==} + '@oxc-node/core-linux-arm64-gnu@0.0.34': + resolution: {integrity: sha512-ixsPMmzZKAYKyR+15jQ0NrSseRrdk3Mp0AG8ovhui80NWz4s646v+CQiyYtlw1c/Eqyq2WhhDihf1hUZ92mNUQ==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-arm64-musl@0.0.32': - resolution: {integrity: sha512-AZeVCYaECJbQaj6bxCZK77ApbAQUKNOq4wWoRIkVZnn9/ay5wqHLmkvWdOku0aw2WkGiteLp5nCXSDZjw1g0/A==} + '@oxc-node/core-linux-arm64-musl@0.0.34': + resolution: {integrity: sha512-YDM3gx8LrHa9A4bMu0gNUsN1evGLnLZfbmIcUUcCmD8r4i0htNgS0LwcbWhfufp4bLglGLJs+FGq8nMTGbN0aw==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-ppc64-gnu@0.0.32': - resolution: {integrity: sha512-sz8r3BPLWZC5vZ/5UCb2MhcEFT8bRIeo3IFnksh6K9umAyjgByxnBZP/EyL4twcjQqbrDC64Ox0Pm5vtTIiFWw==} + '@oxc-node/core-linux-ppc64-gnu@0.0.34': + resolution: {integrity: sha512-OgJxLan0D8Yrps0/vl+lvH1inHVfVraD0xSCx8C8Ni5ThJN99TJwNQ0cpb4BugETyYi05A3EikJfvzebbcCRaA==} cpu: [ppc64] os: [linux] - '@oxc-node/core-linux-s390x-gnu@0.0.32': - resolution: {integrity: sha512-YLpDVEcsvj03z6SqqcxA1J+ocTR+pP6dv0oIrGXaATwQtx0C+nt6WrVESaXjJpQDAc/5I+LkVDlimeAJb4iLNQ==} + '@oxc-node/core-linux-s390x-gnu@0.0.34': + resolution: {integrity: sha512-jHMSfjCNZpsWqYzijLdK2Ee5sYlxh5t/GEwjq8yGW5OVshnFLJ9na5ji3Pcf2YZQTuMu25X52SBq3Lzun3cMxQ==} cpu: [s390x] os: [linux] - '@oxc-node/core-linux-x64-gnu@0.0.32': - resolution: {integrity: sha512-FCBaQq4Y08AOLvl83AVzGeRAp/7RI49sDb44sE3/XzxdAVHYyhp0wA84h/NBi8Cj8XhSJdr6KosskHl1cVB0Qg==} + '@oxc-node/core-linux-x64-gnu@0.0.34': + resolution: {integrity: sha512-LPEPXIC3nEM5rxTjC/bdVEXimt5K38bJ6BpufFw598HtDXc/esEsFqgEmUhG3oqdg09bkVSK7tiCiZGdEMGYRA==} cpu: [x64] os: [linux] - '@oxc-node/core-linux-x64-musl@0.0.32': - resolution: {integrity: sha512-QKvj6d7VGKK3udW8TXfB0NYNjCloKxZznl58eaoFMoO+bOwuOWJX/8tN37FjkghH4Sb38vRK24+BdqebAHjBdA==} + '@oxc-node/core-linux-x64-musl@0.0.34': + resolution: {integrity: sha512-5wmq2Taqiygn0KffdMLbtAEMYeQak22lQNG4rBH8B8ByzShIWfDcHrEr22Jy0DTcEpauxXszPKtvQaKD0j2W0Q==} cpu: [x64] os: [linux] - '@oxc-node/core-openharmony-arm64@0.0.32': - resolution: {integrity: sha512-k8wqQZ04J4l44v6iB7VFVNc+tz0BBJV2nxSwhLTHpciAFZnOG4BJUqw+2OsObUreR3z5zarebkVFyEJ3QaUH5g==} + '@oxc-node/core-openharmony-arm64@0.0.34': + resolution: {integrity: sha512-gneUiwZ7eAe5orOHufZs0nY7o/W8IpwlFzbEt8XSR/Sl/sUBSoksICKH5/c9LpdN4cNQDr02hvZaSj81BLzcfw==} cpu: [arm64] os: [openharmony] - '@oxc-node/core-wasm32-wasi@0.0.32': - resolution: {integrity: sha512-O8Bj67iC0lm0xSlpmHseU+tQytrqdhDFUc0MzYmPSvs0i60u3CNGiw/BWuO6xDpBfhp/IQkWSGBrecZZt1hMFg==} + '@oxc-node/core-wasm32-wasi@0.0.34': + resolution: {integrity: sha512-biUhZDLfZUKEL4xX1G2LkzfotLmsgRjquHWy+4+JUnc81bzGhMlfnbN+7pKvx/rsZJ0jE4mOfCRzXMH5aGKxZw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-node/core-win32-arm64-msvc@0.0.32': - resolution: {integrity: sha512-mGFu9B3E/jBqvy6FzTZHjUZUOOst1dnN/LIX1Bi8wbSrB+1TdOBykOcNJ3F+BppdaTCWqKb6ieLU6BvvnxboaA==} + '@oxc-node/core-win32-arm64-msvc@0.0.34': + resolution: {integrity: sha512-fBKnTr7hVPuN4B743fxOuC9pfIdn5R6QYhC1yhjCJQCOiVlO1tTfG6MYvZbsfaGjeORYdorWtsyY5R2Vl+uj6w==} cpu: [arm64] os: [win32] - '@oxc-node/core-win32-ia32-msvc@0.0.32': - resolution: {integrity: sha512-JEk4P/c/x6T4MHPBtty7IdCx/hxqhdhLrrJ0pIQ8Ue1Kkx74Aq6NDPg6TWtHAxmn+4cw6c1TLzGPXW+1dwbFcA==} + '@oxc-node/core-win32-ia32-msvc@0.0.34': + resolution: {integrity: sha512-7vPLRCORWl2KHlbNYzl9H/YgaKAxY1PAX2KLIJRvEzwslLrqI7lDtBUIshbf2C7QaiA7tyuWuHa1B6gX/ohNnQ==} cpu: [ia32] os: [win32] - '@oxc-node/core-win32-x64-msvc@0.0.32': - resolution: {integrity: sha512-6G0YmfxjD3Ec8G619VXfJ3luryJb1Fq649H8ZcfLO8810WLwtzZiAXZCsCLs8lPsLTEpTeFR+AWuc8v4IRHekg==} + '@oxc-node/core-win32-x64-msvc@0.0.34': + resolution: {integrity: sha512-mrJd8crE/rJAahyCqMG4SSCRb436KNtU7nq1YyBefQuPpGUh+XBE/cIzCUJBjw8X+ngIZlozPY5cUzlea2tWXQ==} cpu: [x64] os: [win32] - '@oxc-node/core@0.0.32': - resolution: {integrity: sha512-2lbEquSd7qU5SZwbu2ngxs/vaa5sgRB5FE6TSPIPp6wfy7+11M0OrzD3g9TxH5CcsawecF2pC8nNpRVjBgBhOg==} + '@oxc-node/core@0.0.34': + resolution: {integrity: sha512-hdpQO2PhRjhbCuf0fszzTZqIf4gH3d058of+Go0xivhPINkh8rP/chiH0RrCSri68V8uhVqz/Im+mr7vw/AGsQ==} '@oxlint/darwin-arm64@0.18.1': resolution: {integrity: sha512-FqDrcQJmEGNkgmZgI4wbCrGyJl1tiRZa3udxvyYaXag8W80A0zLFNCyWVvHIgUJ0DHlZjRc7O72xUGjiyvQrqQ==} @@ -1256,80 +1256,80 @@ snapshots: dependencies: '@octokit/openapi-types': 27.0.0 - '@oxc-node/core-android-arm-eabi@0.0.32': + '@oxc-node/core-android-arm-eabi@0.0.34': optional: true - '@oxc-node/core-android-arm64@0.0.32': + '@oxc-node/core-android-arm64@0.0.34': optional: true - '@oxc-node/core-darwin-arm64@0.0.32': + '@oxc-node/core-darwin-arm64@0.0.34': optional: true - '@oxc-node/core-darwin-x64@0.0.32': + '@oxc-node/core-darwin-x64@0.0.34': optional: true - '@oxc-node/core-freebsd-x64@0.0.32': + '@oxc-node/core-freebsd-x64@0.0.34': optional: true - '@oxc-node/core-linux-arm-gnueabihf@0.0.32': + '@oxc-node/core-linux-arm-gnueabihf@0.0.34': optional: true - '@oxc-node/core-linux-arm64-gnu@0.0.32': + '@oxc-node/core-linux-arm64-gnu@0.0.34': optional: true - '@oxc-node/core-linux-arm64-musl@0.0.32': + '@oxc-node/core-linux-arm64-musl@0.0.34': optional: true - '@oxc-node/core-linux-ppc64-gnu@0.0.32': + '@oxc-node/core-linux-ppc64-gnu@0.0.34': optional: true - '@oxc-node/core-linux-s390x-gnu@0.0.32': + '@oxc-node/core-linux-s390x-gnu@0.0.34': optional: true - '@oxc-node/core-linux-x64-gnu@0.0.32': + '@oxc-node/core-linux-x64-gnu@0.0.34': optional: true - '@oxc-node/core-linux-x64-musl@0.0.32': + '@oxc-node/core-linux-x64-musl@0.0.34': optional: true - '@oxc-node/core-openharmony-arm64@0.0.32': + '@oxc-node/core-openharmony-arm64@0.0.34': optional: true - '@oxc-node/core-wasm32-wasi@0.0.32': + '@oxc-node/core-wasm32-wasi@0.0.34': dependencies: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@oxc-node/core-win32-arm64-msvc@0.0.32': + '@oxc-node/core-win32-arm64-msvc@0.0.34': optional: true - '@oxc-node/core-win32-ia32-msvc@0.0.32': + '@oxc-node/core-win32-ia32-msvc@0.0.34': optional: true - '@oxc-node/core-win32-x64-msvc@0.0.32': + '@oxc-node/core-win32-x64-msvc@0.0.34': optional: true - '@oxc-node/core@0.0.32': + '@oxc-node/core@0.0.34': dependencies: pirates: 4.0.7 optionalDependencies: - '@oxc-node/core-android-arm-eabi': 0.0.32 - '@oxc-node/core-android-arm64': 0.0.32 - '@oxc-node/core-darwin-arm64': 0.0.32 - '@oxc-node/core-darwin-x64': 0.0.32 - '@oxc-node/core-freebsd-x64': 0.0.32 - '@oxc-node/core-linux-arm-gnueabihf': 0.0.32 - '@oxc-node/core-linux-arm64-gnu': 0.0.32 - '@oxc-node/core-linux-arm64-musl': 0.0.32 - '@oxc-node/core-linux-ppc64-gnu': 0.0.32 - '@oxc-node/core-linux-s390x-gnu': 0.0.32 - '@oxc-node/core-linux-x64-gnu': 0.0.32 - '@oxc-node/core-linux-x64-musl': 0.0.32 - '@oxc-node/core-openharmony-arm64': 0.0.32 - '@oxc-node/core-wasm32-wasi': 0.0.32 - '@oxc-node/core-win32-arm64-msvc': 0.0.32 - '@oxc-node/core-win32-ia32-msvc': 0.0.32 - '@oxc-node/core-win32-x64-msvc': 0.0.32 + '@oxc-node/core-android-arm-eabi': 0.0.34 + '@oxc-node/core-android-arm64': 0.0.34 + '@oxc-node/core-darwin-arm64': 0.0.34 + '@oxc-node/core-darwin-x64': 0.0.34 + '@oxc-node/core-freebsd-x64': 0.0.34 + '@oxc-node/core-linux-arm-gnueabihf': 0.0.34 + '@oxc-node/core-linux-arm64-gnu': 0.0.34 + '@oxc-node/core-linux-arm64-musl': 0.0.34 + '@oxc-node/core-linux-ppc64-gnu': 0.0.34 + '@oxc-node/core-linux-s390x-gnu': 0.0.34 + '@oxc-node/core-linux-x64-gnu': 0.0.34 + '@oxc-node/core-linux-x64-musl': 0.0.34 + '@oxc-node/core-openharmony-arm64': 0.0.34 + '@oxc-node/core-wasm32-wasi': 0.0.34 + '@oxc-node/core-win32-arm64-msvc': 0.0.34 + '@oxc-node/core-win32-ia32-msvc': 0.0.34 + '@oxc-node/core-win32-x64-msvc': 0.0.34 '@oxlint/darwin-arm64@0.18.1': optional: true From 276627ee9c9dd7e0a1132521cd0a4295fac3c178 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 16 Nov 2025 02:57:29 +0000 Subject: [PATCH 17/25] Update Rust crate napi-derive to v3.3.3 (#48) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a5827d..b0246fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,9 +163,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "convert_case" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +checksum = "db05ffb6856bf0ecdf6367558a76a0e8a77b1713044eb92845c692100ed50190" dependencies = [ "unicode-segmentation", ] @@ -553,9 +553,9 @@ checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" [[package]] name = "napi-derive" -version = "3.3.2" +version = "3.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92539b472a0df8137f76cd4d3736e7d738e320449724de3d582f0b950354e" +checksum = "a258a6521951715e00568b258b8fb7a44c6087f588c371dc6b84a413f2728fdb" dependencies = [ "convert_case", "ctor", @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a850a802342ed3883121e016c63e2ed625df24c36ef2b0920ca114469311f95" +checksum = "77c36636292fe04366a1eec028adc25bc72f4fd7cce35bdcc310499ef74fb7de" dependencies = [ "convert_case", "proc-macro2", From 860b5ce6d1fe5a2169f6c0b17e0f905525d20fa7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 06:01:22 +0000 Subject: [PATCH 18/25] Lock file maintenance (#53) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 50 +++++----- pnpm-lock.yaml | 246 ++++++++++++++++++++++++------------------------- 2 files changed, 148 insertions(+), 148 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0246fa..232e19c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,22 +49,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -105,9 +105,9 @@ checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cfg-if" @@ -117,9 +117,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.51" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.51" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -356,9 +356,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -403,7 +403,7 @@ dependencies = [ [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#f82b8791b8c2149739f63a55980398800fe9291e" +source = "git+https://github.com/platformatic/http-handler#df2850821de32d4e196a68ddbd4c66233957d7ee" dependencies = [ "bytes", "futures-core", @@ -420,7 +420,7 @@ dependencies = [ [[package]] name = "http-rewriter" version = "1.0.0" -source = "git+https://github.com/platformatic/http-rewriter#244abaece1bafa3225334030e2edcfe34a500d43" +source = "git+https://github.com/platformatic/http-rewriter#f4f1f2a08e703ece5dd9b0b8e62be7a31ae54073" dependencies = [ "bytes", "http", @@ -433,12 +433,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", ] [[package]] @@ -771,9 +771,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -871,9 +871,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -920,9 +920,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.109" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddf3ed7..ba734a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.4.1(@emnapi/runtime@1.7.0) + version: 3.4.1(@emnapi/runtime@1.7.1) '@oxc-node/core': specifier: ^0.0.34 version: 0.0.34 @@ -30,21 +30,21 @@ importers: packages: - '@emnapi/core@1.7.0': - resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==} + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - '@emnapi/runtime@1.7.0': - resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@inquirer/ansi@1.0.1': - resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} - '@inquirer/checkbox@4.3.0': - resolution: {integrity: sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==} + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -52,8 +52,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.19': - resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -61,8 +61,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.3.0': - resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -70,8 +70,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.21': - resolution: {integrity: sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==} + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -79,8 +79,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.21': - resolution: {integrity: sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==} + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -88,8 +88,8 @@ packages: '@types/node': optional: true - '@inquirer/external-editor@1.0.2': - resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==} + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -97,12 +97,12 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.14': - resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} - '@inquirer/input@4.2.5': - resolution: {integrity: sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==} + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -110,8 +110,8 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.21': - resolution: {integrity: sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==} + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -119,8 +119,8 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.21': - resolution: {integrity: sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==} + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -128,8 +128,8 @@ packages: '@types/node': optional: true - '@inquirer/prompts@7.9.0': - resolution: {integrity: sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==} + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -137,8 +137,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.9': - resolution: {integrity: sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==} + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -146,8 +146,8 @@ packages: '@types/node': optional: true - '@inquirer/search@3.2.0': - resolution: {integrity: sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==} + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -155,8 +155,8 @@ packages: '@types/node': optional: true - '@inquirer/select@4.4.0': - resolution: {integrity: sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==} + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -164,8 +164,8 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.9': - resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -543,12 +543,12 @@ packages: peerDependencies: '@octokit/core': '>=6' - '@octokit/request-error@7.0.2': - resolution: {integrity: sha512-U8piOROoQQUyExw5c6dTkU3GKxts5/ERRThIauNL7yaRoeXW0q/5bgHWT7JfWBw1UyrbK8ERId2wVkcB32n0uQ==} + '@octokit/request-error@7.1.0': + resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} engines: {node: '>= 20'} - '@octokit/request@10.0.6': - resolution: {integrity: sha512-FO+UgZCUu+pPnZAR+iKdUt64kPE7QW7ciqpldaMXaNzixz5Jld8dJ31LAUewk0cfSRkNSRKyqG438ba9c/qDlQ==} + '@octokit/request@10.0.7': + resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==} engines: {node: '>= 20'} '@octokit/rest@22.0.1': @@ -752,8 +752,8 @@ packages: supports-color: optional: true - emnapi@1.7.0: - resolution: {integrity: sha512-d/RB4oJJu56sOxx+ooK4978jUvnoUo3iRob1/U3N+QnCr91IRQ2QNpAGa3/ZSEZqDWgdhfB1Er5jarfYzjvghg==} + emnapi@1.7.1: + resolution: {integrity: sha512-wlLK2xFq+T+rCBlY6+lPlFVDEyE93b7hSn9dMrfWBIcPf4ArwUvymvvMnN9M5WWuiryYQe9M+UJrkqw4trdyRA==} peerDependencies: node-addon-api: '>= 6.1.0' peerDependenciesMeta: @@ -763,8 +763,8 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - es-toolkit@1.41.0: - resolution: {integrity: sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==} + es-toolkit@1.42.0: + resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -777,8 +777,8 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true ms@2.1.3: @@ -836,13 +836,13 @@ packages: snapshots: - '@emnapi/core@1.7.0': + '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.0': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -852,119 +852,119 @@ snapshots: tslib: 2.8.1 optional: true - '@inquirer/ansi@1.0.1': {} + '@inquirer/ansi@1.0.2': {} - '@inquirer/checkbox@4.3.0': + '@inquirer/checkbox@4.3.2': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9 + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 - '@inquirer/confirm@5.1.19': + '@inquirer/confirm@5.1.21': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 - '@inquirer/core@10.3.0': + '@inquirer/core@10.3.2': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9 + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 - '@inquirer/editor@4.2.21': + '@inquirer/editor@4.2.23': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/external-editor': 1.0.2 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/external-editor': 1.0.3 + '@inquirer/type': 3.0.10 - '@inquirer/expand@4.0.21': + '@inquirer/expand@4.0.23': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 - '@inquirer/external-editor@1.0.2': + '@inquirer/external-editor@1.0.3': dependencies: chardet: 2.1.1 iconv-lite: 0.7.0 - '@inquirer/figures@1.0.14': {} + '@inquirer/figures@1.0.15': {} - '@inquirer/input@4.2.5': + '@inquirer/input@4.3.1': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 - '@inquirer/number@3.0.21': + '@inquirer/number@3.0.23': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 - '@inquirer/password@4.0.21': + '@inquirer/password@4.0.23': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 - '@inquirer/prompts@7.9.0': + '@inquirer/prompts@7.10.1': dependencies: - '@inquirer/checkbox': 4.3.0 - '@inquirer/confirm': 5.1.19 - '@inquirer/editor': 4.2.21 - '@inquirer/expand': 4.0.21 - '@inquirer/input': 4.2.5 - '@inquirer/number': 3.0.21 - '@inquirer/password': 4.0.21 - '@inquirer/rawlist': 4.1.9 - '@inquirer/search': 3.2.0 - '@inquirer/select': 4.4.0 - - '@inquirer/rawlist@4.1.9': + '@inquirer/checkbox': 4.3.2 + '@inquirer/confirm': 5.1.21 + '@inquirer/editor': 4.2.23 + '@inquirer/expand': 4.0.23 + '@inquirer/input': 4.3.1 + '@inquirer/number': 3.0.23 + '@inquirer/password': 4.0.23 + '@inquirer/rawlist': 4.1.11 + '@inquirer/search': 3.2.2 + '@inquirer/select': 4.4.2 + + '@inquirer/rawlist@4.1.11': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 - '@inquirer/search@3.2.0': + '@inquirer/search@3.2.2': dependencies: - '@inquirer/core': 10.3.0 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9 + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 - '@inquirer/select@4.4.0': + '@inquirer/select@4.4.2': dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/core': 10.3.0 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9 + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 - '@inquirer/type@3.0.9': {} + '@inquirer/type@3.0.10': {} - '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.0)': + '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.1)': dependencies: - '@inquirer/prompts': 7.9.0 + '@inquirer/prompts': 7.10.1 '@napi-rs/cross-toolchain': 1.0.3 '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 debug: 4.4.3 - emnapi: 1.7.0 - es-toolkit: 1.41.0 - js-yaml: 4.1.0 + emnapi: 1.7.1 + es-toolkit: 1.42.0 + js-yaml: 4.1.1 semver: 7.7.3 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.7.0 + '@emnapi/runtime': 1.7.1 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -1132,8 +1132,8 @@ snapshots: '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.7.0 - '@emnapi/runtime': 1.7.0 + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -1200,8 +1200,8 @@ snapshots: dependencies: '@octokit/auth-token': 6.0.0 '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.6 - '@octokit/request-error': 7.0.2 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 before-after-hook: 4.0.0 universal-user-agent: 7.0.3 @@ -1213,7 +1213,7 @@ snapshots: '@octokit/graphql@9.0.3': dependencies: - '@octokit/request': 10.0.6 + '@octokit/request': 10.0.7 '@octokit/types': 16.0.0 universal-user-agent: 7.0.3 @@ -1233,14 +1233,14 @@ snapshots: '@octokit/core': 7.0.6 '@octokit/types': 16.0.0 - '@octokit/request-error@7.0.2': + '@octokit/request-error@7.1.0': dependencies: '@octokit/types': 16.0.0 - '@octokit/request@10.0.6': + '@octokit/request@10.0.7': dependencies: '@octokit/endpoint': 11.0.2 - '@octokit/request-error': 7.0.2 + '@octokit/request-error': 7.1.0 '@octokit/types': 16.0.0 fast-content-type-parse: 3.0.0 universal-user-agent: 7.0.3 @@ -1399,11 +1399,11 @@ snapshots: dependencies: ms: 2.1.3 - emnapi@1.7.0: {} + emnapi@1.7.1: {} emoji-regex@8.0.0: {} - es-toolkit@1.41.0: {} + es-toolkit@1.42.0: {} fast-content-type-parse@3.0.0: {} @@ -1413,7 +1413,7 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 From 09f244df2a468e32a61a1d92fd27fb1040af4df9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Nov 2025 03:00:03 +0000 Subject: [PATCH 19/25] Update Rust crate http to v1.4.0 (#54) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 232e19c..8811849 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -233,12 +233,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foldhash" version = "0.1.5" @@ -368,12 +362,11 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] From f3fdbb572430d7284ba8bb75df061224200d5fad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 05:53:47 +0000 Subject: [PATCH 20/25] Update dependency @oxc-node/core to ^0.0.35 (#57) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 146 ++++++++++++++++++++++++------------------------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index e8ba756..6cb1676 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "license": "MIT", "devDependencies": { "@napi-rs/cli": "^3.0.4", - "@oxc-node/core": "^0.0.34", + "@oxc-node/core": "^0.0.35", "oxlint": "^0.18.0" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba734a7..04cd809 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^3.0.4 version: 3.4.1(@emnapi/runtime@1.7.1) '@oxc-node/core': - specifier: ^0.0.34 - version: 0.0.34 + specifier: ^0.0.35 + version: 0.0.35 oxlint: specifier: ^0.18.0 version: 0.18.1 @@ -558,93 +558,93 @@ packages: '@octokit/types@16.0.0': resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - '@oxc-node/core-android-arm-eabi@0.0.34': - resolution: {integrity: sha512-35pNjrAzxHxY5J3rjiXLfySE6be0g9Y05CHMkBODjM7hGSSKmdHMXmaxf/RgfI+UoMtg4jZhhAryf8ly1yijtw==} + '@oxc-node/core-android-arm-eabi@0.0.35': + resolution: {integrity: sha512-Vgw/DtArB1fZJ7LX4FX7YDpRvWzwv80lFNngTcamS+9Kbd83HpZb6Tg38t6f7Ubyc/+cL0TTMo55Kg8gwnQGHQ==} cpu: [arm] os: [android] - '@oxc-node/core-android-arm64@0.0.34': - resolution: {integrity: sha512-oEuR1eHNDyxbc7DiU89IrN79SkPVWM8bjdxubXqydQ9pVhnOeo5+1KlCGVBOuHrSHpN+aTSJQWeShl4ct6gk7A==} + '@oxc-node/core-android-arm64@0.0.35': + resolution: {integrity: sha512-Z/2jKqkTybSDnx2lBb44K0TLD2eUgLMi0te0pp5p5GVnsOZ8A+qSnhZpsPAR8GAbGERdMNOWrDYqj0/VYQt7sQ==} cpu: [arm64] os: [android] - '@oxc-node/core-darwin-arm64@0.0.34': - resolution: {integrity: sha512-cX/wvXYYn3KhoIj/Z2qtjfGkYUOU/Gx5mjJ3ej4HVqbigV+qMx/08xZb1BPrOnNpeGHKX8UmtvzRKHlNcPfQEA==} + '@oxc-node/core-darwin-arm64@0.0.35': + resolution: {integrity: sha512-aeEG/a1zj8pA6GC0P7NypzdDY0c6AbZOdbxaGl9UQlwGgHmw6sOtq5PJO+7rCvzxUKPxBH9VZOVg0laFcncIFw==} cpu: [arm64] os: [darwin] - '@oxc-node/core-darwin-x64@0.0.34': - resolution: {integrity: sha512-qaqI7wti2RV9VLINnSL+9m2LIJxqAt+QGZmEsY4b/xTewPoDtv934Ic6XTp5cX9kOAUymddx8YgGva68qSwESg==} + '@oxc-node/core-darwin-x64@0.0.35': + resolution: {integrity: sha512-MtxGaUR2LBcUmqINyxzSYdx5om9KlFjyvN8cx/NizH6U5nYs7Wh/XAIoGpcQmkK2snT1FsgJeGR9L01Q1oqmng==} cpu: [x64] os: [darwin] - '@oxc-node/core-freebsd-x64@0.0.34': - resolution: {integrity: sha512-tF1f5l6DywX+o5hVt59sDJs4057q6GNEt42NHEIl77yoAbcY+vG6bt06ie/2mu974rGOSXj9dDV8AVSXasYuHw==} + '@oxc-node/core-freebsd-x64@0.0.35': + resolution: {integrity: sha512-xsZNqMeavNxi/WTxaQMZj6walhj7skCu36yff5q0RjsV7Dzp3RQ/SYK1t3ydw3cwPz2oZCx0AukAYJAj4i9vdw==} cpu: [x64] os: [freebsd] - '@oxc-node/core-linux-arm-gnueabihf@0.0.34': - resolution: {integrity: sha512-fGhgxyqawBehGsMobSp0gHiTxJ9aWlW0JaRZiqMHbx1P2JrxBXV5EJJ/mZ3gMObeLU2ARf+vW8Ps4+l/T8Qryg==} + '@oxc-node/core-linux-arm-gnueabihf@0.0.35': + resolution: {integrity: sha512-F+d948mEzQMvcv0BQO3NN4DP0jsJwvvD5VGCFcR2mFa/z6L7UuRkS8yOKnP7tUfZjri7BwxXn37Szj0ZY7pEPA==} cpu: [arm] os: [linux] - '@oxc-node/core-linux-arm64-gnu@0.0.34': - resolution: {integrity: sha512-ixsPMmzZKAYKyR+15jQ0NrSseRrdk3Mp0AG8ovhui80NWz4s646v+CQiyYtlw1c/Eqyq2WhhDihf1hUZ92mNUQ==} + '@oxc-node/core-linux-arm64-gnu@0.0.35': + resolution: {integrity: sha512-wKbAstp6Ztq5UVBf/csnMTPMef+wGsrNykJCAtJuO/l88Okm4jn6wnhudeD3hf/426Vw93txBS8veqN2JSb6fg==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-arm64-musl@0.0.34': - resolution: {integrity: sha512-YDM3gx8LrHa9A4bMu0gNUsN1evGLnLZfbmIcUUcCmD8r4i0htNgS0LwcbWhfufp4bLglGLJs+FGq8nMTGbN0aw==} + '@oxc-node/core-linux-arm64-musl@0.0.35': + resolution: {integrity: sha512-IdLaYnFrDGRICQ86AoEQEv5Rfo//knhg4g9ABy7QE3C231C3YpbgwtY7YH7Qv+xHDuUHnTNo8Lo/iraSIY3tQA==} cpu: [arm64] os: [linux] - '@oxc-node/core-linux-ppc64-gnu@0.0.34': - resolution: {integrity: sha512-OgJxLan0D8Yrps0/vl+lvH1inHVfVraD0xSCx8C8Ni5ThJN99TJwNQ0cpb4BugETyYi05A3EikJfvzebbcCRaA==} + '@oxc-node/core-linux-ppc64-gnu@0.0.35': + resolution: {integrity: sha512-yxfWpG2as+al6G9epDvFk8AX1UWy76WlwCP3pUGtpEUGuoAO63JAHUMDSXv1sSd1YatJmRJ75ptexU6c/xMdXg==} cpu: [ppc64] os: [linux] - '@oxc-node/core-linux-s390x-gnu@0.0.34': - resolution: {integrity: sha512-jHMSfjCNZpsWqYzijLdK2Ee5sYlxh5t/GEwjq8yGW5OVshnFLJ9na5ji3Pcf2YZQTuMu25X52SBq3Lzun3cMxQ==} + '@oxc-node/core-linux-s390x-gnu@0.0.35': + resolution: {integrity: sha512-nH3mnP6ger1i4LaroWhvtk3coquNYBJD9eqG3OEuJEFGo1Ao80irFcFoktQCLLq47uomYuNQxNJw5covYNHvLw==} cpu: [s390x] os: [linux] - '@oxc-node/core-linux-x64-gnu@0.0.34': - resolution: {integrity: sha512-LPEPXIC3nEM5rxTjC/bdVEXimt5K38bJ6BpufFw598HtDXc/esEsFqgEmUhG3oqdg09bkVSK7tiCiZGdEMGYRA==} + '@oxc-node/core-linux-x64-gnu@0.0.35': + resolution: {integrity: sha512-2VKErkkTxLViK/8xbdRoQ9+sid8ZGRROLkcmMtrggjQLU69EhL0wioUVztnDVjHfOPAN17lEAN7tUgxz+PAxCg==} cpu: [x64] os: [linux] - '@oxc-node/core-linux-x64-musl@0.0.34': - resolution: {integrity: sha512-5wmq2Taqiygn0KffdMLbtAEMYeQak22lQNG4rBH8B8ByzShIWfDcHrEr22Jy0DTcEpauxXszPKtvQaKD0j2W0Q==} + '@oxc-node/core-linux-x64-musl@0.0.35': + resolution: {integrity: sha512-QDDZYWMbwB/1uyn0BPMYeqT6miWQBljzLCYESmsVcaHOps204yKHI1Ezp79n2BiYEghhu9RPWrOd4wZ7+Gqa7Q==} cpu: [x64] os: [linux] - '@oxc-node/core-openharmony-arm64@0.0.34': - resolution: {integrity: sha512-gneUiwZ7eAe5orOHufZs0nY7o/W8IpwlFzbEt8XSR/Sl/sUBSoksICKH5/c9LpdN4cNQDr02hvZaSj81BLzcfw==} + '@oxc-node/core-openharmony-arm64@0.0.35': + resolution: {integrity: sha512-ihb0W8mc0iM9SpfFwj9xY/1gVAPv2y7fGuW2w4jWOICCY2enJ8GnY2N9eYloPkHd2/2+S87M63H998psVZQquQ==} cpu: [arm64] os: [openharmony] - '@oxc-node/core-wasm32-wasi@0.0.34': - resolution: {integrity: sha512-biUhZDLfZUKEL4xX1G2LkzfotLmsgRjquHWy+4+JUnc81bzGhMlfnbN+7pKvx/rsZJ0jE4mOfCRzXMH5aGKxZw==} + '@oxc-node/core-wasm32-wasi@0.0.35': + resolution: {integrity: sha512-GoT1X1Rw3MXbvU25rsqT6gLhl9AKBdLe1ss6pVHxzps0Va6qrSD/2H4alGglUX+qccKcw0kCgJbPKJphM/0CrQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-node/core-win32-arm64-msvc@0.0.34': - resolution: {integrity: sha512-fBKnTr7hVPuN4B743fxOuC9pfIdn5R6QYhC1yhjCJQCOiVlO1tTfG6MYvZbsfaGjeORYdorWtsyY5R2Vl+uj6w==} + '@oxc-node/core-win32-arm64-msvc@0.0.35': + resolution: {integrity: sha512-ObSjUyRd5md+hKg4j8ufhjaeXHGm4f+9cz1y20mOHr/HOkBIY6CNoPM7x5JEzZNerVZ9Ye62G6t6HNQZttBjsg==} cpu: [arm64] os: [win32] - '@oxc-node/core-win32-ia32-msvc@0.0.34': - resolution: {integrity: sha512-7vPLRCORWl2KHlbNYzl9H/YgaKAxY1PAX2KLIJRvEzwslLrqI7lDtBUIshbf2C7QaiA7tyuWuHa1B6gX/ohNnQ==} + '@oxc-node/core-win32-ia32-msvc@0.0.35': + resolution: {integrity: sha512-ZE7/di30tfhh/2ItgcZim4aPLw1ve+TQrp6oJSqMRyYjq0k1AwFrxIqICbaAG9sk79ap9Sy1icFMfFgSkhnABQ==} cpu: [ia32] os: [win32] - '@oxc-node/core-win32-x64-msvc@0.0.34': - resolution: {integrity: sha512-mrJd8crE/rJAahyCqMG4SSCRb436KNtU7nq1YyBefQuPpGUh+XBE/cIzCUJBjw8X+ngIZlozPY5cUzlea2tWXQ==} + '@oxc-node/core-win32-x64-msvc@0.0.35': + resolution: {integrity: sha512-9OyyjY/ECi1icwq32baG0Uct7RuAHbVxzGDffJzNhRtBABpQiIQauoaVuYiSlNecqnA8qFYxh2wxbKaVlsR1YA==} cpu: [x64] os: [win32] - '@oxc-node/core@0.0.34': - resolution: {integrity: sha512-hdpQO2PhRjhbCuf0fszzTZqIf4gH3d058of+Go0xivhPINkh8rP/chiH0RrCSri68V8uhVqz/Im+mr7vw/AGsQ==} + '@oxc-node/core@0.0.35': + resolution: {integrity: sha512-PV46QRDI2wCDdaPzppEh4UfzFmmpSt+1dX32ooq8RWb0BuWX24+LKYicAmSrsk1ls8JRSkAqiWrjrYFHIGozGg==} '@oxlint/darwin-arm64@0.18.1': resolution: {integrity: sha512-FqDrcQJmEGNkgmZgI4wbCrGyJl1tiRZa3udxvyYaXag8W80A0zLFNCyWVvHIgUJ0DHlZjRc7O72xUGjiyvQrqQ==} @@ -1256,80 +1256,80 @@ snapshots: dependencies: '@octokit/openapi-types': 27.0.0 - '@oxc-node/core-android-arm-eabi@0.0.34': + '@oxc-node/core-android-arm-eabi@0.0.35': optional: true - '@oxc-node/core-android-arm64@0.0.34': + '@oxc-node/core-android-arm64@0.0.35': optional: true - '@oxc-node/core-darwin-arm64@0.0.34': + '@oxc-node/core-darwin-arm64@0.0.35': optional: true - '@oxc-node/core-darwin-x64@0.0.34': + '@oxc-node/core-darwin-x64@0.0.35': optional: true - '@oxc-node/core-freebsd-x64@0.0.34': + '@oxc-node/core-freebsd-x64@0.0.35': optional: true - '@oxc-node/core-linux-arm-gnueabihf@0.0.34': + '@oxc-node/core-linux-arm-gnueabihf@0.0.35': optional: true - '@oxc-node/core-linux-arm64-gnu@0.0.34': + '@oxc-node/core-linux-arm64-gnu@0.0.35': optional: true - '@oxc-node/core-linux-arm64-musl@0.0.34': + '@oxc-node/core-linux-arm64-musl@0.0.35': optional: true - '@oxc-node/core-linux-ppc64-gnu@0.0.34': + '@oxc-node/core-linux-ppc64-gnu@0.0.35': optional: true - '@oxc-node/core-linux-s390x-gnu@0.0.34': + '@oxc-node/core-linux-s390x-gnu@0.0.35': optional: true - '@oxc-node/core-linux-x64-gnu@0.0.34': + '@oxc-node/core-linux-x64-gnu@0.0.35': optional: true - '@oxc-node/core-linux-x64-musl@0.0.34': + '@oxc-node/core-linux-x64-musl@0.0.35': optional: true - '@oxc-node/core-openharmony-arm64@0.0.34': + '@oxc-node/core-openharmony-arm64@0.0.35': optional: true - '@oxc-node/core-wasm32-wasi@0.0.34': + '@oxc-node/core-wasm32-wasi@0.0.35': dependencies: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@oxc-node/core-win32-arm64-msvc@0.0.34': + '@oxc-node/core-win32-arm64-msvc@0.0.35': optional: true - '@oxc-node/core-win32-ia32-msvc@0.0.34': + '@oxc-node/core-win32-ia32-msvc@0.0.35': optional: true - '@oxc-node/core-win32-x64-msvc@0.0.34': + '@oxc-node/core-win32-x64-msvc@0.0.35': optional: true - '@oxc-node/core@0.0.34': + '@oxc-node/core@0.0.35': dependencies: pirates: 4.0.7 optionalDependencies: - '@oxc-node/core-android-arm-eabi': 0.0.34 - '@oxc-node/core-android-arm64': 0.0.34 - '@oxc-node/core-darwin-arm64': 0.0.34 - '@oxc-node/core-darwin-x64': 0.0.34 - '@oxc-node/core-freebsd-x64': 0.0.34 - '@oxc-node/core-linux-arm-gnueabihf': 0.0.34 - '@oxc-node/core-linux-arm64-gnu': 0.0.34 - '@oxc-node/core-linux-arm64-musl': 0.0.34 - '@oxc-node/core-linux-ppc64-gnu': 0.0.34 - '@oxc-node/core-linux-s390x-gnu': 0.0.34 - '@oxc-node/core-linux-x64-gnu': 0.0.34 - '@oxc-node/core-linux-x64-musl': 0.0.34 - '@oxc-node/core-openharmony-arm64': 0.0.34 - '@oxc-node/core-wasm32-wasi': 0.0.34 - '@oxc-node/core-win32-arm64-msvc': 0.0.34 - '@oxc-node/core-win32-ia32-msvc': 0.0.34 - '@oxc-node/core-win32-x64-msvc': 0.0.34 + '@oxc-node/core-android-arm-eabi': 0.0.35 + '@oxc-node/core-android-arm64': 0.0.35 + '@oxc-node/core-darwin-arm64': 0.0.35 + '@oxc-node/core-darwin-x64': 0.0.35 + '@oxc-node/core-freebsd-x64': 0.0.35 + '@oxc-node/core-linux-arm-gnueabihf': 0.0.35 + '@oxc-node/core-linux-arm64-gnu': 0.0.35 + '@oxc-node/core-linux-arm64-musl': 0.0.35 + '@oxc-node/core-linux-ppc64-gnu': 0.0.35 + '@oxc-node/core-linux-s390x-gnu': 0.0.35 + '@oxc-node/core-linux-x64-gnu': 0.0.35 + '@oxc-node/core-linux-x64-musl': 0.0.35 + '@oxc-node/core-openharmony-arm64': 0.0.35 + '@oxc-node/core-wasm32-wasi': 0.0.35 + '@oxc-node/core-win32-arm64-msvc': 0.0.35 + '@oxc-node/core-win32-ia32-msvc': 0.0.35 + '@oxc-node/core-win32-x64-msvc': 0.0.35 '@oxlint/darwin-arm64@0.18.1': optional: true From 34b7029b9a5fd59ae8c2be0b7372c8b95161c099 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Dec 2025 10:03:38 +0000 Subject: [PATCH 21/25] Update Rust crate libc to v0.2.178 (#58) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8811849..98ac34b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,9 +457,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" From 0638e493b50db5bc78703aef495e095170d4433b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Dec 2025 06:53:51 +0000 Subject: [PATCH 22/25] Update dependency @napi-rs/cli to v3.5.0 (#59) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 354 ++++++++++++++++++++++++------------------------- 1 file changed, 171 insertions(+), 183 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 04cd809..d92db4c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.0.4 - version: 3.4.1(@emnapi/runtime@1.7.1) + version: 3.5.0(@emnapi/runtime@1.7.1) '@oxc-node/core': specifier: ^0.0.35 version: 0.0.35 @@ -39,146 +39,146 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@inquirer/ansi@1.0.2': - resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} - engines: {node: '>=18'} + '@inquirer/ansi@2.0.2': + resolution: {integrity: sha512-SYLX05PwJVnW+WVegZt1T4Ip1qba1ik+pNJPDiqvk6zS5Y/i8PhRzLpGEtVd7sW0G8cMtkD8t4AZYhQwm8vnww==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - '@inquirer/checkbox@4.3.2': - resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} - engines: {node: '>=18'} + '@inquirer/checkbox@5.0.2': + resolution: {integrity: sha512-iTPV4tMMct7iOpwer5qmTP7gjnk1VQJjsNfAaC2b8Q3qiuHM3K2yjjDr5u1MKfkrvp2JD4Flf8sIPpF21pmZmw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/confirm@5.1.21': - resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} - engines: {node: '>=18'} + '@inquirer/confirm@6.0.2': + resolution: {integrity: sha512-A0/13Wyi+8iFeNDX6D4zZYKPoBLIEbE4K/219qHcnpXMer2weWvaTo63+2c7mQPPA206DEMSYVOPnEw3meOlCw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/core@10.3.2': - resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} - engines: {node: '>=18'} + '@inquirer/core@11.0.2': + resolution: {integrity: sha512-lgMRx/n02ciiNELBvFLHtmcjbV5tf5D/I0UYfCg2YbTZWmBZ10/niLd3IjWBxz8LtM27xP+4oLEa06Slmb7p7A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/editor@4.2.23': - resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} - engines: {node: '>=18'} + '@inquirer/editor@5.0.2': + resolution: {integrity: sha512-pXQ4Nf0qmFcJuYB6NlcIIxH6l6zKOwNg1Jh/ZRdKd2dTqBB4OXKUFbFwR2K4LVXVtq15ZFFatBVT+rerYR8hWQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/expand@4.0.23': - resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} - engines: {node: '>=18'} + '@inquirer/expand@5.0.2': + resolution: {integrity: sha512-siFG1swxfjFIOxIcehtZkh+KUNB/YCpyfHNEGu+nC/SBXIbgUWibvThLn/WesSxLRGOeSKdNKoTm+GQCKFm6Ww==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/external-editor@1.0.3': - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} - engines: {node: '>=18'} + '@inquirer/external-editor@2.0.2': + resolution: {integrity: sha512-X/fMXK7vXomRWEex1j8mnj7s1mpnTeP4CO/h2gysJhHLT2WjBnLv4ZQEGpm/kcYI8QfLZ2fgW+9kTKD+jeopLg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/figures@1.0.15': - resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} - engines: {node: '>=18'} + '@inquirer/figures@2.0.2': + resolution: {integrity: sha512-qXm6EVvQx/FmnSrCWCIGtMHwqeLgxABP8XgcaAoywsL0NFga9gD5kfG0gXiv80GjK9Hsoz4pgGwF/+CjygyV9A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - '@inquirer/input@4.3.1': - resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} - engines: {node: '>=18'} + '@inquirer/input@5.0.2': + resolution: {integrity: sha512-hN2YRo1QiEc9lD3mK+CPnTS4TK2RhCMmMmP4nCWwTkmQL2vx9jPJWYk+rbUZpwR1D583ZJk1FI3i9JZXIpi/qg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/number@3.0.23': - resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} - engines: {node: '>=18'} + '@inquirer/number@4.0.2': + resolution: {integrity: sha512-4McnjTSYrlthNW1ojkkmP75WLRYhQs7GXm6pDDoIrHqJuV5uUYwfdbB0geHdaKMarAqJQgoOVjzIT0jdWCsKew==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/password@4.0.23': - resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} - engines: {node: '>=18'} + '@inquirer/password@5.0.2': + resolution: {integrity: sha512-oSDziMKiw4G2e4zS+0JRfxuPFFGh6N/9yUaluMgEHp2/Yyj2JGwfDO7XbwtOrxVrz+XsP/iaGyWXdQb9d8A0+g==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/prompts@7.10.1': - resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} - engines: {node: '>=18'} + '@inquirer/prompts@8.0.2': + resolution: {integrity: sha512-2zK5zY48fZcl6+gG4eqOC/UzZsJckHCRvjXoLuW4D8LKOCVGdcJiSKkLnumSZjR/6PXPINDGOrGHqNxb+sxJDg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/rawlist@4.1.11': - resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} - engines: {node: '>=18'} + '@inquirer/rawlist@5.0.2': + resolution: {integrity: sha512-AcNALEdQKUQDeJcpC1a3YC53m1MLv+sMUS+vRZ8Qigs1Yg3Dcdtmi82rscJplogKOY8CXkKW4wvVwHS2ZjCIBQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/search@3.2.2': - resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} - engines: {node: '>=18'} + '@inquirer/search@4.0.2': + resolution: {integrity: sha512-hg63w5toohdzE65S3LiGhdfIL0kT+yisbZARf7zw65PvyMUTutTN3eMAvD/B6y/25z88vTrB7kSB45Vz5CbrXg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/select@4.4.2': - resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} - engines: {node: '>=18'} + '@inquirer/select@5.0.2': + resolution: {integrity: sha512-JygTohvQxSNnvt7IKANVlg/eds+yN5sLRilYeGc4ri/9Aqi/2QPoXBMV5Cz/L1VtQv63SnTbPXJZeCK2pSwsOA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@inquirer/type@3.0.10': - resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} - engines: {node: '>=18'} + '@inquirer/type@4.0.2': + resolution: {integrity: sha512-cae7mzluplsjSdgFA6ACLygb5jC8alO0UUnFPyu0E7tNRPrL+q/f8VcSXp+cjZQ7l5CMpDpi2G1+IQvkOiL1Lw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} peerDependencies: '@types/node': '>=18' peerDependenciesMeta: '@types/node': optional: true - '@napi-rs/cli@3.4.1': - resolution: {integrity: sha512-ayhm+NfrP5Hmh7vy5pfyYm/ktYtLh2PrgdLuqHTAubO7RoO2JkUE4F991AtgYxNewwXI8+guZLxU8itV7QnDrQ==} + '@napi-rs/cli@3.5.0': + resolution: {integrity: sha512-bJsDvAa9qK9VMkFhr780XWfQlK+GDlAX8qpK20buSmA0ld6nxCtiZ5a0J45zbd0FWT+VTZE1/u8VPH2vLfnVvw==} engines: {node: '>= 16'} hasBin: true peerDependencies: - '@emnapi/runtime': ^1.5.0 + '@emnapi/runtime': ^1.7.1 peerDependenciesMeta: '@emnapi/runtime': optional: true @@ -425,6 +425,9 @@ packages: '@napi-rs/wasm-runtime@1.0.7': resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@napi-rs/wasm-runtime@1.1.0': + resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} engines: {node: '>= 10'} @@ -707,13 +710,13 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -733,13 +736,6 @@ packages: peerDependencies: typanion: '*' - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -760,8 +756,8 @@ packages: node-addon-api: optional: true - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} es-toolkit@1.42.0: resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} @@ -769,14 +765,14 @@ packages: fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} + get-east-asian-width@1.4.0: + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + engines: {node: '>=18'} + iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -784,9 +780,12 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mute-stream@2.0.0: - resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} - engines: {node: ^18.17.0 || >=20.5.0} + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} oxlint@0.18.1: resolution: {integrity: sha512-JGcQvbhd00Qb+nq4f9sYYRh7mZIb0K/7rbMepNdJDMzo8pbmBpx1N2XOG61RjHDsNnY6ImAmVk3h4QVwFenwUQ==} @@ -809,13 +808,13 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -826,12 +825,8 @@ packages: universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - yoctocolors-cjs@2.1.3: - resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} snapshots: @@ -852,115 +847,109 @@ snapshots: tslib: 2.8.1 optional: true - '@inquirer/ansi@1.0.2': {} + '@inquirer/ansi@2.0.2': {} - '@inquirer/checkbox@4.3.2': + '@inquirer/checkbox@5.0.2': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.0.2 + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/confirm@5.1.21': + '@inquirer/confirm@6.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/core@10.3.2': + '@inquirer/core@11.0.2': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10 + '@inquirer/ansi': 2.0.2 + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2 cli-width: 4.1.0 - mute-stream: 2.0.0 + mute-stream: 3.0.0 signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 + wrap-ansi: 9.0.2 - '@inquirer/editor@4.2.23': + '@inquirer/editor@5.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/external-editor': 1.0.3 - '@inquirer/type': 3.0.10 + '@inquirer/core': 11.0.2 + '@inquirer/external-editor': 2.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/expand@4.0.23': + '@inquirer/expand@5.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/external-editor@1.0.3': + '@inquirer/external-editor@2.0.2': dependencies: chardet: 2.1.1 iconv-lite: 0.7.0 - '@inquirer/figures@1.0.15': {} + '@inquirer/figures@2.0.2': {} - '@inquirer/input@4.3.1': + '@inquirer/input@5.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/number@3.0.23': + '@inquirer/number@4.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/password@4.0.23': + '@inquirer/password@5.0.2': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/prompts@7.10.1': + '@inquirer/prompts@8.0.2': dependencies: - '@inquirer/checkbox': 4.3.2 - '@inquirer/confirm': 5.1.21 - '@inquirer/editor': 4.2.23 - '@inquirer/expand': 4.0.23 - '@inquirer/input': 4.3.1 - '@inquirer/number': 3.0.23 - '@inquirer/password': 4.0.23 - '@inquirer/rawlist': 4.1.11 - '@inquirer/search': 3.2.2 - '@inquirer/select': 4.4.2 - - '@inquirer/rawlist@4.1.11': + '@inquirer/checkbox': 5.0.2 + '@inquirer/confirm': 6.0.2 + '@inquirer/editor': 5.0.2 + '@inquirer/expand': 5.0.2 + '@inquirer/input': 5.0.2 + '@inquirer/number': 4.0.2 + '@inquirer/password': 5.0.2 + '@inquirer/rawlist': 5.0.2 + '@inquirer/search': 4.0.2 + '@inquirer/select': 5.0.2 + + '@inquirer/rawlist@5.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/search@3.2.2': + '@inquirer/search@4.0.2': dependencies: - '@inquirer/core': 10.3.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 + '@inquirer/core': 11.0.2 + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/select@4.4.2': + '@inquirer/select@5.0.2': dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/core': 10.3.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 + '@inquirer/ansi': 2.0.2 + '@inquirer/core': 11.0.2 + '@inquirer/figures': 2.0.2 + '@inquirer/type': 4.0.2 - '@inquirer/type@3.0.10': {} + '@inquirer/type@4.0.2': {} - '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.1)': + '@napi-rs/cli@3.5.0(@emnapi/runtime@1.7.1)': dependencies: - '@inquirer/prompts': 7.10.1 + '@inquirer/prompts': 8.0.2 '@napi-rs/cross-toolchain': 1.0.3 '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.1 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - debug: 4.4.3 emnapi: 1.7.1 es-toolkit: 1.42.0 js-yaml: 4.1.1 + obug: 2.1.1 semver: 7.7.3 typanion: 3.14.0 optionalDependencies: @@ -1029,7 +1018,7 @@ snapshots: '@napi-rs/lzma-wasm32-wasi@1.4.5': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 1.1.0 optional: true '@napi-rs/lzma-win32-arm64-msvc@1.4.5': @@ -1099,7 +1088,7 @@ snapshots: '@napi-rs/tar-wasm32-wasi@1.1.0': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 1.1.0 optional: true '@napi-rs/tar-win32-arm64-msvc@1.1.0': @@ -1137,6 +1126,13 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@napi-rs/wasm-runtime@1.1.0': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': optional: true @@ -1166,7 +1162,7 @@ snapshots: '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 1.1.0 optional: true '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': @@ -1369,11 +1365,9 @@ snapshots: tslib: 2.8.1 optional: true - ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 + ansi-styles@6.2.3: {} argparse@2.0.1: {} @@ -1387,12 +1381,6 @@ snapshots: dependencies: typanion: 3.14.0 - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - colorette@2.0.20: {} debug@4.4.3: @@ -1401,25 +1389,27 @@ snapshots: emnapi@1.7.1: {} - emoji-regex@8.0.0: {} + emoji-regex@10.6.0: {} es-toolkit@1.42.0: {} fast-content-type-parse@3.0.0: {} + get-east-asian-width@1.4.0: {} + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 - is-fullwidth-code-point@3.0.0: {} - js-yaml@4.1.1: dependencies: argparse: 2.0.1 ms@2.1.3: {} - mute-stream@2.0.0: {} + mute-stream@3.0.0: {} + + obug@2.1.1: {} oxlint@0.18.1: optionalDependencies: @@ -1440,15 +1430,15 @@ snapshots: signal-exit@4.1.0: {} - string-width@4.2.3: + string-width@7.2.0: dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 - strip-ansi@6.0.1: + strip-ansi@7.1.2: dependencies: - ansi-regex: 5.0.1 + ansi-regex: 6.2.2 tslib@2.8.1: optional: true @@ -1457,10 +1447,8 @@ snapshots: universal-user-agent@7.0.3: {} - wrap-ansi@6.2.0: + wrap-ansi@9.0.2: dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - yoctocolors-cjs@2.1.3: {} + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 From 964686464d94a7c8dfb9ee3275919d322de5364c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 06:56:24 +0000 Subject: [PATCH 23/25] Lock file maintenance (#60) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 36 ++++++++++++++++++------------------ pnpm-lock.yaml | 12 +----------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98ac34b..0036a1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,9 +163,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "convert_case" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db05ffb6856bf0ecdf6367558a76a0e8a77b1713044eb92845c692100ed50190" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ "unicode-segmentation", ] @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ffc71fcdcdb40d6f087edddf7f8f1f8f79e6cf922f555a9ee8779752d4819bd" +checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e" dependencies = [ "ctor-proc-macro", "dtor", @@ -396,7 +396,7 @@ dependencies = [ [[package]] name = "http-handler" version = "1.0.0" -source = "git+https://github.com/platformatic/http-handler#df2850821de32d4e196a68ddbd4c66233957d7ee" +source = "git+https://github.com/platformatic/http-handler#3e685693556f63145ed122d0a2faabc81da1ae40" dependencies = [ "bytes", "futures-core", @@ -413,7 +413,7 @@ dependencies = [ [[package]] name = "http-rewriter" version = "1.0.0" -source = "git+https://github.com/platformatic/http-rewriter#f4f1f2a08e703ece5dd9b0b8e62be7a31ae54073" +source = "git+https://github.com/platformatic/http-rewriter#94047c9863803e4b068fc92091a9515cc8432207" dependencies = [ "bytes", "http", @@ -482,9 +482,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" @@ -513,9 +513,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi", @@ -524,9 +524,9 @@ dependencies = [ [[package]] name = "napi" -version = "3.5.2" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e917a98ac74187a5d486604a269ed69cd7901dd4824453d5573fb051f69b1b3" +checksum = "3af30fe8e799dda3a555c496c59e960e4cff1e931b63acbaf3a3b25d9fad22b6" dependencies = [ "bitflags", "ctor", @@ -546,9 +546,9 @@ checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" [[package]] name = "napi-derive" -version = "3.3.3" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258a6521951715e00568b258b8fb7a44c6087f588c371dc6b84a413f2728fdb" +checksum = "47cffa09ea668c4cc5d7b1198780882e28780ed1804a903b80680725426223d9" dependencies = [ "convert_case", "ctor", @@ -560,9 +560,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "3.0.2" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c36636292fe04366a1eec028adc25bc72f4fd7cce35bdcc310499ef74fb7de" +checksum = "5e186227ec22f4675267a176d98dffecb27e6cc88926cbb7efb5427268565c0f" dependencies = [ "convert_case", "proc-macro2", @@ -573,9 +573,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.1.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50ef9c1086f16aea2417c3788dbefed7591c3bccd800b827f4dfb271adff1149" +checksum = "8eb602b84d7c1edae45e50bbf1374696548f36ae179dfa667f577e384bb90c2b" dependencies = [ "libloading", ] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d92db4c..7eae84b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -422,9 +422,6 @@ packages: resolution: {integrity: sha512-7cmzIu+Vbupriudo7UudoMRH2OA3cTw67vva8MxeoAe5S7vPFI7z0vp0pMXiA25S8IUJefImQ90FeJjl8fjEaQ==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.0.7': - resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} - '@napi-rs/wasm-runtime@1.1.0': resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} @@ -1119,13 +1116,6 @@ snapshots: '@napi-rs/tar-win32-ia32-msvc': 1.1.0 '@napi-rs/tar-win32-x64-msvc': 1.1.0 - '@napi-rs/wasm-runtime@1.0.7': - dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 - '@tybys/wasm-util': 0.10.1 - optional: true - '@napi-rs/wasm-runtime@1.1.0': dependencies: '@emnapi/core': 1.7.1 @@ -1293,7 +1283,7 @@ snapshots: '@oxc-node/core-wasm32-wasi@0.0.35': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 1.1.0 optional: true '@oxc-node/core-win32-arm64-msvc@0.0.35': From a862160df22d0ad66cf9b7534e7321f1c70aa8a8 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Wed, 10 Dec 2025 19:50:34 +0800 Subject: [PATCH 24/25] Split release process out to manual workflow_dispatch (#61) --- .github/workflows/CI.yml | 403 +-------------------------- .github/workflows/build-and-test.yml | 366 ++++++++++++++++++++++++ .github/workflows/release.yml | 75 +++++ npm/darwin-x64/README.md | 3 - npm/darwin-x64/package.json | 27 -- package.json | 2 - pnpm-lock.yaml | 12 - pnpm-workspace.yaml | 2 + scripts/update-version.mjs | 6 + 9 files changed, 454 insertions(+), 442 deletions(-) create mode 100644 .github/workflows/build-and-test.yml create mode 100644 .github/workflows/release.yml delete mode 100644 npm/darwin-x64/README.md delete mode 100644 npm/darwin-x64/package.json create mode 100644 pnpm-workspace.yaml create mode 100644 scripts/update-version.mjs diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 28d061b..cf9d8fb 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -6,8 +6,7 @@ env: MACOSX_DEPLOYMENT_TARGET: '10.13' permissions: - contents: write - id-token: write + contents: read on: push: @@ -28,399 +27,7 @@ concurrency: cancel-in-progress: true jobs: - build-wasm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - sparse-checkout: | - fix-python-soname - sparse-checkout-cone-mode: false - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: wasm32-wasip1 - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - .cargo-cache - target/ - key: wasm-cargo-cache-${{ hashFiles('**/Cargo.lock') }} - - name: Build WASM - working-directory: fix-python-soname - run: | - cargo build --target wasm32-wasip1 --release - cp target/wasm32-wasip1/release/fix-python-soname.wasm ../fix-python-soname.wasm - - name: Upload WASM artifacts - uses: actions/upload-artifact@v4 - with: - name: wasm-bindings - path: fix-python-soname.wasm - - build: - needs: build-wasm - strategy: - fail-fast: false - matrix: - settings: - - host: macos-13 - target: x86_64-apple-darwin - build: pnpm run build --target x86_64-apple-darwin - - host: macos-latest - target: aarch64-apple-darwin - build: pnpm run build --target aarch64-apple-darwin - - host: ubuntu-latest - target: x86_64-unknown-linux-gnu - docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - build: pnpm run build --target x86_64-unknown-linux-gnu - # Need to deal with this build failure before we can enable arm64 Linux builds. - # Probably also should be public first so we can use the arm runners to test it anyway. - # error: PYO3_CROSS_PYTHON_VERSION or an abi3-py3* feature must be specified when cross-compiling and PYO3_CROSS_LIB_DIR is not set. - # help: see the PyO3 user guide for more information: https://pyo3.rs/v0.25.1/building-and-distribution.html#cross-compiling - # - # - host: ubuntu-latest - # target: aarch64-unknown-linux-gnu - # docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - # build: pnpm run build --target aarch64-unknown-linux-gnu - name: stable - ${{ matrix.settings.target }} - node@20 - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v4 - - name: Download WASM artifacts - uses: actions/download-artifact@v4 - with: - name: wasm-bindings - path: . - - uses: pnpm/action-setup@v4 - with: - version: latest - - uses: actions/setup-node@v4 - if: ${{ !matrix.settings.docker }} - with: - node-version: 24 - - uses: dtolnay/rust-toolchain@stable - if: ${{ !matrix.settings.docker }} - with: - toolchain: stable - targets: ${{ matrix.settings.target }} - - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - .cargo-cache - target/ - key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} - - uses: goto-bus-stop/setup-zig@v2 - if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' || matrix.settings.target == 'armv7-unknown-linux-musleabihf' }} - with: - version: 0.13.0 - - name: Setup toolchain - run: ${{ matrix.settings.setup }} - if: ${{ matrix.settings.setup }} - shell: bash - - name: Install dependencies - run: pnpm install - - name: Build in docker - uses: addnab/docker-run-action@v3 - if: ${{ matrix.settings.docker }} - with: - image: ${{ matrix.settings.docker }} - options: '--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build' - run: | - set -x - - # Install apt dependencies - apt-get update -y - apt-get install -y openssh-client python3 python3-dev - - # Setup pnpm - corepack disable - npm i -gf pnpm - - ${{ matrix.settings.build }} - - name: Build - run: ${{ matrix.settings.build }} - if: ${{ !matrix.settings.docker }} - shell: bash - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: bindings-${{ matrix.settings.target }} - path: | - ${{ env.APP_NAME }}.*.node - index.d.ts - index.js - fix-python-soname.wasm - fix-python-soname.js - if-no-files-found: error - - test-macOS-windows-binding: - name: Test ${{ matrix.settings.target }} - node@${{ matrix.node }} + python@${{ matrix.python }} - needs: - - build - strategy: - fail-fast: false - matrix: - settings: - - host: macos-13 - target: x86_64-apple-darwin - architecture: x64 - - host: macos-latest - target: aarch64-apple-darwin - architecture: arm64 - node: - - '20' - - '22' - - '24' - python: - - '3.8' - - '3.9' - - '3.10' - - '3.11' - - '3.12' - - '3.13' - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: latest - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - architecture: ${{ matrix.settings.architecture }} - cache: pnpm - - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python }} - architecture: ${{ matrix.settings.architecture }} - - run: pnpm install - - uses: actions/download-artifact@v4 - with: - name: bindings-${{ matrix.settings.target }} - path: . - - name: Remove old prebuilt binaries - run: | - echo "Removing old prebuilt binaries from node_modules..." - rm -rf node_modules/@platformatic/python-node-* - shell: bash - - name: List packages - run: ls -R . - shell: bash - - name: Check test directory - run: | - echo "Current directory: $(pwd)" - echo "Test directory contents:" - ls -la test/ || echo "test/ directory not found" - echo "Looking for test files:" - find . -name "*.test.mjs" -type f || echo "No test files found" - shell: bash - - run: cargo test - - run: pnpm test - - test-linux-binding: - name: Test ${{ matrix.settings.target }} - node@${{ matrix.node }} + python@${{ matrix.python }} - needs: - - build - strategy: - fail-fast: false - matrix: - settings: - - host: ubuntu-22.04 - target: x86_64-unknown-linux-gnu - architecture: x64 - # Not supported yet. - # - host: ubuntu-22.04 - # target: x86_64-unknown-linux-musl - # Not supported yet, ubuntu-24.04-arm runner requires repo is public - # - host: ubuntu-22.04-arm - # target: aarch64-unknown-linux-gnu - # - host: ubuntu-22.04-arm - # target: aarch64-unknown-linux-musl - node: - - '20' - - '22' - - '24' - python: - - '3.8' - - '3.9' - - '3.10' - - '3.11' - - '3.12' - - '3.13' - # - '3.14-rc' - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: latest - - name: Setup node - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - architecture: ${{ matrix.settings.architecture }} - cache: pnpm - - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python }} - architecture: ${{ matrix.settings.architecture }} - - name: Install dependencies - run: pnpm install - - uses: actions/download-artifact@v4 - with: - name: bindings-${{ matrix.settings.target }} - path: . - - name: Remove old prebuilt binaries - run: | - echo "Removing old prebuilt binaries from node_modules..." - rm -rf node_modules/@platformatic/python-node-* - shell: bash - - name: List packages - run: ls -R . - shell: bash - - name: Output docker params - id: docker - run: | - node -e " - if ('${{ matrix.settings.target }}'.startsWith('aarch64')) { - console.log('PLATFORM=linux/arm64') - } else if ('${{ matrix.settings.target }}'.startsWith('armv7')) { - console.log('PLATFORM=linux/arm/v7') - } else { - console.log('PLATFORM=linux/amd64') - } - " >> $GITHUB_OUTPUT - node -e " - if ('${{ matrix.settings.target }}'.endsWith('-musl')) { - console.log('IMAGE=node:${{ matrix.node }}-alpine') - } else { - console.log('IMAGE=node:${{ matrix.node }}-slim') - } - " >> $GITHUB_OUTPUT - echo "PNPM_STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT - - name: Test crates - uses: addnab/docker-run-action@v3 - with: - image: ${{ steps.docker.outputs.IMAGE }} - options: -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }} - run: | - set -x - - # Install apt dependencies - apt-get update -y - apt-get install -y openssh-client curl git build-essential python3 python3-dev - - # Install rust toolchain - curl https://sh.rustup.rs -sSf | bash -s -- -y -t ${{ matrix.settings.target }} - . "$HOME/.cargo/env" - - cargo test --target ${{ matrix.settings.target }} - - name: Test bindings - uses: addnab/docker-run-action@v3 - with: - image: ${{ steps.docker.outputs.IMAGE }} - options: -v ${{ steps.docker.outputs.PNPM_STORE_PATH }}:${{ steps.docker.outputs.PNPM_STORE_PATH }} -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }} -e CI=true -e GITHUB_ACTIONS=true - run: | - # Install Python 3.x - apt-get update -y - apt-get install -y python3 python3-dev patchelf - - corepack disable - npm i -gf pnpm - node fix-python-soname.js - pnpm install --prefer-offline - pnpm test - - publish: - name: Publish - runs-on: ubuntu-latest - environment: npm - permissions: - contents: write - id-token: write - if: contains(github.ref, 'main') - needs: - - test-macOS-windows-binding - - test-linux-binding - steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: latest - - uses: actions/setup-node@v4 - with: - node-version: 20 - registry-url: 'https://registry.npmjs.org' - cache: pnpm - - name: Install dependencies - run: pnpm install - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - name: Move artifacts - run: pnpm artifacts - - name: Restore entrypoints - run: | - INDEX_JS=$(find artifacts -name "index.js" | head -n 1) - INDEX_D_TS=$(find artifacts -name "index.d.ts" | head -n 1) - - if [ -n "$INDEX_JS" ] && [ -n "$INDEX_D_TS" ]; then - echo "Found index.js: $INDEX_JS" - echo "Found index.d.ts: $INDEX_D_TS" - - echo "Copying entrypoints to project root" - cp "$INDEX_JS" index.js - cp "$INDEX_D_TS" index.d.ts - else - echo "Error: entrypoints not found in artifacts" >&2 - exit 1 - fi - shell: bash - - name: Copy fix-python-soname files to Linux and macOS packages - run: | - # Find the WASM and JS files from Linux artifacts - WASM_FILE=$(find artifacts -name "fix-python-soname.wasm" | head -n 1) - JS_FILE=$(find artifacts -name "fix-python-soname.js" | head -n 1) - - if [ -n "$WASM_FILE" ] && [ -n "$JS_FILE" ]; then - echo "Found WASM file: $WASM_FILE" - echo "Found JS file: $JS_FILE" - - # Copy to all Linux and macOS npm directories - for dir in npm/*/; do - if [[ "$dir" == *"linux"* ]] || [[ "$dir" == *"darwin"* ]]; then - echo "Copying files to $dir" - cp "$WASM_FILE" "$dir" - cp "$JS_FILE" "$dir" - fi - done - else - echo "Error: fix-python-soname files not found in artifacts" >&2 - exit 1 - fi - - name: List project files - run: ls -R . - shell: bash - - name: Update npm - run: npm install -g npm@latest - - name: Publish - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - if git log -1 --pretty=%B | grep "^v\?[0-9]\+\.[0-9]\+\.[0-9]\+"; - then - npm publish - elif git log -1 --pretty=%B | grep "^v\?[0-9]\+\.[0-9]\+\.[0-9]\+-\.+"; - then - npm publish - else - echo "Not a release, skipping publish" - fi + build-and-test: + uses: ./.github/workflows/build-and-test.yml + with: + run-tests: true diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000..ae401f3 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,366 @@ +name: Build and Test + +on: + workflow_call: + inputs: + run-tests: + description: 'Whether to run tests after build' + required: false + type: boolean + default: true + +env: + DEBUG: napi:* + APP_NAME: python-node + MACOSX_DEPLOYMENT_TARGET: '10.13' + +jobs: + build-wasm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + fix-python-soname + fix-python-soname.js + sparse-checkout-cone-mode: false + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-wasip1 + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + .cargo-cache + target/ + key: wasm-cargo-cache-${{ hashFiles('**/Cargo.lock') }} + - name: Build WASM + working-directory: fix-python-soname + run: | + cargo build --target wasm32-wasip1 --release + cp target/wasm32-wasip1/release/fix-python-soname.wasm ../fix-python-soname.wasm + - name: Upload WASM artifacts + uses: actions/upload-artifact@v4 + with: + name: wasm-bindings + path: | + fix-python-soname.wasm + fix-python-soname.js + + build: + needs: build-wasm + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: aarch64-apple-darwin + npm_dir: darwin-arm64 + build: pnpm run build --target aarch64-apple-darwin + - host: ubuntu-latest + target: x86_64-unknown-linux-gnu + npm_dir: linux-x64-gnu + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian + build: pnpm run build --target x86_64-unknown-linux-gnu + name: stable - ${{ matrix.settings.target }} - node@20 + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - name: Download WASM artifact + uses: actions/download-artifact@v4 + with: + name: wasm-bindings + path: npm/${{ matrix.settings.npm_dir }} + - uses: pnpm/action-setup@v4 + with: + version: latest + - uses: actions/setup-node@v4 + if: ${{ !matrix.settings.docker }} + with: + node-version: 24 + - uses: dtolnay/rust-toolchain@stable + if: ${{ !matrix.settings.docker }} + with: + toolchain: stable + targets: ${{ matrix.settings.target }} + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + .cargo-cache + target/ + key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} + - uses: goto-bus-stop/setup-zig@v2 + if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' || matrix.settings.target == 'armv7-unknown-linux-musleabihf' }} + with: + version: 0.13.0 + - name: Setup toolchain + run: ${{ matrix.settings.setup }} + if: ${{ matrix.settings.setup }} + shell: bash + - name: Install dependencies + run: pnpm install + - name: Build in docker + uses: addnab/docker-run-action@v3 + if: ${{ matrix.settings.docker }} + with: + image: ${{ matrix.settings.docker }} + options: '--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build' + run: | + set -x + + # Install apt dependencies + apt-get update -y + apt-get install -y openssh-client python3 python3-dev + + # Setup pnpm + corepack disable + npm i -gf pnpm + + ${{ matrix.settings.build }} + - name: Build + run: ${{ matrix.settings.build }} + if: ${{ !matrix.settings.docker }} + shell: bash + - name: Prepare npm package + run: | + mkdir -p artifacts + mv ${{ env.APP_NAME }}.*.node artifacts/ + pnpm artifacts + shell: bash + + - name: Upload npm package artifact + uses: actions/upload-artifact@v4 + with: + name: npm-${{ matrix.settings.npm_dir }} + path: npm/${{ matrix.settings.npm_dir }} + if-no-files-found: error + + - name: Upload entrypoints artifact + uses: actions/upload-artifact@v4 + with: + name: entrypoints + path: | + index.d.ts + index.js + overwrite: true + if-no-files-found: error + + bundle: + name: Bundle release artifacts + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download all npm package artifacts + uses: actions/download-artifact@v4 + with: + pattern: npm-* + path: npm-artifacts + + - name: Download entrypoints artifact + uses: actions/download-artifact@v4 + with: + name: entrypoints + path: . + + - name: Organize npm packages + run: | + for dir in npm-artifacts/npm-*/; do + platform=$(basename "$dir" | sed 's/^npm-//') + echo "Moving $dir to npm/$platform/" + mv "$dir"/* "npm/$platform/" + done + rm -rf npm-artifacts + shell: bash + + - name: List release bundle contents + run: | + echo "=== Root entrypoints ===" + ls -la index.js index.d.ts + echo "" + echo "=== npm package directories ===" + for dir in npm/*/; do + echo "--- $dir ---" + ls -la "$dir" + done + shell: bash + + - name: Upload release bundle + uses: actions/upload-artifact@v4 + with: + name: release-bundle + path: | + npm/ + index.js + index.d.ts + if-no-files-found: error + + test-macOS-binding: + name: Test ${{ matrix.settings.target }} - node@${{ matrix.node }} + python@${{ matrix.python }} + if: ${{ inputs.run-tests }} + needs: + - build + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: aarch64-apple-darwin + architecture: arm64 + npm_dir: darwin-arm64 + node: + - '20' + - '22' + - '24' + python: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' + - '3.13' + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: latest + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.settings.architecture }} + cache: pnpm + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python }} + architecture: ${{ matrix.settings.architecture }} + - run: pnpm install + - name: Download npm package artifact + uses: actions/download-artifact@v4 + with: + name: npm-${{ matrix.settings.npm_dir }} + path: npm/${{ matrix.settings.npm_dir }} + - name: Download entrypoints artifact + uses: actions/download-artifact@v4 + with: + name: entrypoints + path: . + - name: Link npm package for testing + run: pnpm link ./npm/${{ matrix.settings.npm_dir }} + - run: cargo test + - run: pnpm test + + test-linux-binding: + name: Test ${{ matrix.settings.target }} - node@${{ matrix.node }} + python@${{ matrix.python }} + if: ${{ inputs.run-tests }} + needs: + - build + strategy: + fail-fast: false + matrix: + settings: + - host: ubuntu-22.04 + target: x86_64-unknown-linux-gnu + architecture: x64 + npm_dir: linux-x64-gnu + node: + - '20' + - '22' + - '24' + python: + - '3.8' + - '3.9' + - '3.10' + - '3.11' + - '3.12' + - '3.13' + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: latest + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + architecture: ${{ matrix.settings.architecture }} + cache: pnpm + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python }} + architecture: ${{ matrix.settings.architecture }} + - name: Install dependencies + run: pnpm install + - name: Download npm package artifact + uses: actions/download-artifact@v4 + with: + name: npm-${{ matrix.settings.npm_dir }} + path: npm/${{ matrix.settings.npm_dir }} + - name: Download entrypoints artifact + uses: actions/download-artifact@v4 + with: + name: entrypoints + path: . + - name: Output docker params + id: docker + run: | + node -e " + if ('${{ matrix.settings.target }}'.startsWith('aarch64')) { + console.log('PLATFORM=linux/arm64') + } else if ('${{ matrix.settings.target }}'.startsWith('armv7')) { + console.log('PLATFORM=linux/arm/v7') + } else { + console.log('PLATFORM=linux/amd64') + } + " >> $GITHUB_OUTPUT + node -e " + if ('${{ matrix.settings.target }}'.endsWith('-musl')) { + console.log('IMAGE=node:${{ matrix.node }}-alpine') + } else { + console.log('IMAGE=node:${{ matrix.node }}-slim') + } + " >> $GITHUB_OUTPUT + echo "PNPM_STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + - name: Test crates + uses: addnab/docker-run-action@v3 + with: + image: ${{ steps.docker.outputs.IMAGE }} + options: -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }} + run: | + set -x + + # Install apt dependencies + apt-get update -y + apt-get install -y openssh-client curl git build-essential python3 python3-dev + + # Install rust toolchain + curl https://sh.rustup.rs -sSf | bash -s -- -y -t ${{ matrix.settings.target }} + . "$HOME/.cargo/env" + + cargo test --target ${{ matrix.settings.target }} + - name: Test bindings + uses: addnab/docker-run-action@v3 + with: + image: ${{ steps.docker.outputs.IMAGE }} + options: -v ${{ steps.docker.outputs.PNPM_STORE_PATH }}:${{ steps.docker.outputs.PNPM_STORE_PATH }} -v ${{ github.workspace }}:${{ github.workspace }} -w ${{ github.workspace }} --platform ${{ steps.docker.outputs.PLATFORM }} -e CI=true -e GITHUB_ACTIONS=true + run: | + # Install Python 3.x + apt-get update -y + apt-get install -y python3 python3-dev patchelf + + corepack disable + npm i -gf pnpm + pnpm install --prefer-offline + pnpm link ./npm/${{ matrix.settings.npm_dir }} + # Run fix-python-soname.js from the npm package directory to patch that binary + node npm/${{ matrix.settings.npm_dir }}/fix-python-soname.js + pnpm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0e473e8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,75 @@ +name: Publish releases + +on: + workflow_dispatch: + inputs: + version: + description: 'The version number to tag and release' + required: true + type: string + prerelease: + description: 'Release as pre-release' + required: false + type: boolean + default: false + skip-tests: + description: 'Skip tests (use if tests already passed in CI)' + required: false + type: boolean + default: false + +env: + DEBUG: napi:* + APP_NAME: python-node + MACOSX_DEPLOYMENT_TARGET: '10.13' + +permissions: + contents: write + id-token: write + +concurrency: + group: release + cancel-in-progress: false + +jobs: + build-and-test: + uses: ./.github/workflows/build-and-test.yml + with: + run-tests: ${{ inputs.skip-tests == false }} + + release-npm: + needs: build-and-test + runs-on: ubuntu-latest + environment: npm + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: latest + - uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + - run: pnpm install + - uses: actions/download-artifact@v4 + with: + name: release-bundle + path: . + - name: Change version number and sync + run: node scripts/update-version.mjs ${{ inputs.version }} + - name: Update lockfile + run: pnpm install + - name: GIT commit and push all changed files + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git commit -a -m "Bumped v${{ inputs.version }}" + git push origin HEAD:${{ github.ref }} + - run: npm publish --access public --provenance --tag ${{ inputs.prerelease == true && 'next' || 'latest' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: 'Create release notes' + run: | + npx @matteo.collina/release-notes -a ${{ secrets.GITHUB_TOKEN }} -t v${{ inputs.version }} -r python-node -o platformatic ${{ inputs.prerelease == true && '-p' || '' }} -c ${{ github.ref }} diff --git a/npm/darwin-x64/README.md b/npm/darwin-x64/README.md deleted file mode 100644 index f394f89..0000000 --- a/npm/darwin-x64/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# `python-node-darwin-x64` - -This is the **x86_64-apple-darwin** binary for `python-node` diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json deleted file mode 100644 index adf7649..0000000 --- a/npm/darwin-x64/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@platformatic/python-node-darwin-x64", - "version": "0.0.1", - "os": [ - "darwin" - ], - "cpu": [ - "x64" - ], - "main": "python-node.darwin-x64.node", - "files": [ - "python-node.darwin-x64.node", - "fix-python-soname.js", - "fix-python-soname.wasm" - ], - "scripts": { - "postinstall": "node fix-python-soname.js" - }, - "publishConfig": { - "registry": "https://registry.npmjs.org/", - "scope": "@platformatic" - }, - "license": "MIT", - "engines": { - "node": ">= 20" - } -} diff --git a/package.json b/package.json index 6cb1676..fc6a670 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "binaryName": "python-node", "targets": [ "aarch64-apple-darwin", - "x86_64-apple-darwin", "x86_64-unknown-linux-gnu" ] }, @@ -38,7 +37,6 @@ }, "optionalDependencies": { "@platformatic/python-node-darwin-arm64": "^0.1.4", - "@platformatic/python-node-darwin-x64": "^0.1.4", "@platformatic/python-node-linux-x64-gnu": "^0.1.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7eae84b..3bfd0cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,9 +21,6 @@ importers: '@platformatic/python-node-darwin-arm64': specifier: ^0.1.4 version: 0.1.10 - '@platformatic/python-node-darwin-x64': - specifier: ^0.1.4 - version: 0.1.10 '@platformatic/python-node-linux-x64-gnu': specifier: ^0.1.4 version: 0.1.10 @@ -692,12 +689,6 @@ packages: cpu: [arm64] os: [darwin] - '@platformatic/python-node-darwin-x64@0.1.10': - resolution: {integrity: sha512-rs4STYb/2D6mV2duO7CCrmtf0/YjPTkn1IaIdxxSQGTVK0z+LONymCvS/TCdGK9mWdj9Y88ao66NIr/itlM73g==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - '@platformatic/python-node-linux-x64-gnu@0.1.10': resolution: {integrity: sha512-raqvdM6W74qa/m6qjhr2OV0dPyt5VVmFD/e/X/wZllR3iDtpO/D7c5VQJ4HsY166VmYA7ffOGBoNh8luV1Gdng==} engines: {node: '>= 20'} @@ -1344,9 +1335,6 @@ snapshots: '@platformatic/python-node-darwin-arm64@0.1.10': optional: true - '@platformatic/python-node-darwin-x64@0.1.10': - optional: true - '@platformatic/python-node-linux-x64-gnu@0.1.10': optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..44e8136 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +onlyBuiltDependencies: + - '@platformatic/python-node-darwin-arm64' diff --git a/scripts/update-version.mjs b/scripts/update-version.mjs new file mode 100644 index 0000000..69df885 --- /dev/null +++ b/scripts/update-version.mjs @@ -0,0 +1,6 @@ +import { readFile, writeFile } from 'fs/promises' + +const version = process.argv[2].replace(/^v/, '') +const packageJson = JSON.parse(await readFile('package.json', 'utf8')) +packageJson.version = version +await writeFile('package.json', JSON.stringify(packageJson, null, 2)) From 53454b2d0bf27421df7cf3c65cc8e853abdcefa9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 10 Dec 2025 12:18:44 +0000 Subject: [PATCH 25/25] Bumped v2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fc6a670..532129d 100644 --- a/package.json +++ b/package.json @@ -39,4 +39,4 @@ "@platformatic/python-node-darwin-arm64": "^0.1.4", "@platformatic/python-node-linux-x64-gnu": "^0.1.4" } -} +} \ No newline at end of file