feat(sdk): add new managerOptions optional param on MessageBoxClient - #490
feat(sdk): add new managerOptions optional param on MessageBoxClient#490kjartan221 wants to merge 3 commits into
Conversation
…age-box-client doc
|
Following up on my own "Open for maintainer input" point 1 above, before this merges — there may be a better Rather than exposing one socket.io field, expose the whole socketOptions?: Omit<AuthSocketClientOptions, 'wallet' | 'originator'>this.socket = AuthSocketClient(targetHost, {
...this.socketOptions,
wallet: this.walletClient,
originator: this.originator
})
That trades one option for full configurability and also makes Happy to push the new shape, or leave this PR as-is if you would rather keep the |
|



feat(message-box-client): forward socket.io manager options to AuthSocketClient
Motivation for this change
MessageBoxClientreaches a server two ways.sendMessage,listMessages, andacknowledgeMessagego over BRC-31 authenticated HTTP viaauthFetch.fetch.initializeConnection,listenForLiveMessages, andsendLiveMessagego oversocket.io via
AuthSocketClient. Only the second path is affected here.initializeConnectionconstructs its socket like this:AuthSocketClientaccepts more than that. Its options includemanagerOptions(socket.io's own
Partial<ManagerOptions & SocketOptions>), which it passesstraight through to
io():MessageBoxClientdoes not forward it, andMessageBoxClientOptionshas nosocket, manager, or transport field — so there is no route from a caller down to
it. Every client therefore gets socket.io's default
transports: ['polling', 'websocket']: establish over Engine.IO HTTPlong-polling, then upgrade to WebSocket.
That default is not universally viable. Whether the polling transport completes
depends on the deployment in front of the socket server — reverse proxies,
ingress rules, and CDN layers vary in how they treat Engine.IO's polling
requests, and socket.io's own documentation recommends
transports: ['websocket']for environments where polling is not carriedcleanly. Today a
MessageBoxClientcaller has no way to express that, regardlessof what they know about the host they are talking to.
This change makes the client host-agnostic on that axis: transport selection
becomes a caller decision, so a
MessageBoxClientworks against any deploymentrunning the AuthSocket backend rather than only those whose fronting
infrastructure happens to suit socket.io's defaults. It is additive, and clients
that pass nothing behave exactly as they do now.
Change
Three source lines of behavior, plus documentation and release metadata.
src/types.ts— new option onMessageBoxClientOptions, typed by borrowing fromthe dependency rather than adding one:
This keeps
socket.io-clientout of@bsv/message-box-client's dependency list(the type arrives through
@bsv/authsocket-client, already a dependency) andmakes the option incapable of drifting from what
AuthSocketClientaccepts.src/MessageBoxClient.ts— stored on aprivate readonlyfield, destructured inthe constructor, and forwarded at the construction site so an unconfigured client
passes no
managerOptionskey at all:Usage:
Backward compatible: the option is optional, omitted by default, and touches only
the socket path. The HTTP methods are untouched.
Open for maintainer input
Two decisions here are deliberate but genuinely open. If you would prefer
either changed, say so and I will add a commit to this PR rather than argue
it.
The name
managerOptionsis up for debate. It mirrorsAuthSocketClientOptions.managerOptionsexactly, so the same name appears atboth layers and greps across them — that was the reasoning. The fair
criticism is that it leaks socket.io vocabulary into an API whose users may
never have heard of an Engine.IO Manager. A narrower
transports?: string[],or a domain-named
socketOptions, would read better to a normal caller at thecost of needing revisiting for the next socket.io knob. Happy to rename.
Placement on the constructor rather than as an
initializeConnectionparameter.
initializeConnectionalready takesoverrideHost, so there isprecedent for the other choice. Reasons we went with the constructor:
initializeConnectionis mostly reached implicitly — fromjoinRoomandlistenForLiveMessages, and viasendLiveMessage. A live-message consumercalls
listenForLiveMessages, notinitializeConnection, so a parameterthere would need threading through three more signatures to be reachable at
all.
overrideHostalready pays that tax.if (this.socket == null). A per-calloption would be silently discarded on every later call.
overrideHosthasthis behavior today: if a socket already exists — even an unauthenticated
one — the construction block is skipped and
overrideHostis ignored.including automatic reconnects, so connection-lifetime scope matches the
layer beneath; a call parameter would advertise per-call granularity it
cannot deliver.
The honest downside, for the record:
managerOptionsis the only option onthe interface that can be entirely inert — pass it, use only the HTTP methods,
and nothing reads it. The JSDoc says so explicitly.
Impact
Affected packages and intended versions (publication occurs only through the
release workflow after approval):
@bsv/message-box-client2.4.02.5.02.4.1 → 2.5.0vianpm version minor --no-git-tag-version. Minor perdocs/about/versioning.md— "MINOR adds backward-compatible behavior or publicAPI" — and per this package's own history, where every
feattook a minor(
2.2.6 → 2.3.0,2.3.0 → 2.4.0) and refactor/lint/fix work took patches.governance/package-release-notes.jsonis updated toreleaseType: "minor"accordingly; its
summarynow covers both this addition and the BRC-29 workalready in the unreleased
2.4.1window, since the note spans2.4.0 → 2.5.0.On the unchecked security box: transport selection does not weaken the BRC-103
mutual authentication
AuthSocketClientperforms, the option is opt-in, and noauth, authorization, or validation path changed. Flagging that it was considered
rather than leaving a bare unchecked box.
Verification
Node
v24.19.0, pnpm10.33.2, run inpackages/messaging/message-box-client:npm testnpm run typecheck(tsc --project tsconfig.typecheck.json)npm run lint(oxlint --deny-warnings)prettier --checkon all six changed filespnpm install --filter '@bsv/message-box-client...'Two tests were added, both against the
@bsv/authsocket-clientmodule boundary —the same technique and the same
{ transports: ['websocket'] }fixture thatauthsocket-client's own suite uses for this call(
expect(mockIo).toHaveBeenCalledWith('https://example.test', managerOptions)):and watched fail against the old behavior, which received only
{originator, wallet}.default transport-negotiation path.
Both were mutation-checked rather than taken on trust:
managerOptions: this.managerOptions)managerOptions: { transports: ['polling'] }Live-socket evidence:
AuthSocketClientwithmanagerOptions: { transports: ['websocket'] }connects and authenticatesagainst a MessageBox deployment running the AuthSocket backend — verified
independently, outside this repo, including with a plain
@bsv/sdkProtoWallet(no funding, no certificates, no wallet-toolbox). This PR's own test suite does
not open a live socket; it proves the option reaches
AuthSocketClient, notthat a given host accepts it. Stated plainly so the coverage is not overread.
Conformance evidence: not applicable — no wire format, encoding,
serialization, or persisted schema changed.
Coverage delta: two added tests over previously uncovered forwarding
behavior; no lines removed from coverage.
Lint/typecheck delta: none — both clean before and after.
Browser/mobile/packed-consumer evidence: not run locally. No runtime target
or export surface changed; the addition is a type-only widening of an existing
options interface plus one object spread.
Performance or bundle-size delta: none expected — no new dependency and no
new runtime import (
AuthSocketClientOptionsisimport typeand erases).I self-reviewed the complete diff for correctness, security,
compatibility, public API, artifacts, dependencies, docs, and operations
All applicable checks are terminal and successful on the exact head; any
scope-based skip is expected and validated by the merge gate
Two open items, stated rather than left to be found
docs/reference/package-api-migrations.mdstill needs regenerating for theversion bump. It could not be regenerated on a Windows workstation:
scripts/package-documentation.mjsbuilds doc links withrelative()fromnode:path, so on win32 it emits backslash paths and rewrites all 31 rows.That output was reverted rather than committed, and the file was deliberately
not hand-edited. This is pre-existing —
node scripts/package-documentation.mjs --checkfails identically against apristine
HEADwith none of these changes present. Onepnpm docs:packagesrun on Linux fixes it; happy for a maintainer to push that onto this PR.
pnpm health:checkand the repo-widelint/format:check/typecheckwere not run locally — only the affected package's checks. (
format:checkreports 31 pre-existing failures in this package on files this PR does not
touch; left alone to keep the diff scoped.)
Security and dependencies
audit results were reviewed
and removal condition — none added
no workflow or lifecycle script touched
No dependency was added:
managerOptionsis typed viaAuthSocketClientOptions['managerOptions']from@bsv/authsocket-client, whichis already a
workspace:^dependency, specifically sosocket.io-clientdid nothave to become a direct dependency of this package.
pnpm installreported thelockfile already up to date. The CodeQL and Sonar boxes are unchecked because
they can only be evidenced on a pushed head.
Dependency evidence
No dependency was added, removed, or re-ranged. This section is completed because
the version bump touches a
package.json, which the dependency-evidence checktreats as a dependency file.
package.jsonchange is the
2.4.1 → 2.5.0version bump required by the additive public APIin this PR; no
dependencies,devDependencies,peerDependencies, orenginesfield was modified.so the resolved runtime, build, and peer graphs are identical to base.
pnpm-lock.yamlis unmodified.pnpm install --filter '@bsv/message-box-client...'reported the lockfilealready up to date, so no duplication was introduced.
unchanged from base; CodeQL analysis runs against the PR head.
npm testin the affected package passes 9 suitesand 214 tests;
npm run typecheckandnpm run lintare both clean.import typeand erases at compile time, adding no runtime import and notransitive dependency.
@bsv/message-box-client2.4.1 → 2.5.0(minor), classified
minoringovernance/package-release-notes.json.Release and operations
2.4.1 → 2.5.0, minor, with thematching
governance/package-release-notes.jsonclassification)library-only change with no infrastructure or image surface
The last box is intentionally unchecked: the package
CHANGELOG.md, the JSDoc,and
governance/package-release-notes.jsonare all updated here, but thegenerated
docs/reference/package-api-migrations.mdis not, for theWindows-generator reason given under the two open items above. It becomes true
once
pnpm docs:packagesruns on Linux.Migration guidance: none required.
managerOptionsis optional and omittedwhen unset, so socket transport negotiation and every HTTP code path behave
exactly as before for existing callers.
Completion evidence
guidance are current or concretely not applicable
being handed to another contributor as "complete" — the two open items
(generated doc regeneration, repo-wide gate) are called out explicitly
above rather than left to be discovered
restriction is assumed