Skip to content

Stop one dart:io type from hiding the package from web - #248

Merged
vicajilau merged 1 commit into
mainfrom
feat/web-platform
Sep 4, 2026
Merged

Stop one dart:io type from hiding the package from web#248
vicajilau merged 1 commit into
mainfrom
feat/web-platform

Conversation

@vicajilau

Copy link
Copy Markdown
Owner

pub.dev lists dartssh2 for android, ios, windows, linux and macos, and not web. That is not just a badge: pub.dev's platform filter means the package does not appear at all in a search narrowed to web.

The cause is a single type. SftpFile.downloadToRandomAccess takes a dart:io RandomAccessFile, and naming it from the SFTP library was enough for pana to classify the whole package as unavailable there, even though everything else compiled and ran and 4.0.0 had already fixed the ciphers and SFTP under dart2js.

What changed

The method moves to an SftpFileDownload extension in lib/src/sftp/sftp_file_io.dart, exported conditionally the way SSHSocket and dynamic forwarding already are.

Non-breaking on the VM. Same package:dartssh2/dartssh2.dart import, same file.downloadToRandomAccess(raf) call. On the web the extension is absent, along with the RandomAccessFile it would have needed.

The extension reaches back into SftpFile through isClosed, which was already public, and readChunk, which was _readChunk and is now @internal. That one method is the entire seam. _ReadCompletion was used by nothing else so it moved with the method, and the two size constants are redeclared in the new library rather than widening the internal surface further.

Verified with pana rather than argued

Same tool pub.dev scores with:

before  platform:android, platform:ios, platform:windows, platform:linux, platform:macos
after   platform:android, platform:ios, platform:windows, platform:linux, platform:macos, platform:web

dart format and dart analyze --fatal-infos clean, 703 tests passing.

Note

I tried the cheaper version first, a conditional import 'dart:io' if ... with a stub RandomAccessFile, and it does not work. That trick is for types the package hands back, not types a caller passes in: the stub class and the real one are unrelated, so every existing call site stops compiling. This route avoids that entirely.

README gains a line saying downloadToRandomAccess is the one thing not available on the web, alongside the existing ChaCha20-Poly1305 caveat.

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.83784% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.84%. Comparing base (55ef90f) to head (bdcece8).

Files with missing lines Patch % Lines
lib/src/sftp/sftp_file_io.dart 87.50% 9 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #248   +/-   ##
=======================================
  Coverage   77.84%   77.84%           
=======================================
  Files          81       82    +1     
  Lines        6395     6395           
=======================================
  Hits         4978     4978           
  Misses       1417     1417           
Flag Coverage Δ
unittests 77.84% <87.83%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
lib/src/sftp/sftp_client.dart 63.63% <ø> (ø)
lib/src/sftp/sftp_file.dart 87.73% <100.00%> (+0.07%) ⬆️
lib/src/sftp/sftp_file_io.dart 87.50% <87.50%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

pub.dev listed android, ios, windows, linux and macos and not web. That
also keeps the package out of any search narrowed to web, so it costs
discoverability rather than a badge.

The cause was one type. `SftpFile.downloadToRandomAccess` takes a
`dart:io` `RandomAccessFile`, and naming it from the SFTP library made
pana classify the whole package as unavailable there, even though
everything else compiled and ran and 4.0.0 had already made the ciphers
and SFTP work under dart2js.

The method moves to an `SftpFileDownload` extension in its own library,
exported conditionally the way `SSHSocket` and dynamic forwarding
already are. Nothing changes for a caller on the VM: same import from
`package:dartssh2/dartssh2.dart`, same call. On the web the extension is
absent, along with the `RandomAccessFile` it would need.

The extension reaches back through `isClosed`, already public, and
`readChunk`, which was `_readChunk` and is now `@internal`. That one
method is the entire seam. `_ReadCompletion` was used by nothing else so
it moved too, and the two size constants are redeclared rather than
widening the surface further.

Saying `platform:web` on pub.dev is a stronger claim than a paragraph in
the README, so CI now checks it. Everything that ran under `-p chrome`
until now proved the pieces compile and behave, and none of it put a
packet on a wire, which is the gap that let every AEAD cipher and the
whole of SFTP sit broken on the web until 4.0.0 with a green suite the
whole time. So the browser now runs against the same sshd container the
VM interop tests use, through `tool/ws_bridge.dart`, because a browser
has no TCP socket of its own. Four tests: a handshake, a command, a
session pinned to aes256-gcm because its nonce counter is the code that
threw under dart2js, and an SFTP round trip because every size and
offset on the wire is a 64-bit field. The socket they connect through is
the WebSocket one the README tells web users to write, so it doubles as
a worked example.

They skip when the bridge is not there, the way the VM interop tests
skip without the server, decided by probing the bridge rather than by a
compile-time define: `dart test` has neither `--define` nor
`--dart2js-args`, and a browser has no `Platform.environment`.

Verified: pana reports `platform:web` on this branch and not on main,
and the four browser tests pass in CI against the real server. Project
coverage is unchanged at 4978/6395, the lines codecov reports as new
being the same error paths that were already uncovered before the move.
@vicajilau
vicajilau merged commit 982a793 into main Sep 4, 2026
6 of 7 checks passed
@vicajilau
vicajilau deleted the feat/web-platform branch September 4, 2026 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant