mirror of
https://github.com/anomalyco/opentui.git
synced 2026-09-19 01:26:03 +08:00
runtime: support Bun 1.4 (#1400)
This commit is contained in:
@@ -13,7 +13,7 @@ concurrency:
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
BUN_VERSION: 1.3.14
|
||||
BUN_VERSION: 1.4.1
|
||||
ZIG_VERSION: 0.16.0
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
@@ -190,16 +190,49 @@ jobs:
|
||||
with:
|
||||
name: crash-dumps-core-${{ matrix.os }}-${{ github.run_attempt }}
|
||||
|
||||
bun-1-compat:
|
||||
name: Bun 1.3 compatibility
|
||||
needs: build
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup development Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Download native artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: native-libraries
|
||||
path: packages/core/node_modules/@opentui/
|
||||
|
||||
- name: Setup runtime Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
|
||||
- name: Test portable FFI arguments
|
||||
working-directory: packages/core
|
||||
run: |
|
||||
test "$(bun --version)" = "1.3.14"
|
||||
bun test src/tests/ffi-borrowed-pointer-callsites.test.ts
|
||||
|
||||
# Gate job for branch protection
|
||||
build-complete:
|
||||
name: Core - Build and Test
|
||||
needs: [test]
|
||||
needs: [test, bun-1-compat]
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check test results
|
||||
run: |
|
||||
if [ "${{ needs.test.result }}" != "success" ]; then
|
||||
if [ "${{ needs.test.result }}" != "success" ] || [ "${{ needs['bun-1-compat'].result }}" != "success" ]; then
|
||||
echo "Tests failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install dependencies FIRST (before copying built packages)
|
||||
run: |
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
@@ -101,7 +101,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
OPENTUI_INDEX_DIR: ${{ github.workspace }}/opentui-index/packages
|
||||
with:
|
||||
path: ./packages/web
|
||||
package-manager: bun@1.3.14
|
||||
package-manager: bun@1.4.1
|
||||
node-version: 26
|
||||
|
||||
deploy:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
if: steps.run-mode.outputs.run == 'true'
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.run-mode.outputs.run == 'true'
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Prepare release versions
|
||||
if: ${{ inputs.prepareVersion != '' }}
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Setup Zig
|
||||
uses: mlugg/setup-zig@v2
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
bun-version: 1.4.1
|
||||
|
||||
- name: Install opencode
|
||||
run: curl -fsSL https://opencode.ai/install | bash
|
||||
|
||||
@@ -41,11 +41,14 @@ terminal or platform is unavailable locally.
|
||||
`u32`/`u64`, not backend-only ABI names such as `usize`, `napi_env`, or `napi_value`; represent `i64`/`u64` as `bigint`,
|
||||
native booleans as `0`/`1`, and shared pointers as `number | bigint`.
|
||||
- Default to `buffer` for transient, non-null `TypedArray` parameters and pass the view directly. Do not call `ptr()`.
|
||||
- Use `ptr` only when a parameter can be null, accepts a numeric native address, is a callback, or receives a raw
|
||||
`ArrayBuffer`. Pass transient owner objects directly to `ptr` parameters; do not pre-resolve them.
|
||||
- On Bun 1.3.14, `DataView` is not accepted by `buffer` or `ptr`. You MUST pass an equivalent typed array such as
|
||||
- For a raw `ArrayBuffer`, create one `Uint8Array` view over it, keep that view, and declare `buffer`. A `buffer` call
|
||||
costs less than a `ptr` call. `buffer` rejects an argument that is not a view with a `TypeError`. `ptr` sends a bad
|
||||
argument to native code as an address.
|
||||
- Use `ptr` only when a parameter can be null, accepts a numeric native address, or is a callback. Pass transient owner
|
||||
objects directly to `ptr` parameters. Do not pre-resolve them.
|
||||
- Bun 1.3 does not accept `DataView` directly for `buffer` or `ptr` parameters. Pass an equivalent typed array such as
|
||||
`new Uint8Array(view.buffer, view.byteOffset, view.byteLength)`.
|
||||
- On Bun 1.4+, a non-null `DataView` MUST use `buffer` and be passed directly.
|
||||
- On Bun 1.4+, use `buffer` when you pass a `DataView` directly to FFI.
|
||||
- Use `ptr(view)` only when native code stores the address beyond the call. Before resolving it, access `view.buffer` to
|
||||
move any inline typed-array storage into a stable `ArrayBuffer`, then keep the view alive for the complete native
|
||||
lifetime. The order is required: `const owner = view.buffer; const address = ptr(view)`. Calling `ptr(view)` first and
|
||||
|
||||
@@ -49,7 +49,7 @@ Add `-g` to install the skill globally.
|
||||
|
||||
## Development
|
||||
|
||||
Development requires Bun 1.3.0 or later and Zig 0.16.0.
|
||||
Development requires Bun 1.4.1 or later and Zig 0.16.0.
|
||||
|
||||
See [AGENTS.md](AGENTS.md) for engineering, tooling, and verification conventions.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"commander": "^13.1.0",
|
||||
"typescript": "^5",
|
||||
@@ -57,7 +57,7 @@
|
||||
"web-tree-sitter": "0.25.10",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/three": "0.177.0",
|
||||
"typescript": "^5",
|
||||
@@ -72,7 +72,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"react": ">=19.2.0",
|
||||
@@ -105,7 +105,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"typescript": "^5",
|
||||
},
|
||||
@@ -127,7 +127,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"@types/react-reconciler": "^0.33.0",
|
||||
@@ -162,7 +162,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/babel__core": "7.20.5",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"solid-js": "1.9.12",
|
||||
"typescript": "^5",
|
||||
@@ -190,7 +190,7 @@
|
||||
"@opentui/core": "workspace:*",
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"@types/ssh2": "^1.15.0",
|
||||
@@ -211,7 +211,7 @@
|
||||
"three": "0.177.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/three": "0.177.0",
|
||||
"commander": "^13.1.0",
|
||||
@@ -235,7 +235,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/qrcode": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@xterm/addon-unicode11": "^0.8.0",
|
||||
"@xterm/headless": "^5.5.0",
|
||||
"typescript": "^5",
|
||||
@@ -677,56 +677,6 @@
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.2", "", { "os": "android", "cpu": "arm" }, "sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.2", "", { "os": "android", "cpu": "arm64" }, "sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.2", "", { "os": "linux", "cpu": "arm" }, "sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.2", "", { "os": "linux", "cpu": "arm" }, "sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.2", "", { "os": "linux", "cpu": "none" }, "sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.2", "", { "os": "linux", "cpu": "none" }, "sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.2", "", { "os": "linux", "cpu": "none" }, "sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.2", "", { "os": "linux", "cpu": "none" }, "sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.2", "", { "os": "linux", "cpu": "x64" }, "sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA=="],
|
||||
|
||||
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw=="],
|
||||
|
||||
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.2", "", { "os": "win32", "cpu": "x64" }, "sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.2", "", { "os": "win32", "cpu": "x64" }, "sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q=="],
|
||||
|
||||
"@shikijs/core": ["@shikijs/core@4.2.0", "", { "dependencies": { "@shikijs/primitive": "4.2.0", "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ=="],
|
||||
|
||||
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.2.0", "", { "dependencies": { "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og=="],
|
||||
@@ -759,7 +709,7 @@
|
||||
|
||||
"@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||
"@types/bun": ["@types/bun@1.4.1", "", { "dependencies": { "bun-types": "1.4.1" } }, "sha512-0AVGiTXGajf1rgKom3N+c5L7CBxuoyyv1i44M0nX4UDK0G/fnRAMiri93nHuVPIb429KKtAgj7HatVmmOjeQLA=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
@@ -863,7 +813,7 @@
|
||||
|
||||
"bun-ffi-structs": ["bun-ffi-structs@0.3.1", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-3gM7PpVWLyrwxWjcilSiGuhWanhZivvo6l0u573NziPH6f/gwk6McbaYgn7oJWov6pKGRTDbrg94W5DcJsKTtQ=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||
"bun-types": ["bun-types@1.4.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-loKuVrAFZKfEv+JvWkHRS9GW5IqLuLRjVXN9p+vZvBN86O5hf/pBZQ5hSoyipsrMmWObZBDvWnlmKvjKTM0PdA=="],
|
||||
|
||||
"bun-webgpu": ["bun-webgpu@0.1.7", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.7", "bun-webgpu-darwin-x64": "^0.1.7", "bun-webgpu-linux-x64": "^0.1.7", "bun-webgpu-win32-x64": "^0.1.7" } }, "sha512-KUxUp+oQIf7pPBMD4Hv1TUu7DWaOZ4ciKulTk9to9+Uc8yHoYrMW7L2SJCJ4FHHkywgf/7aLRgRx0b7i6DvGIQ=="],
|
||||
|
||||
@@ -1405,8 +1355,6 @@
|
||||
|
||||
"rolldown": ["rolldown@1.2.3", "", { "dependencies": { "@oxc-project/types": "=0.143.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.2.3", "@rolldown/binding-darwin-arm64": "1.2.3", "@rolldown/binding-darwin-x64": "1.2.3", "@rolldown/binding-freebsd-x64": "1.2.3", "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", "@rolldown/binding-linux-arm64-gnu": "1.2.3", "@rolldown/binding-linux-arm64-musl": "1.2.3", "@rolldown/binding-linux-ppc64-gnu": "1.2.3", "@rolldown/binding-linux-s390x-gnu": "1.2.3", "@rolldown/binding-linux-x64-gnu": "1.2.3", "@rolldown/binding-linux-x64-musl": "1.2.3", "@rolldown/binding-openharmony-arm64": "1.2.3", "@rolldown/binding-win32-arm64-msvc": "1.2.3", "@rolldown/binding-win32-x64-msvc": "1.2.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A=="],
|
||||
|
||||
"rollup": ["rollup@4.55.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.2", "@rollup/rollup-android-arm64": "4.55.2", "@rollup/rollup-darwin-arm64": "4.55.2", "@rollup/rollup-darwin-x64": "4.55.2", "@rollup/rollup-freebsd-arm64": "4.55.2", "@rollup/rollup-freebsd-x64": "4.55.2", "@rollup/rollup-linux-arm-gnueabihf": "4.55.2", "@rollup/rollup-linux-arm-musleabihf": "4.55.2", "@rollup/rollup-linux-arm64-gnu": "4.55.2", "@rollup/rollup-linux-arm64-musl": "4.55.2", "@rollup/rollup-linux-loong64-gnu": "4.55.2", "@rollup/rollup-linux-loong64-musl": "4.55.2", "@rollup/rollup-linux-ppc64-gnu": "4.55.2", "@rollup/rollup-linux-ppc64-musl": "4.55.2", "@rollup/rollup-linux-riscv64-gnu": "4.55.2", "@rollup/rollup-linux-riscv64-musl": "4.55.2", "@rollup/rollup-linux-s390x-gnu": "4.55.2", "@rollup/rollup-linux-x64-gnu": "4.55.2", "@rollup/rollup-linux-x64-musl": "4.55.2", "@rollup/rollup-openbsd-x64": "4.55.2", "@rollup/rollup-openharmony-arm64": "4.55.2", "@rollup/rollup-win32-arm64-msvc": "4.55.2", "@rollup/rollup-win32-ia32-msvc": "4.55.2", "@rollup/rollup-win32-x64-gnu": "4.55.2", "@rollup/rollup-win32-x64-msvc": "4.55.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg=="],
|
||||
|
||||
"s-js": ["s-js@0.4.9", "", {}, "sha512-RtpOm+cM6O0sHg6IA70wH+UC3FZcND+rccBZpBAHzlUgNO2Bm5BN+FnM8+OBxzXdwpKWFwX11JGF0MFRkhSoIQ=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@opentui",
|
||||
"private": true,
|
||||
"packageManager": "bun@1.4.1",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"packages/solid/examples"
|
||||
|
||||
@@ -52,6 +52,8 @@ Then build your first app with the [quickstart](https://opentui.com/docs/getting
|
||||
`@opentui/core` runs on Bun 1.3.0 or later, or on Node.js 26.4.0 or later with ECMAScript modules (ESM) and
|
||||
`--experimental-ffi`.
|
||||
|
||||
Use Bun 1.4.0 or later on native Windows arm64.
|
||||
|
||||
The native ABI and the generated platform packages, such as `@opentui/core-linux-x64`, are internal distribution
|
||||
surfaces, not application APIs.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"commander": "^13.1.0",
|
||||
"typescript": "^5",
|
||||
@@ -129,6 +129,7 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">=1.3.0"
|
||||
"bun": ">=1.3.0",
|
||||
"node": ">=26.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,6 +585,7 @@ if (buildLib) {
|
||||
homepage: packageJson.homepage,
|
||||
repository: packageJson.repository,
|
||||
bugs: packageJson.bugs,
|
||||
engines: packageJson.engines,
|
||||
exports,
|
||||
dependencies: packageJson.dependencies,
|
||||
peerDependencies: packageJson.peerDependencies,
|
||||
|
||||
@@ -481,7 +481,12 @@ function assertNodeStaticImportFailure(
|
||||
}
|
||||
|
||||
function installAndTest(nodeDir: string, bunDir: string): void {
|
||||
runCommand("npm", ["install", "--ignore-scripts", "--no-package-lock"], nodeDir, "Node dist test install failed")
|
||||
runCommand(
|
||||
"npm",
|
||||
["install", "--engine-strict", "--ignore-scripts", "--no-package-lock"],
|
||||
nodeDir,
|
||||
"Node dist test install failed",
|
||||
)
|
||||
runCommand(nodePath, ["-e", `import(${JSON.stringify(packageJson.name)})`], nodeDir, "Node import smoke check failed")
|
||||
runCommand(nodePath, ["--experimental-ffi", "--no-warnings", "index.mjs"], nodeDir, "Node dist smoke tests failed", {
|
||||
timeout: 60_000,
|
||||
|
||||
@@ -1352,8 +1352,9 @@ export class CliRenderer extends EventEmitter implements RenderContext {
|
||||
private removeExitListeners(): void {
|
||||
if (!this._exitListenersAdded || this.exitSignals.length === 0) return
|
||||
|
||||
const processEvents = process as EventEmitter
|
||||
this.exitSignals.forEach((signal) => {
|
||||
process.removeListener(signal, this.exitHandler)
|
||||
processEvents.removeListener(signal, this.exitHandler)
|
||||
})
|
||||
|
||||
this._exitListenersAdded = false
|
||||
@@ -4388,12 +4389,14 @@ export class CliRenderer extends EventEmitter implements RenderContext {
|
||||
this.lib.cancelKittyImageTransport(this.rendererPtr, false)
|
||||
}
|
||||
|
||||
// Bun 1.4's types narrow process.removeListener to its memoryPressure overload.
|
||||
const processEvents = process as EventEmitter
|
||||
if (this._usesProcessStdout) {
|
||||
process.removeListener("SIGWINCH", this.sigwinchHandler)
|
||||
processEvents.removeListener("SIGWINCH", this.sigwinchHandler)
|
||||
}
|
||||
process.removeListener("uncaughtException", this.handleError)
|
||||
process.removeListener("unhandledRejection", this.handleError)
|
||||
process.removeListener("warning", this.warningHandler)
|
||||
processEvents.removeListener("uncaughtException", this.handleError)
|
||||
processEvents.removeListener("unhandledRejection", this.handleError)
|
||||
processEvents.removeListener("warning", this.warningHandler)
|
||||
this.removeExitListeners()
|
||||
|
||||
if (this.resizeTimeoutId !== null) {
|
||||
|
||||
@@ -68,6 +68,10 @@ function fieldOffset(struct: { layoutByName: Map<string, { offset: number }> },
|
||||
return field.offset
|
||||
}
|
||||
|
||||
function dataView(bytes: Uint8Array): DataView {
|
||||
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
||||
}
|
||||
|
||||
function readPackedColor(packed: ArrayBuffer, offset: number): number[] {
|
||||
// 64-bit StyledChunk/CursorStyleOptions layout; matches the supported
|
||||
// x64/arm64 native targets.
|
||||
@@ -77,6 +81,15 @@ function readPackedColor(packed: ArrayBuffer, offset: number): number[] {
|
||||
}
|
||||
|
||||
describe("borrowed pointer call sites", () => {
|
||||
test("passes reusable struct views through the native FFI boundary", () => {
|
||||
const buffer = lib.createEditBuffer("wcwidth")
|
||||
try {
|
||||
expect(lib.editBufferGetCursorPosition(buffer)).toEqual({ row: 0, col: 0, offset: 0 })
|
||||
} finally {
|
||||
lib.destroyEditBuffer(buffer)
|
||||
}
|
||||
})
|
||||
|
||||
test("preserves the native viewport lookup success result", () => {
|
||||
const x = new Uint32Array([1])
|
||||
const y = new Uint32Array([1])
|
||||
@@ -180,7 +193,7 @@ describe("borrowed pointer call sites", () => {
|
||||
textBufferViewMeasureForDimensions: symbols.textBufferViewMeasureForDimensions,
|
||||
audioGetStreamStats: symbols.audioGetStreamStats,
|
||||
}
|
||||
const outputBuffers: Record<string, ArrayBuffer[]> = {
|
||||
const outputViews: Record<string, Uint8Array[]> = {
|
||||
logical: [],
|
||||
visual: [],
|
||||
measure: [],
|
||||
@@ -191,25 +204,25 @@ describe("borrowed pointer call sites", () => {
|
||||
let lineCount = 2
|
||||
let bytesReceived = 20n
|
||||
|
||||
symbols.editBufferGetCursorPosition = (_buffer, output: ArrayBuffer) => {
|
||||
outputBuffers.logical.push(output)
|
||||
LogicalCursorStruct.packInto({ row: 0, col: logicalOffset, offset: logicalOffset++ }, new DataView(output), 0)
|
||||
symbols.editBufferGetCursorPosition = (_buffer, output: Uint8Array) => {
|
||||
outputViews.logical.push(output)
|
||||
LogicalCursorStruct.packInto({ row: 0, col: logicalOffset, offset: logicalOffset++ }, dataView(output), 0)
|
||||
}
|
||||
symbols.editorViewGetVisualCursor = (_view, output: ArrayBuffer) => {
|
||||
outputBuffers.visual.push(output)
|
||||
symbols.editorViewGetVisualCursor = (_view, output: Uint8Array) => {
|
||||
outputViews.visual.push(output)
|
||||
VisualCursorStruct.packInto(
|
||||
{ visualRow: 0, visualCol: visualOffset, logicalRow: 0, logicalCol: visualOffset, offset: visualOffset++ },
|
||||
new DataView(output),
|
||||
dataView(output),
|
||||
0,
|
||||
)
|
||||
}
|
||||
symbols.textBufferViewMeasureForDimensions = (_view, _width, _height, output: ArrayBuffer) => {
|
||||
outputBuffers.measure.push(output)
|
||||
MeasureResultStruct.packInto({ lineCount: lineCount++, widthColsMax: 8 }, new DataView(output), 0)
|
||||
symbols.textBufferViewMeasureForDimensions = (_view, _width, _height, output: Uint8Array) => {
|
||||
outputViews.measure.push(output)
|
||||
MeasureResultStruct.packInto({ lineCount: lineCount++, widthColsMax: 8 }, dataView(output), 0)
|
||||
return 1
|
||||
}
|
||||
symbols.audioGetStreamStats = (_engine, _streamId, output: ArrayBuffer) => {
|
||||
outputBuffers.audio.push(output)
|
||||
symbols.audioGetStreamStats = (_engine, _streamId, output: Uint8Array) => {
|
||||
outputViews.audio.push(output)
|
||||
AudioStreamStatsStruct.packInto(
|
||||
{
|
||||
bytesReceived: bytesReceived++,
|
||||
@@ -224,7 +237,7 @@ describe("borrowed pointer call sites", () => {
|
||||
errorCode: 0,
|
||||
readyGeneration: 1,
|
||||
},
|
||||
new DataView(output),
|
||||
dataView(output),
|
||||
0,
|
||||
)
|
||||
return 0
|
||||
@@ -255,17 +268,17 @@ describe("borrowed pointer call sites", () => {
|
||||
expect(audioFirst.bytesReceived).toBe(20n)
|
||||
expect(audioSecond.bytesReceived).toBe(21n)
|
||||
|
||||
for (const buffers of Object.values(outputBuffers)) {
|
||||
expect(buffers).toHaveLength(2)
|
||||
expect(buffers[0]).toBeInstanceOf(ArrayBuffer)
|
||||
expect(buffers[1]).toBe(buffers[0])
|
||||
for (const views of Object.values(outputViews)) {
|
||||
expect(views).toHaveLength(2)
|
||||
expect(views[0]).toBeInstanceOf(Uint8Array)
|
||||
expect(views[1]).toBe(views[0])
|
||||
}
|
||||
} finally {
|
||||
Object.assign(symbols, originals)
|
||||
}
|
||||
})
|
||||
|
||||
test("grid draw repacks and forwards one owning ArrayBuffer", () => {
|
||||
test("grid draw repacks and forwards one owning Uint8Array", () => {
|
||||
const calls: any[][] = []
|
||||
const original = symbols.bufferDrawGrid
|
||||
const fg = RGBA.fromValues(1, 1, 1, 1)
|
||||
@@ -278,16 +291,16 @@ describe("borrowed pointer call sites", () => {
|
||||
drawInner: true,
|
||||
drawOuter: false,
|
||||
})
|
||||
const firstBuffer = calls[0]![8] as ArrayBuffer
|
||||
expect(firstBuffer).toBeInstanceOf(ArrayBuffer)
|
||||
expect(new Uint8Array(firstBuffer).slice(0, GridDrawOptionsStruct.size)).toEqual(new Uint8Array([1, 0]))
|
||||
const firstView = calls[0]![8] as Uint8Array
|
||||
expect(firstView).toBeInstanceOf(Uint8Array)
|
||||
expect(firstView).toEqual(new Uint8Array([1, 0]))
|
||||
|
||||
lib.bufferDrawGrid(1 as any, chars, fg, bg, offsets, 1, offsets, 1, {
|
||||
drawInner: false,
|
||||
drawOuter: true,
|
||||
})
|
||||
expect(calls[1]![8]).toBe(firstBuffer)
|
||||
expect(new Uint8Array(firstBuffer).slice(0, GridDrawOptionsStruct.size)).toEqual(new Uint8Array([0, 1]))
|
||||
expect(calls[1]![8]).toBe(firstView)
|
||||
expect(firstView).toEqual(new Uint8Array([0, 1]))
|
||||
} finally {
|
||||
symbols.bufferDrawGrid = original
|
||||
}
|
||||
@@ -313,41 +326,43 @@ describe("borrowed pointer call sites", () => {
|
||||
try {
|
||||
for (const [index, name] of logicalQueries.entries()) {
|
||||
originals.set(name, symbols[name])
|
||||
const outputBuffers: ArrayBuffer[] = []
|
||||
const outputViews: Uint8Array[] = []
|
||||
let offset = index + 2
|
||||
symbols[name] = (...args: any[]) => {
|
||||
const output = args.at(-1) as ArrayBuffer
|
||||
outputBuffers.push(output)
|
||||
LogicalCursorStruct.packInto({ row: index, col: index + 1, offset: offset++ }, new DataView(output), 0)
|
||||
const output = args.at(-1) as Uint8Array
|
||||
outputViews.push(output)
|
||||
LogicalCursorStruct.packInto({ row: index, col: index + 1, offset: offset++ }, dataView(output), 0)
|
||||
}
|
||||
const first = (lib as any)[name](1)
|
||||
const second = (lib as any)[name](1)
|
||||
expect(first).not.toBe(second)
|
||||
expect(first).toEqual({ row: index, col: index + 1, offset: index + 2 })
|
||||
expect(second).toEqual({ row: index, col: index + 1, offset: index + 3 })
|
||||
expect(outputBuffers[1]).toBe(outputBuffers[0])
|
||||
expect(outputViews[0]).toBeInstanceOf(Uint8Array)
|
||||
expect(outputViews[1]).toBe(outputViews[0])
|
||||
}
|
||||
|
||||
originals.set("editBufferOffsetToPosition", symbols.editBufferOffsetToPosition)
|
||||
const positionBuffers: ArrayBuffer[] = []
|
||||
symbols.editBufferOffsetToPosition = (_buffer, offset: number, output: ArrayBuffer) => {
|
||||
positionBuffers.push(output)
|
||||
LogicalCursorStruct.packInto({ row: 1, col: 2, offset }, new DataView(output), 0)
|
||||
const positionViews: Uint8Array[] = []
|
||||
symbols.editBufferOffsetToPosition = (_buffer, offset: number, output: Uint8Array) => {
|
||||
positionViews.push(output)
|
||||
LogicalCursorStruct.packInto({ row: 1, col: 2, offset }, dataView(output), 0)
|
||||
return 1
|
||||
}
|
||||
const firstPosition = lib.editBufferOffsetToPosition(1 as any, 9)
|
||||
const secondPosition = lib.editBufferOffsetToPosition(1 as any, 10)
|
||||
expect(firstPosition).toEqual({ row: 1, col: 2, offset: 9 })
|
||||
expect(secondPosition).toEqual({ row: 1, col: 2, offset: 10 })
|
||||
expect(positionBuffers[1]).toBe(positionBuffers[0])
|
||||
expect(positionViews[0]).toBeInstanceOf(Uint8Array)
|
||||
expect(positionViews[1]).toBe(positionViews[0])
|
||||
|
||||
for (const [index, name] of visualQueries.entries()) {
|
||||
originals.set(name, symbols[name])
|
||||
const outputBuffers: ArrayBuffer[] = []
|
||||
const outputViews: Uint8Array[] = []
|
||||
let offset = index + 4
|
||||
symbols[name] = (...args: any[]) => {
|
||||
const output = args.at(-1) as ArrayBuffer
|
||||
outputBuffers.push(output)
|
||||
const output = args.at(-1) as Uint8Array
|
||||
outputViews.push(output)
|
||||
VisualCursorStruct.packInto(
|
||||
{
|
||||
visualRow: index,
|
||||
@@ -356,7 +371,7 @@ describe("borrowed pointer call sites", () => {
|
||||
logicalCol: index + 3,
|
||||
offset: offset++,
|
||||
},
|
||||
new DataView(output),
|
||||
dataView(output),
|
||||
0,
|
||||
)
|
||||
}
|
||||
@@ -365,7 +380,8 @@ describe("borrowed pointer call sites", () => {
|
||||
expect(first).not.toBe(second)
|
||||
expect(first.offset).toBe(index + 4)
|
||||
expect(second.offset).toBe(index + 5)
|
||||
expect(outputBuffers[1]).toBe(outputBuffers[0])
|
||||
expect(outputViews[0]).toBeInstanceOf(Uint8Array)
|
||||
expect(outputViews[1]).toBe(outputViews[0])
|
||||
}
|
||||
} finally {
|
||||
for (const [name, original] of originals) symbols[name] = original
|
||||
@@ -602,7 +618,7 @@ describe("borrowed pointer call sites", () => {
|
||||
}
|
||||
})
|
||||
|
||||
test("audioCloseStream forwards its reason and unpacks the owned output buffer", () => {
|
||||
test("audioCloseStream forwards its reason and unpacks the owned output view", () => {
|
||||
const calls: any[][] = []
|
||||
const original = symbols.audioCloseStream
|
||||
symbols.audioCloseStream = (...args: any[]) => {
|
||||
@@ -621,7 +637,7 @@ describe("borrowed pointer call sites", () => {
|
||||
errorCode: -3,
|
||||
readyGeneration: 7,
|
||||
},
|
||||
new DataView(args[3]),
|
||||
dataView(args[3] as Uint8Array),
|
||||
0,
|
||||
)
|
||||
return 0
|
||||
@@ -632,7 +648,7 @@ describe("borrowed pointer call sites", () => {
|
||||
expect(calls[0]![0]).toBe(11)
|
||||
expect(calls[0]![1]).toBe(22)
|
||||
expect(calls[0]![2]).toBe(NativeAudioStreamCloseReason.TransportError)
|
||||
expect(calls[0]![3]).toBeInstanceOf(ArrayBuffer)
|
||||
expect(calls[0]![3]).toBeInstanceOf(Uint8Array)
|
||||
expect(result).toEqual({
|
||||
status: 0,
|
||||
stats: {
|
||||
@@ -817,9 +833,9 @@ describe("borrowed pointer call sites", () => {
|
||||
lib.imageComposite(handle, handle, 0, 0, 0, 255)
|
||||
|
||||
expect(calls.get("bufferDrawImage")![2]).toBe(firstImageOptions)
|
||||
expect(firstImageOptions).toBeInstanceOf(ArrayBuffer)
|
||||
expect((firstImageOptions as ArrayBuffer).byteLength).toBe(ImageDrawOptionsStruct.size)
|
||||
expect(ImageDrawOptionsStruct.unpack(firstImageOptions as ArrayBuffer)).toMatchObject({
|
||||
expect(firstImageOptions).toBeInstanceOf(Uint8Array)
|
||||
expect((firstImageOptions as Uint8Array).byteLength).toBe(ImageDrawOptionsStruct.size)
|
||||
expect(ImageDrawOptionsStruct.unpack((firstImageOptions as Uint8Array).buffer)).toMatchObject({
|
||||
x: 2,
|
||||
y: 3,
|
||||
width: 4,
|
||||
|
||||
+53
-44
@@ -102,6 +102,15 @@ import { isBunfsPath } from "./lib/bunfs.js"
|
||||
import { resolveNativeLibraryPath } from "#opentui/runtime-assets"
|
||||
import { allocStruct } from "bun-ffi-structs"
|
||||
|
||||
// Struct outputs use `buffer` instead of `ptr`. A `buffer` call is about 3x cheaper on Bun 1.3 and 2.5x cheaper on
|
||||
// Bun 1.4. `buffer` rejects an argument that is not a view with a TypeError. `ptr` accepts a number as a raw address.
|
||||
// `buffer` also skips the Node pointer normalizer. Bun 1.3 rejects ArrayBuffer and DataView for `buffer`, so keep one
|
||||
// Uint8Array view per reusable struct.
|
||||
function allocFFIStruct(structDefinition: Parameters<typeof allocStruct>[0]) {
|
||||
const storage = allocStruct(structDefinition)
|
||||
return { ...storage, ffiView: new Uint8Array(storage.buffer) }
|
||||
}
|
||||
|
||||
registerEnvVar({
|
||||
name: "OPENTUI_LIBC",
|
||||
description: "Select Linux native libc package. Supported values: glibc, musl.",
|
||||
@@ -454,11 +463,11 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "i32",
|
||||
},
|
||||
embeddedTerminalCursor: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "i32",
|
||||
},
|
||||
embeddedTerminalEncodeKey: {
|
||||
args: ["u32", "ptr", "ptr", "u32", "ptr", "u32", "ptr", "u32", "ptr"],
|
||||
args: ["u32", "buffer", "ptr", "u32", "ptr", "u32", "ptr", "u32", "ptr"],
|
||||
returns: "i32",
|
||||
},
|
||||
embeddedTerminalEncodeMouse: {
|
||||
@@ -818,7 +827,7 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
bufferDrawImage: {
|
||||
args: ["u32", "u32", "ptr"],
|
||||
args: ["u32", "u32", "buffer"],
|
||||
returns: "u8",
|
||||
},
|
||||
bufferDrawPackedBuffer: {
|
||||
@@ -834,7 +843,7 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
bufferDrawGrid: {
|
||||
args: ["u32", "buffer", "buffer", "buffer", "buffer", "u32", "buffer", "u32", "ptr"],
|
||||
args: ["u32", "buffer", "buffer", "buffer", "buffer", "u32", "buffer", "u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
bufferDrawBox: {
|
||||
@@ -1207,7 +1216,7 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
textBufferViewMeasureForDimensions: {
|
||||
args: ["u32", "u32", "u32", "ptr"],
|
||||
args: ["u32", "u32", "u32", "buffer"],
|
||||
returns: "bool",
|
||||
},
|
||||
bufferDrawTextBufferView: {
|
||||
@@ -1359,7 +1368,7 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
editBufferGetCursorPosition: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editBufferGetId: {
|
||||
@@ -1403,19 +1412,19 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
editBufferGetNextWordBoundary: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editBufferGetPrevWordBoundary: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editBufferGetEOL: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editBufferOffsetToPosition: {
|
||||
args: ["u32", "u32", "ptr"],
|
||||
args: ["u32", "u32", "buffer"],
|
||||
returns: "bool",
|
||||
},
|
||||
editBufferPositionToOffset: {
|
||||
@@ -1495,7 +1504,7 @@ function getOpenTUILib(libPath?: string) {
|
||||
|
||||
// EditorView VisualCursor methods
|
||||
editorViewGetVisualCursor: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
|
||||
@@ -1516,23 +1525,23 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGetNextWordBoundary: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGetPrevWordBoundary: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGetEOL: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGetVisualSOL: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGetVisualEOL: {
|
||||
args: ["u32", "ptr"],
|
||||
args: ["u32", "buffer"],
|
||||
returns: "void",
|
||||
},
|
||||
editorViewGotoVisualLineEnd: {
|
||||
@@ -1958,11 +1967,11 @@ function getOpenTUILib(libPath?: string) {
|
||||
returns: "i32",
|
||||
},
|
||||
audioGetStreamStats: {
|
||||
args: ["u32", "u32", "ptr"],
|
||||
args: ["u32", "u32", "buffer"],
|
||||
returns: "i32",
|
||||
},
|
||||
audioCloseStream: {
|
||||
args: ["u32", "u32", "u32", "ptr"],
|
||||
args: ["u32", "u32", "u32", "buffer"],
|
||||
returns: "i32",
|
||||
},
|
||||
audioLoad: {
|
||||
@@ -3225,11 +3234,11 @@ class FFIRenderLib implements RenderLib {
|
||||
private readonly yogaLayout = new Float32Array(6)
|
||||
private readonly ffiStructStorage = {
|
||||
logicalCursor: {
|
||||
...allocStruct(LogicalCursorStruct),
|
||||
...allocFFIStruct(LogicalCursorStruct),
|
||||
result: { row: 0, col: 0, offset: 0 } as LogicalCursor,
|
||||
},
|
||||
visualCursor: {
|
||||
...allocStruct(VisualCursorStruct),
|
||||
...allocFFIStruct(VisualCursorStruct),
|
||||
result: {
|
||||
visualRow: 0,
|
||||
visualCol: 0,
|
||||
@@ -3239,13 +3248,13 @@ class FFIRenderLib implements RenderLib {
|
||||
} as VisualCursor,
|
||||
},
|
||||
measureResult: {
|
||||
...allocStruct(MeasureResultStruct),
|
||||
...allocFFIStruct(MeasureResultStruct),
|
||||
result: { lineCount: 0, widthColsMax: 0 } as MeasureResult,
|
||||
},
|
||||
embeddedTerminalCursor: allocStruct(EmbeddedTerminalCursorStruct),
|
||||
embeddedTerminalKeyOptions: allocStruct(EmbeddedTerminalKeyOptionsStruct),
|
||||
embeddedTerminalCursor: allocFFIStruct(EmbeddedTerminalCursorStruct),
|
||||
embeddedTerminalKeyOptions: allocFFIStruct(EmbeddedTerminalKeyOptionsStruct),
|
||||
audioStreamStats: {
|
||||
...allocStruct(AudioStreamStatsStruct),
|
||||
...allocFFIStruct(AudioStreamStatsStruct),
|
||||
result: {
|
||||
bytesReceived: 0n,
|
||||
framesDecoded: 0n,
|
||||
@@ -3260,8 +3269,8 @@ class FFIRenderLib implements RenderLib {
|
||||
readyGeneration: 0,
|
||||
} as NativeAudioStreamStats,
|
||||
},
|
||||
imageDrawOptions: allocStruct(ImageDrawOptionsStruct),
|
||||
gridDrawOptions: allocStruct(GridDrawOptionsStruct),
|
||||
imageDrawOptions: allocFFIStruct(ImageDrawOptionsStruct),
|
||||
gridDrawOptions: allocFFIStruct(GridDrawOptionsStruct),
|
||||
}
|
||||
private disposed = false
|
||||
private clipboardServices = new Set<ClipboardServiceHandle>()
|
||||
@@ -3400,7 +3409,7 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public embeddedTerminalCursor(handle: EmbeddedTerminalHandle): EmbeddedTerminalCursor {
|
||||
const storage = this.ffiStructStorage.embeddedTerminalCursor
|
||||
embeddedTerminalResult(this.opentui.symbols.embeddedTerminalCursor(handle, storage.buffer), "cursor query")
|
||||
embeddedTerminalResult(this.opentui.symbols.embeddedTerminalCursor(handle, storage.ffiView), "cursor query")
|
||||
const result = EmbeddedTerminalCursorStruct.unpack(storage.buffer)
|
||||
return {
|
||||
x: result.x,
|
||||
@@ -3436,7 +3445,7 @@ class FFIRenderLib implements RenderLib {
|
||||
const encode = (output: Uint8Array) =>
|
||||
this.opentui.symbols.embeddedTerminalEncodeKey(
|
||||
handle,
|
||||
options.buffer,
|
||||
options.ffiView,
|
||||
keyCodeLength === 0 ? null : keyCode,
|
||||
keyCodeLength,
|
||||
textLength === 0 ? null : text,
|
||||
@@ -4063,7 +4072,7 @@ class FFIRenderLib implements RenderLib {
|
||||
storage.view,
|
||||
0,
|
||||
)
|
||||
return Boolean(this.opentui.symbols.bufferDrawImage(buffer, image, storage.buffer))
|
||||
return Boolean(this.opentui.symbols.bufferDrawImage(buffer, image, storage.ffiView))
|
||||
}
|
||||
|
||||
public bufferDrawPackedBuffer(
|
||||
@@ -4156,7 +4165,7 @@ class FFIRenderLib implements RenderLib {
|
||||
columnCount,
|
||||
rowOffsets,
|
||||
rowCount,
|
||||
this.ffiStructStorage.gridDrawOptions.buffer,
|
||||
this.ffiStructStorage.gridDrawOptions.ffiView,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5373,7 +5382,7 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public textBufferViewMeasureForDimensions(view: Pointer, width: number, height: number): MeasureResult | null {
|
||||
const storage = this.ffiStructStorage.measureResult
|
||||
const success = this.opentui.symbols.textBufferViewMeasureForDimensions(view, width, height, storage.buffer)
|
||||
const success = this.opentui.symbols.textBufferViewMeasureForDimensions(view, width, height, storage.ffiView)
|
||||
if (!success) return null
|
||||
const result = MeasureResultStruct.unpackInto(storage.view, storage.result)
|
||||
return { lineCount: result.lineCount, widthColsMax: result.widthColsMax }
|
||||
@@ -5686,7 +5695,7 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public editBufferGetCursorPosition(buffer: Pointer): LogicalCursor {
|
||||
const storage = this.ffiStructStorage.logicalCursor
|
||||
this.opentui.symbols.editBufferGetCursorPosition(buffer, storage.buffer)
|
||||
this.opentui.symbols.editBufferGetCursorPosition(buffer, storage.ffiView)
|
||||
const cursor = LogicalCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { row: cursor.row, col: cursor.col, offset: cursor.offset }
|
||||
}
|
||||
@@ -5745,28 +5754,28 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public editBufferGetNextWordBoundary(buffer: Pointer): LogicalCursor {
|
||||
const storage = this.ffiStructStorage.logicalCursor
|
||||
this.opentui.symbols.editBufferGetNextWordBoundary(buffer, storage.buffer)
|
||||
this.opentui.symbols.editBufferGetNextWordBoundary(buffer, storage.ffiView)
|
||||
const cursor = LogicalCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { row: cursor.row, col: cursor.col, offset: cursor.offset }
|
||||
}
|
||||
|
||||
public editBufferGetPrevWordBoundary(buffer: Pointer): LogicalCursor {
|
||||
const storage = this.ffiStructStorage.logicalCursor
|
||||
this.opentui.symbols.editBufferGetPrevWordBoundary(buffer, storage.buffer)
|
||||
this.opentui.symbols.editBufferGetPrevWordBoundary(buffer, storage.ffiView)
|
||||
const cursor = LogicalCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { row: cursor.row, col: cursor.col, offset: cursor.offset }
|
||||
}
|
||||
|
||||
public editBufferGetEOL(buffer: Pointer): LogicalCursor {
|
||||
const storage = this.ffiStructStorage.logicalCursor
|
||||
this.opentui.symbols.editBufferGetEOL(buffer, storage.buffer)
|
||||
this.opentui.symbols.editBufferGetEOL(buffer, storage.ffiView)
|
||||
const cursor = LogicalCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { row: cursor.row, col: cursor.col, offset: cursor.offset }
|
||||
}
|
||||
|
||||
public editBufferOffsetToPosition(buffer: Pointer, offset: number): LogicalCursor | null {
|
||||
const storage = this.ffiStructStorage.logicalCursor
|
||||
const success = this.opentui.symbols.editBufferOffsetToPosition(buffer, offset, storage.buffer)
|
||||
const success = this.opentui.symbols.editBufferOffsetToPosition(buffer, offset, storage.ffiView)
|
||||
if (!success) return null
|
||||
const cursor = LogicalCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { row: cursor.row, col: cursor.col, offset: cursor.offset }
|
||||
@@ -5966,7 +5975,7 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public editorViewGetVisualCursor(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetVisualCursor(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetVisualCursor(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
@@ -5989,35 +5998,35 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public editorViewGetNextWordBoundary(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetNextWordBoundary(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetNextWordBoundary(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
|
||||
public editorViewGetPrevWordBoundary(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetPrevWordBoundary(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetPrevWordBoundary(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
|
||||
public editorViewGetEOL(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetEOL(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetEOL(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
|
||||
public editorViewGetVisualSOL(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetVisualSOL(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetVisualSOL(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
|
||||
public editorViewGetVisualEOL(view: Pointer): VisualCursor {
|
||||
const storage = this.ffiStructStorage.visualCursor
|
||||
this.opentui.symbols.editorViewGetVisualEOL(view, storage.buffer)
|
||||
this.opentui.symbols.editorViewGetVisualEOL(view, storage.ffiView)
|
||||
const cursor = VisualCursorStruct.unpackInto(storage.view, storage.result)
|
||||
return { ...cursor }
|
||||
}
|
||||
@@ -6371,7 +6380,7 @@ class FFIRenderLib implements RenderLib {
|
||||
|
||||
public audioGetStreamStats(engine: AudioEngineHandle, streamId: number): NativeAudioStreamStats | null {
|
||||
const storage = this.ffiStructStorage.audioStreamStats
|
||||
const status = this.opentui.symbols.audioGetStreamStats(engine, streamId, storage.buffer)
|
||||
const status = this.opentui.symbols.audioGetStreamStats(engine, streamId, storage.ffiView)
|
||||
if (status !== 0) return null
|
||||
const stats = AudioStreamStatsStruct.unpackInto(storage.view, storage.result) as NativeAudioStreamStats
|
||||
return { ...stats }
|
||||
@@ -6383,7 +6392,7 @@ class FFIRenderLib implements RenderLib {
|
||||
reason: NativeAudioStreamCloseReason,
|
||||
): { status: number; stats: NativeAudioStreamStats | null } {
|
||||
const storage = this.ffiStructStorage.audioStreamStats
|
||||
const status = this.opentui.symbols.audioCloseStream(engine, streamId, reason, storage.buffer)
|
||||
const status = this.opentui.symbols.audioCloseStream(engine, streamId, reason, storage.ffiView)
|
||||
if (status !== 0) return { status, stats: null }
|
||||
const stats = AudioStreamStatsStruct.unpackInto(storage.view, storage.result) as NativeAudioStreamStats
|
||||
return { status, stats: { ...stats } }
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"web-tree-sitter": "0.25.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/three": "0.177.0",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"react": ">=19.2.0",
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"typescript": "^5"
|
||||
},
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"@types/react-reconciler": "^0.33.0",
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"devDependencies": {
|
||||
"@opentui/keymap": "workspace:*",
|
||||
"@types/babel__core": "7.20.5",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"solid-js": "1.9.12",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -40,8 +40,10 @@ npm install @opentui/ssh
|
||||
|
||||
`@opentui/core` is a peer dependency. Supported runtimes are Bun ≥ 1.3.0 and
|
||||
Node.js ≥ 26.4.0. CI runs the SSH integration suite with Bun on macOS, Linux,
|
||||
and Windows, and installs, imports, starts, and closes the packed ESM package
|
||||
on Node.js.
|
||||
and Windows. CI also installs, imports, starts, and closes the packed ESM
|
||||
package on Node.js.
|
||||
|
||||
Use Bun ≥ 1.4.0 on native Windows arm64.
|
||||
|
||||
## The shape: `createServer(config).serve(handler)`
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@opentui/core": "workspace:*",
|
||||
"@opentui/react": "workspace:*",
|
||||
"@opentui/solid": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.2.0",
|
||||
"@types/ssh2": "^1.15.0",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"planck": "^1.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/three": "0.177.0",
|
||||
"commander": "^13.1.0",
|
||||
|
||||
@@ -134,6 +134,7 @@ writeFileSync(
|
||||
homepage: packageJson.homepage,
|
||||
repository: packageJson.repository,
|
||||
bugs: packageJson.bugs,
|
||||
engines: packageJson.engines,
|
||||
exports,
|
||||
dependencies: processedDependencies,
|
||||
optionalDependencies: packageJson.optionalDependencies,
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentui/qrcode": "workspace:*",
|
||||
"@types/bun": "1.3.14",
|
||||
"@types/bun": "1.4.1",
|
||||
"@xterm/addon-unicode11": "^0.8.0",
|
||||
"@xterm/headless": "^5.5.0",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -77,7 +77,7 @@ A failed automatic start destroys the partial native engine. Successful automati
|
||||
|
||||
Audio uses the same native runtime as the renderer. Read [Runtime and platform support](/docs/getting-started/runtime-support) for setup and distribution details.
|
||||
|
||||
The local requirements are Bun 1.3.0 or later, or Node.js 26.4.0 or later with experimental FFI. Native packages support macOS, Linux, and Windows on x64 and arm64.
|
||||
The local requirements are Bun 1.3.0 or later, or Node.js 26.4.0 or later with experimental FFI. Native packages support macOS, Linux, and Windows on x64 and arm64. Use Bun 1.4.0 or later on native Windows arm64.
|
||||
|
||||
Linux selects glibc by default. Set the documented libc selector when the target needs musl. Audio has no browser target.
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ Check the runtime, native artifact, permission, asset, and package requirements
|
||||
|
||||
The Node.js acceptance scripts accept Node.js 26.4 or later.
|
||||
|
||||
Use Bun 1.4.0 or later on native Windows arm64 because Bun 1.3 does not support FFI on that target.
|
||||
|
||||
Use ESM for Node.js applications. The Core root has an asynchronous ESM graph. A CommonJS `require("@opentui/core")`
|
||||
call fails with `ERR_REQUIRE_ASYNC_MODULE`.
|
||||
|
||||
|
||||
@@ -380,7 +380,8 @@ The package root works in Bun and Node.js. Each framework path re-exports the fu
|
||||
|
||||
## `@opentui/ssh`
|
||||
|
||||
The package supports Bun 1.3.0 and Node.js 26.4.0 or later. It has one public entry point.
|
||||
The package supports Bun 1.3.0 or later and Node.js 26.4.0 or later. Use Bun 1.4.0 or later on native Windows arm64.
|
||||
It has one public entry point.
|
||||
|
||||
| Symbols | Class | Canonical documentation |
|
||||
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------------------------- |
|
||||
|
||||
@@ -21,7 +21,8 @@ SSH is an access transport. It is not an application packaging format. See
|
||||
bun add @opentui/ssh @opentui/core
|
||||
```
|
||||
|
||||
`@opentui/core` is a peer dependency. The SSH package declares Bun >=1.3.0 and Node.js >=26.4.0. The SSH Node CI lane
|
||||
`@opentui/core` is a peer dependency. The SSH package declares Bun >=1.3.0 and Node.js >=26.4.0. Use Bun >=1.4.0 on
|
||||
native Windows arm64. The SSH Node CI lane
|
||||
runs on Linux x64. Its packed Node consumer test uses a Core stub, so that test does not start the native renderer. See
|
||||
[Runtime and platform support](/docs/getting-started/runtime-support) before you run the native renderer with Node.js.
|
||||
|
||||
|
||||
@@ -12,10 +12,12 @@ skill:
|
||||
|
||||
## Requirements
|
||||
|
||||
`@opentui/three` requires Bun >=1.3.0. It does not support Node.js. The package pins Three.js 0.177.0. Its manifest lists
|
||||
`bun-webgpu` 0.1.7, `@dimforge/rapier2d-simd-compat`, and `planck` as optional dependencies, but the root statically
|
||||
imports all three through its renderer and physics exports. They must all resolve even when an application does not
|
||||
use physics. A normal install includes them. An install with optional dependencies omitted makes the root import fail.
|
||||
`@opentui/three` requires Bun >=1.3.0. It does not support Node.js.
|
||||
|
||||
The package pins Three.js 0.177.0. Its manifest lists `bun-webgpu` 0.1.7, `@dimforge/rapier2d-simd-compat`, and `planck`
|
||||
as optional dependencies. The package root imports all three through its renderer and physics exports. All three
|
||||
dependencies must resolve even when an application does not use physics. A normal install includes them. The root
|
||||
module does not load when the installation omits optional dependencies.
|
||||
|
||||
```bash
|
||||
bun add @opentui/three
|
||||
|
||||
@@ -24,7 +24,7 @@ categories:
|
||||
|
||||
`@opentui/ssh` maps each accepted SSH shell to a `CliRenderer`. The renderer dimensions track the client's terminal.
|
||||
|
||||
The package requires Bun `>=1.3.0` or Node.js `>=26.4.0`.
|
||||
The package requires Bun `>=1.3.0` or Node.js `>=26.4.0`. Use Bun `>=1.4.0` on native Windows arm64.
|
||||
|
||||
Open authentication accepts SSH `none` without credentials. Use it only for loopback development. Do not expose open
|
||||
authentication to a public or untrusted network.
|
||||
|
||||
Reference in New Issue
Block a user