Skip to content

Type the verifyClient callback in the ws library definition - #2225

Open
javache wants to merge 1 commit into
mainfrom
export-D131765444
Open

javache wants to merge 1 commit into
mainfrom
export-D131765444

Conversation

@javache

@javache javache commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Summary:
The ws v7 library definition declared verifyClient as () => unknown, so callers that read the connection info (such as origin) failed to type-check. Type its first argument as the info object ws passes (origin, secure and req), matching the React Native copy of this definition.

Changelog: [Internal]

Differential Revision: D131765444

Summary:
The `ws` v7 library definition declared `verifyClient` as `() => unknown`, so callers that read the connection info (such as `origin`) failed to type-check. Type its first argument as the info object `ws` passes (`origin`, `secure` and `req`), matching the React Native copy of this definition.

Changelog: [Internal]

Differential Revision: D131765444
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 13, 2026
@meta-codesync

meta-codesync Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

@javache has exported this pull request. If you are a Meta employee, you can view the originating Diff in D131765444.

@github-actions

Copy link
Copy Markdown

Metro review: Changes suggested

Risk: low · Commit: 7f43305 · 4 commands run

This PR fills in the type of the verifyClient callback in the ws v7 Flow library definition, which was () => unknown, so callers can read origin, secure and req. It is only a type change and Flow passes. The problem is that origin is typed as string, but ws passes undefined when the client sends no Origin header. An origin check written against this type can therefore throw at runtime even though it type-checks.

Findings

  • should fix · origin is typed as string, but ws passes undefined when the client sends no Origin header — flow-typed/npm/ws_v7.x.x.js:44 · 487658c6
Verified
  • ✅ node repro/origin-repro.js <head worktree> (ws 7.5.10 server, Node ws client) — Prints origin: undefined undefined: ws passes an undefined origin when the client sends no Origin header.
  • ✅ yarn typecheck (head, with repro/__review_verifyClient.js temporarily in packages/metro/src/lib) (failed as expected) — Flow accepts info.origin.startsWith(...) with no error, and reports one error: the two-argument (info, cb) form requires another argument.
  • ✅ yarn typecheck (head, repro file removed) — No errors.
  • ✅ yarn eslint flow-typed/npm/ws_v7.x.x.js — flow-typed is in the ignore pattern, so nothing was linted.

Not run: No benchmark: this is a type-only libdef change with no runtime effect. I didn't compare against React Native's copy of the libdef because that repo isn't checked out. No Jest tests were run, since Flow is the only check this change affects.

Automated review by Claude. Advisory only: it never approves or blocks, and a maintainer makes the call.

verifyClient?: () => unknown,
verifyClient?: (
info: Readonly<{
origin: string,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should fix · origin is typed as string, but ws passes undefined when the client sends no Origin header

ws 7.x builds the info object as origin: req.headers[version === 8 ? 'sec-websocket-origin' : 'origin'] (ws/lib/websocket-server.js:252-257). Browsers always send that header. Node clients, CLI tools, native apps and many proxies often don't, and then info.origin is undefined.

With this libdef, verifyClient: info => info.origin.startsWith('http://localhost') type-checks, but it throws a TypeError inside the server's upgrade handling when such a client connects. The stated motivation is callers that read origin, and an origin allowlist is exactly where a missing-header case matters, so the type should make callers handle it.

Suggested fix: origin?: string (or origin: string | void). React Native's copy of this definition should get the same change.

Optional, since the old () => unknown type also rejected it: ws also supports an async form, (info, cb) => void, selected by verifyClient.length === 2. The new type still rejects it with "requires another argument". If you want it covered, add an optional callback?: (verified: boolean, code?: number, message?: string, headers?: {[string]: string}) => void parameter.

Reproduced: repro/origin-repro.js starts a ws 7.5.10 server with a verifyClient that logs info.origin, then connects with the Node ws client. It prints origin: undefined undefined. repro/__review_verifyClient.js, placed temporarily in packages/metro/src/lib, used info.origin.startsWith(...) and Flow accepted it with no error. The same file's two-argument (info, cb) form failed with incompatible-type, "requires another argument". · id 487658c6

@javache
javache requested review from huntie and robhogan November 13, 2026 13:14
@javache

javache commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported needs-meta-import

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants