Extracts two sets of utilities from the feat/tailshare branch into their own standalone packages so other apps (and tailshare itself once these land) can consume them without depending on an app package.
@webnet/react
useClient() — returns true on the client, false during SSR; backed by useSyncExternalStore
useLocalStorage(key, defaultValue?) — cross-tab-synchronised localStorage binding; also backed by useSyncExternalStore
Peer dep: react ^19. No other dependencies.
@webnet/utils
download(data, name) — downloads a Uint8Array | Blob | ReadableStream via showSaveFilePicker when available, falling back to an <a> click
upload() — opens a file picker and returns the selected File | null
readBlob(blob, "text" | "bytes") — FileReader wrapper with an overloaded return type
Both packages follow the same build setup as @webnet/tsconnect-react (tsc, "type": "module", single . export).
tailshare will drop its local copies once this PR lands.
Extracts two sets of utilities from the `feat/tailshare` branch into their own standalone packages so other apps (and tailshare itself once these land) can consume them without depending on an app package.
## `@webnet/react`
- `useClient()` — returns `true` on the client, `false` during SSR; backed by `useSyncExternalStore`
- `useLocalStorage(key, defaultValue?)` — cross-tab-synchronised localStorage binding; also backed by `useSyncExternalStore`
Peer dep: `react ^19`. No other dependencies.
## `@webnet/utils`
- `download(data, name)` — downloads a `Uint8Array | Blob | ReadableStream` via `showSaveFilePicker` when available, falling back to an `<a>` click
- `upload()` — opens a file picker and returns the selected `File | null`
- `readBlob(blob, "text" | "bytes")` — `FileReader` wrapper with an overloaded return type
- `fmtSize(n)` — formats byte counts as KiB / MiB / GiB
No dependencies; browser-only (DOM APIs).
## Notes
- Both packages follow the same build setup as `@webnet/tsconnect-react` (`tsc`, `"type": "module"`, single `.` export).
- tailshare will drop its local copies once this PR lands.
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>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Extracts two sets of utilities from the
feat/tailsharebranch into their own standalone packages so other apps (and tailshare itself once these land) can consume them without depending on an app package.@webnet/reactuseClient()— returnstrueon the client,falseduring SSR; backed byuseSyncExternalStoreuseLocalStorage(key, defaultValue?)— cross-tab-synchronised localStorage binding; also backed byuseSyncExternalStorePeer dep:
react ^19. No other dependencies.@webnet/utilsdownload(data, name)— downloads aUint8Array | Blob | ReadableStreamviashowSaveFilePickerwhen available, falling back to an<a>clickupload()— opens a file picker and returns the selectedFile | nullreadBlob(blob, "text" | "bytes")—FileReaderwrapper with an overloaded return typefmtSize(n)— formats byte counts as KiB / MiB / GiBNo dependencies; browser-only (DOM APIs).
Notes
@webnet/tsconnect-react(tsc,"type": "module", single.export).