- src/i18n.ts holds the client's own texts (connection lost/restored,
request timeout/lost) in en de es fr it ja nl pl tr uk, exported as
`@blax-software/networking/i18n` and registered through the "blax-i18n"
package.json field, so `blax-i18n build --packages auto` merges them.
- `_t()` treats a translation equal to its key as missing. vue-i18n echoes
missing keys, so users saw "websocket.connectionrestored" instead of the
English fallback.
- Tests: echoed key falls back, real translation is used, the shipped
module covers every `_t()` key in every locale.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
send() waited forever when the server never answered. In apps that awaited
a read during page setup, a dropped response left the old layout on screen
with an empty body until a reload.
- sendTimeout (ms, default 0 = off): reject unanswered sends with
{ message, code: 'timeout' }. The clock starts at the call, so a send
stuck behind the connect or channel subscribe times out too.
- send(event, data, channel, { timeout, progress }): per-call override;
a bare function as 4th argument still means progress. timeout 0 opts out.
- A send that timed out before it was written is dropped from the queue
instead of going out late after a reconnect.
- Protocol events (websocket.*) never time out.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A page's send() queued behind a failing first connect hung forever — the
close handler dropped the ensureConnected() waiter without settling it, and
a throttled connect() was silently skipped, so nothing ever reconnected.
Symptom in apps: sidebar renders, page body stays blank until a reload.
- ensureConnected(): one waiter per outage, resolved by whichever attempt
succeeds next (no longer orphaned by a failed attempt)
- connect(): a call that lands on the reconnect throttle is retried when the
window opens instead of being dropped
- a replaced (connect(true)) or destroy()ed socket's late error/close no
longer wipes the live socket's state or schedules a reconnect
- destroy() cancels a pending auto-reconnect
- new opt-in `rejectOnDisconnect`: a send already written to a socket that
closes rejects with { message, code: 'connection_lost' } instead of
hanging (default off — unchanged behaviour for existing consumers)
- node:test suite (`npm test`) with a scripted fake socket covering each case
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
createWsClient eagerly invoked a function-form `config.url` to print a dev-time
URL-validation warning. For a module-scope singleton built with
`createVueWsClient({ url: () => useRuntimeConfig().public... })`, that called
useRuntimeConfig() at import time — outside any Nuxt context — and threw
"A composable that requires access to the Nuxt instance was called outside of a
plugin, Nuxt hook, Nuxt middleware, or Vue setup function" (regression vs 0.2.x).
Now only STRING urls are validated eagerly; a function url stays lazy and is
resolved in _getUrl() at connect time (as in 0.2.x). Bump 0.3.1.
- AGENTS.md: canonical client reference — factories + the app `ws` singleton, send()
(streaming via the 4th progress arg, no-timeout caveat), listen/listenWhileMounted,
the EventTarget mechanics, the setAppReady() gate, the SSR pattern, and a footgun checklist.
- package.json: add AGENTS.md to files[] so it ships to node_modules in consumer installs.
- README: correct the ApiClient method table — `bearerToken` getter / getBackendUrl() /
setBearer(null) (getBearer/getServerUrl/clearBearer never existed) + accurate verb signatures.