Commit Graph
232 Commits
Author SHA1 Message Date
codingetandClaude 37f2fb04a0 feat: integrate @webnet/react and @webnet/utils into example-app and test-app
Checks / lint (pull_request) Successful in 2m50s
Checks / format (pull_request) Successful in 3m22s
Checks / typetest (pull_request) Successful in 10m10s
Checks / typecheck (pull_request) Successful in 10m43s
Node Tests / node-tests (pull_request) Successful in 10m50s
Checks / build (pull_request) Successful in 11m27s
Browser Tests / browser-tests (pull_request) Successful in 12m2s
- example-app: replace local useClient duplicate with @webnet/react, add
  useLocalStorage to persist SharedWorker preference across page reloads
- example-app: replace local fmtSize duplicate with @webnet/utils/fmtSize,
  use download() util in WaitingFileDebug instead of inline logic
- test-app: add @webnet/utils dependency and expose it on window alongside
  other globals for console testing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 16:34:42 +00:00
codingetandClaude 5dc0478970 feat: add @webnet/react and @webnet/utils packages
Checks / lint (pull_request) Successful in 2m5s
Checks / format (pull_request) Successful in 2m4s
Checks / typecheck (pull_request) Successful in 9m10s
Checks / typetest (pull_request) Successful in 10m16s
Checks / build (pull_request) Successful in 11m12s
Node Tests / node-tests (pull_request) Successful in 10m57s
Browser Tests / browser-tests (pull_request) Successful in 12m28s
Checks / format (push) Successful in 3m15s
Checks / lint (push) Successful in 3m46s
Checks / typetest (push) Successful in 9m41s
Checks / typecheck (push) Successful in 11m54s
Checks / build (push) Successful in 11m59s
Node Tests / node-tests (push) Failing after 9m54s
Browser Tests / browser-tests (push) Successful in 14m28s
Extracts the useClient and useLocalStorage hooks into @webnet/react,
and the download, upload, readBlob, and fmtSize utilities into @webnet/utils,
so they can be shared by tailshare and other apps without living inside
a single app package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 00:42:38 +00:00
codingetandClaude 9914bd07a8 docs(agents): PR labeling and auto-finalise guidance
Node Tests / node-tests (push) Has been cancelled
Browser Tests / browser-tests (push) Has been cancelled
Checks / lint (push) Has been cancelled
Checks / format (push) Has been cancelled
Checks / typecheck (push) Has been cancelled
Checks / typetest (push) Has been cancelled
Checks / build (push) Has been cancelled
Node Tests / node-tests (pull_request) Has been cancelled
Browser Tests / browser-tests (pull_request) Has been cancelled
Checks / lint (pull_request) Successful in 3m34s
Checks / format (pull_request) Successful in 3m1s
Checks / typetest (pull_request) Successful in 9m17s
Checks / typecheck (pull_request) Successful in 9m45s
Checks / build (pull_request) Successful in 9m42s
Add instructions for agents to apply `Agentic` + `Agent/<model-line>`
labels to every PR they open (creating the labels via `tea labels create`
if absent), and to auto-finalise PRs without user prompting when the
work is trivial or was fully specified upfront.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 02:25:32 +02:00
codingetandClaude d1e4352765 docs(ai): finalise AI_CHANGES.md for PR #51
Checks / format (pull_request) Successful in 3m32s
Checks / lint (pull_request) Successful in 3m33s
Checks / typetest (pull_request) Successful in 11m24s
Checks / build (pull_request) Successful in 11m54s
Checks / typecheck (pull_request) Successful in 12m1s
Node Tests / node-tests (pull_request) Successful in 9m19s
Browser Tests / browser-tests (pull_request) Successful in 6m48s
Checks / typecheck (push) Successful in 8m34s
Browser Tests / browser-tests (push) Has been cancelled
Checks / typetest (push) Has been cancelled
Checks / build (push) Has been cancelled
Checks / lint (push) Has been cancelled
Checks / format (push) Has been cancelled
Node Tests / node-tests (push) Successful in 8m10s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 23:36:11 +00:00
codingetandClaude 1ad12e7a77 fix(tsconnect-worker): address code review findings
Checks / lint (pull_request) Successful in 3m11s
Checks / format (pull_request) Successful in 3m23s
Checks / typecheck (pull_request) Successful in 10m21s
Checks / typetest (pull_request) Successful in 10m45s
Checks / build (pull_request) Successful in 10m55s
Node Tests / node-tests (pull_request) Successful in 8m14s
Browser Tests / browser-tests (pull_request) Successful in 4m57s
- IpnClientHandle.disconnect() JSDoc clarifies that the main-thread path
  terminates IPN while the worker path is a soft detach
- connectWithFallback logs a console.warn with the caught error when falling
  back from the SharedWorker path, so unexpected fallbacks are diagnosable
- IpnMainThreadHandle constructor comment explains that pre-run() callbacks
  are intentionally dropped (run() snapshots current state on subscribe)
- lock?.release ?? null -> lock ? () => lock.release() : null to avoid
  passing an unbound method reference
- Browser test: first test adds stateStorage: "memory" to avoid leaving IDB
  state between runs
- Browser test: new test covers the IDB lock-contention path — acquires the
  lock manually then confirms connectMainThread rejects immediately

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 07:50:01 +00:00
codingetandClaude 3165653471 docs(ai): update AI_CHANGES.md for WorkerConfig.wasmUrl type widening and test isolation fix
Checks / lint (pull_request) Successful in 3m51s
Checks / format (pull_request) Successful in 3m17s
Checks / typecheck (pull_request) Successful in 12m4s
Checks / typetest (pull_request) Successful in 11m46s
Browser Tests / browser-tests (pull_request) Failing after 9m54s
Checks / build (pull_request) Successful in 12m7s
Node Tests / node-tests (pull_request) Successful in 6m32s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 23:51:52 +00:00
codingetandClaude 8040418f09 fix(tsconnect-worker): widen WorkerConfig.wasmUrl type and fix test isolation
Checks / lint (pull_request) Successful in 4m15s
Checks / format (pull_request) Successful in 4m30s
Checks / typetest (pull_request) Successful in 11m11s
Checks / typecheck (pull_request) Successful in 11m47s
Node Tests / node-tests (pull_request) Successful in 10m6s
Checks / build (pull_request) Failing after 13m8s
Browser Tests / browser-tests (pull_request) Successful in 15m26s
- WorkerConfig.wasmUrl now accepts string | ArrayBuffer | ArrayBufferView,
  allowing tests (and callers) to pass raw WASM bytes without going through
  a URL fetch (useful in Node.js where file:// fetch is unsupported)
- Restructured connect.test.ts to share a single WASM+IPN instance across
  tests via before()/after() hooks, preventing uncaught Go goroutine errors
  that fired after sequential shutdown of multiple WASM runtimes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 23:50:49 +00:00
codingetandClaude 564dbfad3f feat(tsconnect-worker): main-thread fallback with IpnClientHandle and connectWithFallback
Checks / lint (pull_request) Successful in 3m3s
Checks / format (pull_request) Successful in 3m12s
Checks / typetest (pull_request) Failing after 10m1s
Checks / build (pull_request) Failing after 10m49s
Checks / typecheck (pull_request) Failing after 10m50s
Browser Tests / browser-tests (pull_request) Failing after 12m36s
Node Tests / node-tests (pull_request) Failing after 14m20s
- IpnClientHandle interface: shared contract for both SharedWorker client and
  main-thread handle (connectionMode, store, state, running, fileOps, run,
  disconnect)
- IpnMainThreadHandle: wraps IPN + Redux store; all IpnClient methods proxy
  directly; run() fires user callbacks with current state and delegates future
  state changes via runWithStore; disconnect() releases the lock and shuts down
- connectMainThread: IndexedDB-backed state uses a web lock keyed to the DB
  name ("tsconnect-idb:<name>"), rejecting immediately if held; in-memory
  state skips the lock entirely
- connectWithFallback: tries SharedWorker first, falls back to main thread if
  unavailable, disabled (disableSharedWorker option), or on worker init failure
- useBuildIpnWorker updated to use connectWithFallback, returns IpnClientHandle
- Tests: 6 Node tests verifying main-thread init and fallback behaviour; 4
  browser tests (Chromium + Firefox) verifying worker path and explicit
  disable fallback via esbuild-bundled inline build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 23:40:45 +00:00
codingetandClaude 061a7ee50c feat(tsconnect-worker): add connectMainThread fallback for environments without SharedWorker
Checks / format (pull_request) Successful in 3m12s
Checks / lint (pull_request) Successful in 3m25s
Checks / typecheck (pull_request) Successful in 10m5s
Checks / typetest (pull_request) Successful in 10m49s
Checks / build (pull_request) Successful in 10m56s
Browser Tests / browser-tests (pull_request) Successful in 10m5s
Node Tests / node-tests (pull_request) Failing after 13m2s
Adds connectMainThread(config) for browsers that do not support
SharedWorker (e.g. Chrome on Android before 2025). It mirrors the
worker's init path but runs in the main thread, returning an IPN
instance directly instead of a worker-proxy client.

Uses navigator.locks.request with { ifAvailable: true } to protect
against concurrent tabs; rejects immediately if the lock is already
held. The lock is released when the returned IPN.shutdown() resolves.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 23:09:29 +00:00
codingetandClaude 03d12d25a9 test(tsconnect-worker): cover WorkerSSHSession.close() idempotency
Checks / lint (pull_request) Successful in 3m1s
Checks / format (pull_request) Successful in 3m16s
Checks / typetest (pull_request) Successful in 9m49s
Checks / build (pull_request) Successful in 10m41s
Checks / typecheck (pull_request) Successful in 11m31s
Node Tests / node-tests (pull_request) Successful in 9m49s
Browser Tests / browser-tests (pull_request) Successful in 10m50s
Checks / lint (push) Successful in 2m53s
Checks / format (push) Successful in 3m14s
Checks / build (push) Successful in 9m54s
Checks / typetest (push) Successful in 10m47s
Checks / typecheck (push) Successful in 11m22s
Node Tests / node-tests (push) Successful in 10m6s
Browser Tests / browser-tests (push) Successful in 11m40s
Verify that the second close() call returns false (the #closed guard path
added in the previous commit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 19:54:52 +00:00
codingetandClaude b0c25375d4 fix(tsconnect-worker): close MessagePort in close() to prevent event loop hang
Checks / format (pull_request) Successful in 3m11s
Checks / lint (pull_request) Successful in 3m40s
Checks / typecheck (pull_request) Successful in 10m58s
Checks / typetest (pull_request) Successful in 12m16s
Checks / build (pull_request) Successful in 12m26s
Node Tests / node-tests (pull_request) Successful in 10m17s
Browser Tests / browser-tests (pull_request) Successful in 11m59s
WorkerConn/WorkerTCPListener/WorkerPacketConn/WorkerSSHSession.close() sent a
"close" message but never called port.close(). The port stayed active until the
worker sent a "closed" reply, which never happens in tests. Node.js's --test
runner uses process.on('exit') rather than process.exit(), so an undrained event
loop (open MessagePort handles) caused the test process to hang indefinitely.

Fix: close() now calls this.#port.close() and immediately rejects pending
promises. WorkerSSHSession gains a #closed guard to make close() idempotent.
Test cleanup updated to call close() methods rather than leaking ports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 19:35:24 +00:00
codingetandClaude a49588d3b1 docs(ai): log test coverage gap-fill for xml, tsconnect-redux, vfs, tsconnect-worker
Checks / lint (pull_request) Successful in 2m55s
Checks / format (pull_request) Successful in 3m34s
Checks / typecheck (pull_request) Successful in 11m46s
Checks / typetest (pull_request) Successful in 12m38s
Checks / build (pull_request) Successful in 12m41s
Browser Tests / browser-tests (pull_request) Successful in 12m34s
Node Tests / node-tests (pull_request) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:50:40 +00:00
codingetandClaude 23a2dca900 test: fill coverage gaps across xml, tsconnect-redux, vfs, tsconnect-worker
- xml: add xml.test.ts (el/text/stringify — 17 tests), add test scripts to package.json
- tsconnect-redux: add selectors.test.ts covering all ~25 exported selectors (60 tests)
- vfs: add memory/memory.test.ts with direct MemoryVFS unit tests (44 tests)
- tsconnect-worker: add worker.test.ts (38 tests — WorkerConn, WorkerTCPListener,
  WorkerPacketConn, WorkerSSHSession, pumpStreamToPort, portToReadableStream); add
  test scripts, @types/node devDep, and "types":["node"] to tsconfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:50:16 +00:00
codingetandClaude b69bac3c24 docs(agents): add CI watch, auto-review, and push-notification guidance
Checks / lint (pull_request) Successful in 2m36s
Checks / format (pull_request) Successful in 3m3s
Checks / typecheck (pull_request) Successful in 10m20s
Checks / typetest (pull_request) Successful in 10m23s
Checks / build (pull_request) Successful in 11m14s
Node Tests / node-tests (pull_request) Successful in 8m49s
Browser Tests / browser-tests (pull_request) Successful in 12m18s
Checks / lint (push) Successful in 2m50s
Checks / format (push) Successful in 3m33s
Checks / build (push) Successful in 10m34s
Checks / typecheck (push) Successful in 10m45s
Checks / typetest (push) Successful in 10m44s
Node Tests / node-tests (push) Successful in 8m31s
Browser Tests / browser-tests (push) Failing after 14m46s
- Always base PRs on origin/main (fetch before branching)
- Watch CI results after push and address errors
- Spawn autonomous Sonnet-class code review when PR work is complete
- Send push notification to user when work settles or needs unblocking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 10:24:00 +00:00
codingetandClaude ecb5b7e3c4 docs(ai): update AI_CHANGES.md for FileOpsLimits refactor
Checks / format (pull_request) Successful in 2m53s
Checks / lint (pull_request) Successful in 3m6s
Checks / build (pull_request) Successful in 11m19s
Checks / typetest (pull_request) Successful in 12m0s
Checks / typecheck (pull_request) Successful in 12m19s
Node Tests / node-tests (pull_request) Successful in 10m49s
Browser Tests / browser-tests (pull_request) Successful in 11m53s
Checks / format (push) Successful in 2m55s
Checks / lint (push) Successful in 3m11s
Checks / typetest (push) Successful in 11m7s
Checks / typecheck (push) Successful in 12m27s
Checks / build (push) Successful in 12m36s
Node Tests / node-tests (push) Successful in 10m58s
Browser Tests / browser-tests (push) Successful in 14m58s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:42:38 +00:00
codingetandClaude 76579017ee refactor(tsconnect-worker): extract FileOpsLimits type to prevent drift
The setFileOpsConfig handler in worker.ts and the setFileOpsConfig method
in client.ts previously used duplicate inline type literals.  Extracting
FileOpsLimits from protocol.ts ties both to a single source of truth so
the compiler catches any future skew.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:42:38 +00:00
codingetandClaude 01a1fed6ec feat(tsconnect-worker): wire FileOps limits through WorkerConfig to init
Add fileOpsMaxFiles, fileOpsMaxTotalSize, and fileOpsMaxFileSize to
WorkerConfig so callers can set initial Taildrop limits at startup rather
than having to call setFileOpsConfig() after connecting.  The options are
passed straight through to FsaFileOps.createFromOpfs().  Runtime changes
via setFileOpsConfig() continue to work as before.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:42:38 +00:00
codingetandClaude 488ec9bb2d docs(ai): log turbo typecheck fix alongside CI workflow addition
Checks / lint (pull_request) Successful in 2m48s
Checks / format (pull_request) Successful in 3m19s
Checks / typetest (pull_request) Successful in 10m59s
Checks / typecheck (pull_request) Successful in 11m52s
Checks / build (pull_request) Successful in 11m7s
Node Tests / node-tests (pull_request) Successful in 10m8s
Browser Tests / browser-tests (pull_request) Successful in 11m43s
Checks / lint (push) Successful in 3m5s
Checks / format (push) Successful in 3m15s
Browser Tests / browser-tests (push) Failing after 4m5s
Checks / typetest (push) Successful in 9m25s
Checks / typecheck (push) Successful in 10m54s
Checks / build (push) Successful in 11m5s
Node Tests / node-tests (push) Successful in 8m31s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:16:51 +00:00
codingetandClaude a1942ff38e fix(turbo): make @webnet/tsconnect#typecheck depend on its own build
Checks / lint (pull_request) Successful in 3m5s
Checks / format (pull_request) Successful in 3m6s
Checks / typetest (pull_request) Successful in 9m28s
Checks / typecheck (pull_request) Successful in 9m44s
Checks / build (pull_request) Successful in 9m58s
Browser Tests / browser-tests (pull_request) Successful in 9m11s
Node Tests / node-tests (pull_request) Failing after 14m50s
src/index.ts imports ../dist/wasm_exec.js which only exists after build.sh
runs; the generic typecheck task only declares ^build (dependencies' build)
as a prerequisite, leaving the package's own dist absent in a fresh env.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 00:05:27 +00:00
codingetandClaude 02b80eecbd docs(ai): log CI checks workflow addition
Checks / format (pull_request) Successful in 3m49s
Checks / lint (pull_request) Successful in 3m49s
Checks / typecheck (pull_request) Failing after 3m54s
Checks / typetest (pull_request) Successful in 7m18s
Checks / build (pull_request) Successful in 6m49s
Browser Tests / browser-tests (pull_request) Successful in 8m10s
Node Tests / node-tests (pull_request) Failing after 11m53s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:52:09 +00:00
codingetandClaude 13c25e6f4d ci: add lint, format, typecheck, typetest, and build workflows
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:51:51 +00:00
codinget 57702a3943 chore: run prettier
Node Tests / node-tests (pull_request) Successful in 4m44s
Browser Tests / browser-tests (push) Failing after 7m18s
Browser Tests / browser-tests (pull_request) Successful in 10m9s
Node Tests / node-tests (push) Failing after 11m24s
2026-06-23 23:44:49 +00:00
codingetandClaude a0cc6fc4da docs(ai): log ControlledFileOps binding
Node Tests / node-tests (pull_request) Successful in 6m28s
Browser Tests / browser-tests (pull_request) Successful in 8m21s
Node Tests / node-tests (push) Successful in 5m29s
Browser Tests / browser-tests (push) Successful in 7m40s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:24:50 +00:00
codingetandClaude 630f21c898 feat(fileops): bind ControlledFileOps state to ipn store
Add a ControlledFileOps interface (UserIPNFileOps + observable limits +
onChange) satisfied by InMemoryFileOps and FsaFileOps. Bind its state
into a new fileOps Redux slice so file storage metrics and limits are
observable via store.getState().fileOps and broadcast to all clients.

In tsconnect-worker: hoist the FsaFileOps instance to module scope,
wire bindFileOpsToStore after init, and handle a new setFileOpsConfig
call that lets clients reconfigure maxFiles/maxTotalSize/maxFileSize
at runtime. Limit changes propagate back via the existing action
broadcast path so all connected clients see updated state immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 23:24:50 +00:00
codingetandClaude 22232c921b fix(browser-test-utils): polyfill __name for tsx-compiled page.evaluate callbacks
Node Tests / node-tests (pull_request) Successful in 4m45s
Browser Tests / browser-tests (pull_request) Successful in 4m22s
Node Tests / node-tests (push) Successful in 3m52s
Browser Tests / browser-tests (push) Successful in 5m39s
tsx hardcodes keepNames:true in its esbuild transform, injecting a __name
helper at module scope. Playwright's page.evaluate() serializes callbacks
via .toString(), so the helper is absent in the browser context. Inject a
matching polyfill via addInitScript on every new page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 22:13:38 +00:00
codinget a1081a8194 test: setup node tests in CI 2026-06-23 22:13:38 +00:00
codingetandClaude b7df7c35e3 chore(test): update AI_CHANGES.md to reflect coverage script removal
Browser Tests / browser (push) Failing after 1m5s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 12:49:27 +00:00
codingetandClaude 673fa3aba3 fix(test): address code review feedback on browser testing PR
- serveDirectory: replace regex path traversal guard with resolve+relative
  check, which is simpler to reason about and handles encoded edge cases
- drop test:browser:coverage scripts; c8 only covers Node orchestration
  code, not browser-executed code inside page.evaluate() — the resulting
  lcov is nearly empty and would confuse CI coverage dashboards
- guard server?.close() in after() hooks so teardown doesn't throw a
  TypeError if the before() hook failed to start the server
- extract setupLoopback() helper inside each page.evaluate() in
  transport.browser.ts to avoid verbatim repetition between tests
- add comment in helpers.browser.ts explaining the IDB readonly-transaction
  trick that ensures setState()'s async write has settled before opening
  a second IndexedDBState instance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 12:47:31 +00:00
codingetandClaude c89c478286 feat(test): add browser integration testing with Playwright
Uses Playwright as a library within node:test (not @playwright/test) to
keep the same runner and script conventions. Browser test files use the
*.browser.ts extension so the existing src/**/*.test.ts glob picks up zero
browser tests, leaving the regular test suite unaffected.

Key pieces:
- .npmrc: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 prevents binary downloads on
  npm ci; browsers are installed explicitly in CI via playwright install
- @webnet/browser-test-utils: new private package exporting forBrowsers()
  (iterates chromium + firefox, handles browser lifecycle within node:test
  suite/before/after) and a serveDirectory() helper (minimal http.createServer
  that serves a built dist/ or out/ directory so the browser can fetch ES
  modules via dynamic import())
- test:browser / test:browser:coverage scripts added to transport, vfs,
  tsconnect following the same c8 + lcov pattern as test:coverage
- turbo.json: test:browser and test:browser:coverage tasks depend on build +
  ^build (dist/ must exist before the browser can import from it)
- .gitea/workflows/test-browser.yml: CI pipeline that installs browsers with
  --with-deps then runs npm run test:browser

Integration tests:
- DataChannelTransport: real RTCPeerConnection loopback (both peers in one
  page context), exercises send/receive and close propagation
- FsaVFS: OPFS round-trip (writeFile/readFile), stat, readdir, delete
- IndexedDBState: multi-instance persistence (write via instance 1, open
  fresh instance 2 and verify IDB round-trip), empty-DB initialisation
- FsaFileOps: write/read/stat/remove cycle and rename/listFiles over OPFS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 12:47:30 +00:00
codinget bba2c5c6f5 feat(tsconnect): add limits and change handlers to InMemoryFileOps (#43)
Reviewed-on: #43
Co-authored-by: Codinget <codinget@codi.moe>
Co-committed-by: Codinget <codinget@codi.moe>
2026-06-21 13:16:59 +02:00
codingetandClaude 39b6cdb8ec chore(tsconnect): update AI_CHANGES for FsaFileOps review fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 23:15:10 +00:00
codingetandClaude a15be0f378 fix(tsconnect): address FsaFileOps review feedback
- Move #fileSizes.set in openWriter to after all async FSA ops, so a
  failed getFileHandle/createWritable/seek doesn't leave a phantom entry
  inflating fileCount and totalSize
- Fix rename to stat the file when it wasn't previously tracked, so
  untracked files don't become permanently invisible after a rename
- Document stat/totalSize inconsistency during active writes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 23:04:04 +00:00
codingetandClaude 1a3bd53348 feat(tsconnect): add limits and change handlers to FsaFileOps
Adds maxFiles/maxTotalSize/maxFileSize limit getters/setters,
fileCount/totalSize/openFiles getters, and onChange/offChange
notification to FsaFileOps, mirroring InMemoryFileOps. File sizes
are tracked in memory via a #fileSizes map; createFromOpfs now scans
the directory at startup so pre-existing files count toward limits.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 22:41:42 +00:00
codinget be031f0655 fix(tsconnect-redux): export all selectors 2026-06-20 17:11:29 +00:00
codinget 050de5c2f3 fix(tsconnect-react): add overloads to useBuildIpnWorker to make it clear options are incompatible with factory 2026-06-20 16:23:56 +00:00
codinget 52069887f3 chore(tsconnect-react): remove console.log 2026-06-20 16:21:16 +00:00
codinget 44d6a073bf fix(tsconnect-react): add webpack support for worker via factory 2026-06-20 16:08:37 +00:00
codingetandClaude 5ba7de1998 docs(ai-changes): log @webnet/vfs extraction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 16:21:00 +00:00
codingetandClaude 68313fdcda feat(vfs): extract @webnet/vfs package from @webnet/drive
Splits the VFS abstraction (AsyncVFS, Stat, VFSError, VFSErrorCode) and
its implementations (MemoryVFS, NodeVFS, FsaVFS) into a new standalone
@webnet/vfs package, following the same pattern as the @webnet/transport
split from @webnet/http.

packages/drive now depends on @webnet/vfs and imports directly from it.
packages/test-app likewise imports MemoryVFS and FsaVFS from @webnet/vfs.
The drive package.json export map drops the ./vfs/* sub-exports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 16:20:27 +00:00
codingetandClaude 1e683507e7 docs(agents): PR review instructions, AI_CHANGES.md consolidation
- Add "Reviewing pull requests" section to AGENTS.md: use `tea` (not
  `gh`), validate assumptions with the user in interactive mode, and
  post feedback directly on the PR in autonomous mode.
- Consolidate the AI disclosure out of README.md into a standalone
  AI_CHANGES.md; README.md now links to it.
- Add .gitattributes with merge=union on AI_CHANGES.md so parallel
  branches each appending entries never produce conflicts.
- Update the "AI disclosure" section in AGENTS.md to point agents at
  AI_CHANGES.md instead of README.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 12:06:41 +00:00
codingetandClaude f11eaaa670 style: fix prettier formatting in hooks and Debug component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:38:44 +00:00
codingetandClaude b12c2fe0b1 fix(tsconnect-worker): address round-3 review feedback
Bugs:
- Liveness detection now fires for all clients, including those that connect
  while init is pending. Previously, the "hello" message was consumed by the
  onFirst handler before registerClient set up its port.onmessage listener,
  so navigator.locks.request was never called for the first tab and any tab
  that connected during init. Fix: unified onHello handler in onconnect
  extracts lockName from every "hello"; registerClient always takes lockName
  and acquires the lock immediately.
- Remove dead bodyCallbacks field from bridgeDriveHandler pending map. The
  map was allocated on every request but never read or populated; body chunk
  reads go directly through entry.req.readBodyChunk().
- Drive cleanup in cleanupClient now only installs the no-op handler when no
  other client still has driveRegistered = true, preventing the surviving
  client's handler from being silently replaced.

Code quality:
- wrapDispatch: replace (s as any).dispatch with a two-step cast through
  unknown — avoids the any escape hatch while satisfying RTK's overloaded
  ThunkDispatch type.
- IndexedDBState.setState: add tx.onerror handler so failed IDB writes are
  logged rather than silently dropped.
- pumpStreamToPort fire-and-forget in openWaitingFile fallback: add
  .catch(() => {}) to make the intentional discard explicit.
- tsconfig.json: add skipLibCheck: true to match tsconfig.worker.json (both
  transitively import @webnet/tsconnect which has an unresolved wasm_exec.js
  declaration issue).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:35:52 +00:00
codingetandClaude 720a0c9d59 feat(example-app): SharedWorker demo with main-thread fallback
- Add src/worker.ts as the webpack worker entry (imports @webnet/tsconnect-worker/worker)
- IpnProvider: add useWorker/workerAvailable state; when useWorker is on,
  useBuildIpnWorker() creates the client and its embedded store is passed to
  IpnStoreProvider; when off, existing useBuildIpn() path runs unchanged
- Debug: add "use SharedWorker" checkbox (checked by default when available,
  disabled when not); state dropdown shows indexeddb/memory in worker mode
  and localStorage/sessionStorage/disable in main-thread mode; taildrop
  option label reflects opfs vs memory depending on mode
- useBuildIpnWorker: add optional workerOptions param instead of hardcoding
  { type: "module" } — webpack bundles the worker as a classic script, so
  the caller passes no options; module-mode callers opt in explicitly
- Add @webnet/tsconnect-react, @webnet/tsconnect-redux, @webnet/tsconnect-worker
  to example-app package.json dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:35:07 +00:00
codingetandClaude c65dd00f71 fix(tsconnect-react): narrow useBuildIpnWorker worker arg to string | URL
Accepting a SharedWorker instance was unsafe: in StrictMode, React runs
effects twice in quick succession, and since the connect() promise is
async, clientRef.current is still null when the second effect fires —
so both calls would share the same sw.port, causing two IpnWorkerClient
instances to collide on one MessagePort.

With string | URL, each call to new SharedWorker() fires a fresh connect
event in the worker and returns an independent MessagePort, so the
StrictMode double-invoke is safe: the first connection gets disconnect()ed
when its promise resolves (cleanedUp is true), and the second becomes
the active client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:35:07 +00:00
codingetandClaude 6a6fbc3e5b feat(tsconnect-react): add useBuildIpnWorker hook for SharedWorker clients
- Add disconnect() to IpnWorkerClient (releases Web Lock without shutdown)
- Widen IpnContext from IPN to IpnClient
- Add useBuildIpnWorker(worker, config, runParams) hook with StrictMode-safe
  cleanup: disconnect() fires if the cleanup runs before connect() resolves,
  or immediately after if it resolves first
- Export useBuildIpnWorker from package index
- Add @webnet/tsconnect-worker to package dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:34:14 +00:00
codingetandClaude 1a94620141 fix(tsconnect): move IndexedDBState and use IpnClient in helpers
Place IndexedDBState in the state-storage section alongside
InMemoryState and WebStorageState rather than between the
getIceServers doc comment and its function body.

Change getIceServers to accept IpnClient instead of the raw IPN
interface so callers can pass either IPN or IpnWorkerClient.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:34:14 +00:00
codingetandClaude b4273702db feat(tsconnect-worker): round-2 improvements
- Move IndexedDBState to @webnet/tsconnect/helpers and export from
  package index; remove it from tsconnect-worker/storage.ts
- Add IpnClient interface, IpnSSHTermConfig, and IpnPacketConn to
  @webnet/tsconnect; IPN class and IpnWorkerClient both implement it
- Make IPN.ssh() async to unify the sync/async split
- Add preloadedState parameter to buildIpnStore; worker now sends a
  preloadState message (full Redux state) on connect instead of
  replaying synthetic actions
- WorkerConn implements RawTransport, WorkerTCPListener implements
  RawListener, WorkerPacketConn implements IpnPacketConn
- WorkerSSHSession.resize/close fire-and-forget (sync) to implement
  IPNSSHSession; remove resizeResult/closeResult round-trips
- ReadableStream transfer fallback via MessageChannel sub-protocol for
  Safari compatibility on sendFile and openWaitingFile
- Add stateStorage: "indexeddb" | "memory" option to WorkerConfig
- Export TLSCertKeyPair, WhoIsResponse, PingType, PingResult,
  DNSQueryResult from @webnet/tsconnect package index
- Add @webnet/transport to tsconnect-worker dependencies

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:34:14 +00:00
codingetandClaude 75a841a15d docs(readme): update AI disclosure for tsconnect-worker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:31:20 +00:00
codingetandClaude 5ee74ffc9d feat(tsconnect-worker): add SharedWorker binding for tsconnect
Wraps the IPN and tsconnect-redux store in a SharedWorker, exposing every
IPN method to clients via message-port RPC with per-object MessageChannels
for Conn, TCPListener, PacketConn, drive handler, and SSH sessions.

Key design points:
- IndexedDBState: sync-read/write Map cache with async IDB flush, replacing
  the unavailable localStorage in SharedWorkerGlobalScope
- Redux store on the worker broadcasts every dispatched action to all clients;
  new clients receive a full state snapshot as synthetic actions on connect
- Web Locks API tracks client liveness: when the client's tab closes its lock
  is released and the worker closes all resources that client opened
  (Conn, TCPListener, PacketConn, drive handler)
- Graceful IPN shutdown when the last client leaves
- FsaFileOps (OPFS) available for Taildrop when fileOps: true in config
- Two tsconfigs: DOM lib for client code, WebWorker lib for worker.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 11:30:15 +00:00
codingetandClaude 6b769462a4 docs(readme): update AI disclosure for WebRTC DataChannel transport
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 19:48:57 +00:00