サンプル
ws 8.21.3: Distinguish ws package EventEmitter API and Buffer payloads from native WHATWG EventTarget WebSocket and string payloads in Node
検証済みサンプル — npm ws 8.21.3: Distinguish ws package EventEmitter API and Buffer payloads from native WHATWG EventTarget WebSocket and string payloads in Node.…
sha256:1a1d36a350a9eb2dcd345ed3b5163cee5cc2ec75783de4b1c90f8d313b012ee7
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 3
- ビルドした署名鍵
- 3
宣言された環境
node linux x64 node node npm
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:ac1544ece1e22594 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-14 |
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-07 |
ケース
HOW- ゴール
- Distinguish ws package EventEmitter API and Buffer payloads from native WHATWG EventTarget WebSocket and string payloads in Node
- パッケージ
- シンボル
-
- WebSocket
- WebSocket.prototype.on
- WebSocket.prototype.ping
- WebSocket.prototype.binaryType
- WebSocketServer
- 環境
- node
- 作成日
- 2026-08-14T22:43:45Z
コントラクト
- assert ws inherits from EventEmitter with .on() and .ping() while native WebSocket is an EventTarget without .on() or .ping()
- assert WebSocketServer exists in ws but not on globalThis
- assert ws defaults binaryType to nodebuffer while native WebSocket defaults to blob and rejects nodebuffer
- assert ws .on('message') yields a Buffer directly (data.data is undefined) while native onmessage yields MessageEvent with string event.data
- assert ws .on('close') yields Buffer reason while native onclose yields string event.reason
ファイル
- NOTES.md
- csx.json
- package-lock.json
- package.json
- test/contract.mjs
ソース
A naive model assumes `ws` and native `WebSocket` share the same API, writing `socket.on('message', (event) => process(event.data))` or calling `socket.ping()` on native instances.
This fails loudly with `TypeError: socket.on is not a function` on native `WebSocket`, or fails silently in `ws` where `event.data` evaluates to `undefined` because `data` is passed directly as a `Buffer`.
{"case":{"caseId":"case:sha256:34f392705de3fb799e763847855644ef9f32f03bf99bda08eb93e12aceb03d62","constraints":{"runtime":"node"},"contract":["assert ws inherits from EventEmitter with .on() and .ping() while native WebSocket is an EventTarget without .on() or .ping()","assert WebSocketServer exists in ws but not on globalThis","assert ws defaults binaryType to nodebuffer while native WebSocket defaults to blob and rejects nodebuffer","assert ws .on('message') yields a Buffer directly (data.data is undefined) while native onmessage yields MessageEvent with string event.data","assert ws .on('close') yields Buffer reason while native onclose yields string event.reason"],"goal":"Distinguish ws package EventEmitter API and Buffer payloads from native WHATWG EventTarget WebSocket and string payloads in Node","kind":"HOW","packages":["pkg:npm/ws@8.21.3"],"schemaVersion":1,"symbols":["WebSocket","WebSocket.prototype.on","WebSocket.prototype.ping","WebSocket.prototype.binaryType","WebSocketServer"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/ws@8.21.3"],"schemaVersion":1,"symbols":["WebSocket","WebSocket.prototype.on","WebSocket.prototype.ping","WebSocket.prototype.binaryType","WebSocketServer"],"verifierAdapter":"node-typescript@1"}
{
"name": "sample",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sample",
"version": "1.0.0",
"dependencies": {
"ws": "8.21.3"
}
},
"node_modules/ws": {
"version": "8.21.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
"integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}
{
"name": "sample",
"version": "1.0.0",
"type": "module",
"scripts": {
"test": "node test/contract.mjs"
},
"dependencies": {
"ws": "8.21.3"
}
}
import assert from 'node:assert/strict';
import { EventEmitter } from 'node:events';
import http from 'node:http';
import ws, { WebSocket, WebSocketServer } from 'ws';
// --- 1. Prototype & Class API Disagreements ---
// ws WebSocket inherits from EventEmitter; globalThis.WebSocket inherits from EventTarget
assert.equal(WebSocket.prototype instanceof EventEmitter, true);
assert.equal(typeof WebSocket.prototype.on, 'function');
assert.equal(typeof WebSocket.prototype.ping, 'function');
assert.equal(globalThis.WebSocket.prototype instanceof EventEmitter, false);
assert.equal(globalThis.WebSocket.prototype instanceof EventTarget, true);
assert.equal(typeof globalThis.WebSocket.prototype.on, 'undefined');
assert.equal(typeof globalThis.WebSocket.prototype.ping, 'undefined');
// WebSocketServer exists on the ws package, but not as a global
assert.equal(typeof WebSocketServer, 'function');
assert.equal(typeof globalThis.WebSocketServer, 'undefined');
// --- 2. Default binaryType Disagreements ---
const dummyWs = new WebSocket('ws://127.0.0.1:1');
dummyWs.on('error', () => {});
assert.equal(dummyWs.binaryType, 'nodebuffer');
dummyWs.close();
const dummyNative = new globalThis.WebSocket('ws://127.0.0.1:1');
dummyNative.onerror = () => {};
assert.equal(dummyNative.binaryType, 'blob');
// WHATWG specification ignores 'nodebuffer'; binaryType remains 'blob'
dummyNative.binaryType = 'nodebuffer';
assert.equal(dummyNative.binaryType, 'blob');
dummyNative.close();
// --- 3. Runtime Event Signature & Payload Disagreements ---
const server = http.createServer();
const wss = new WebSocketServer({ server });
wss.on('connection', (socket) => {
socket.on('message', (data) => {
socket.send('ack:' + data.toString());
socket.close(1000, 'server_closed');
});
});
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
const port = server.address().port;
const url = `ws://127.0.0.1:${port}`;
// ws client: .on('message') delivers Buffer directly; .on('close') delivers Buffer reason
await new Promise((resolve, reject) => {
const client = new WebSocket(url);
client.on('error', reject);
client.on('open', () => client.send('hello_ws'));
client.on('message', (data, isBinary) => {
// ws delivers (data: Buffer, isBinary: boolean); data.data is undefined
assert.equal(Buffer.isBuffer(data), true);
assert.equal(data.data, undefined);
assert.equal(isBinary, false);
assert.equal(data.toString('utf8'), 'ack:hello_ws');
});
client.on('close', (code, reason) => {
// ws delivers reason as a Buffer, NOT a string
assert.equal(code, 1000);
assert.equal(Buffer.isBuffer(reason), true);
assert.notEqual(typeof reason, 'string');
assert.equal(reason.toString('utf8'), 'server_closed');
resolve();
});
});
// native WebSocket client: onmessage receives MessageEvent; onclose receives CloseEvent
await new Promise((resolve, reject) => {
const nativeClient = new globalThis.WebSocket(url);
nativeClient.onerror = reject;
nativeClient.onopen = () => nativeClient.send('hello_native');
nativeClient.onmessage = (event) => {
// native delivers MessageEvent; payload is at event.data as string
assert.equal(Buffer.isBuffer(event), false);
assert.equal(typeof event.data, 'string');
assert.equal(event.data, 'ack:hello_native');
};
nativeClient.onclose = (event) => {
// native event.reason is a primitive string, NOT a Buffer
assert.equal(event.code, 1000);
assert.equal(typeof event.reason, 'string');
assert.equal(Buffer.isBuffer(event.reason), false);
assert.equal(event.reason, 'server_closed');
resolve();
};
});
await new Promise((resolve) => server.close(resolve));