wscall-client 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/package.json +58 -0
- package/src/client.js +874 -0
- package/src/index.js +50 -0
- package/src/protocol.js +548 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hinsir-zxc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# wscall-client
|
|
2
|
+
|
|
3
|
+
High-performance JavaScript client SDK for the [WSCALL](https://github.com/Hinsir-zxc/wscall) WebSocket RPC framework.
|
|
4
|
+
|
|
5
|
+
Works in both **Node.js** (≥18) and modern **browsers** (native WebSocket + Web Crypto).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Protocol v3 binary codec** — compact 5-byte frame header, single-letter JSON keys, raw binary attachments (zero Base64 overhead).
|
|
10
|
+
- **Encryption** — ChaCha20-Poly1305 and AES-256-GCM at frame level; no TLS required.
|
|
11
|
+
- **ECDH key agreement** — X25519 dynamic per-connection session key (forward secrecy), no pre-shared key needed.
|
|
12
|
+
- **Bidirectional messaging** — request/response RPC + server-pushed events with ACK correlation.
|
|
13
|
+
- **Automatic reconnect** — exponential backoff with jitter; sticky failover across multiple server URLs.
|
|
14
|
+
- **Zero-copy attachments** — send and receive binary files inline with RPC params or event data.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install wscall-client
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For Node.js environments you also need a WebSocket implementation:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install ws
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Browsers provide `WebSocket` natively — no extra dependency.
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### ECDH mode (recommended — no pre-shared key)
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { WscallClient, WscallClientConfig } from 'wscall-client';
|
|
36
|
+
|
|
37
|
+
const client = await WscallClient.connect(
|
|
38
|
+
'ws://127.0.0.1:9001/socket',
|
|
39
|
+
WscallClientConfig.ecdh()
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// RPC call
|
|
43
|
+
const res = await client.call('system.echo', { message: 'hello' });
|
|
44
|
+
console.log(res.data); // { message: 'hello' }
|
|
45
|
+
|
|
46
|
+
// Subscribe to server events
|
|
47
|
+
client.onEvent('chat.message', (event) => {
|
|
48
|
+
console.log('New message:', event.data);
|
|
49
|
+
return { received: true }; // sent back as ACK receipt
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Emit an event (with ACK)
|
|
53
|
+
const ack = await client.sendEvent('chat.message', { text: 'hi!' });
|
|
54
|
+
console.log('Server acknowledged:', ack.receipt);
|
|
55
|
+
|
|
56
|
+
client.close();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### PSK mode (pre-shared key)
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { WscallClient, WscallClientConfig } from 'wscall-client';
|
|
63
|
+
|
|
64
|
+
const key = new Uint8Array(32).fill(0x42); // 32-byte shared key
|
|
65
|
+
|
|
66
|
+
const config = WscallClientConfig.pskChaCha20(key);
|
|
67
|
+
const client = await WscallClient.connect('ws://127.0.0.1:9001/socket', config);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Failover across multiple servers
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
const config = WscallClientConfig.ecdh()
|
|
74
|
+
.withFailoverUrl('ws://backup1:9001/socket')
|
|
75
|
+
.withFailoverUrl('ws://backup2:9001/socket');
|
|
76
|
+
|
|
77
|
+
const client = await WscallClient.connect('ws://primary:9001/socket', config);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
On disconnect the client iterates through `[primary, ...failover]` starting from the last successfully connected URL (sticky failover).
|
|
81
|
+
|
|
82
|
+
### File attachments
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
import { createTextAttachment, attachmentRef } from 'wscall-client';
|
|
86
|
+
|
|
87
|
+
const att = createTextAttachment('f1', 'hello.txt', 'text/plain', 'Hello, world!');
|
|
88
|
+
|
|
89
|
+
const res = await client.call(
|
|
90
|
+
'files.inspect',
|
|
91
|
+
{ file: attachmentRef('f1') },
|
|
92
|
+
[att]
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API Overview
|
|
97
|
+
|
|
98
|
+
### `WscallClient.connect(url, config?) → Promise<WscallClient>`
|
|
99
|
+
|
|
100
|
+
Static factory. Connects to a WSCALL server and returns a ready client.
|
|
101
|
+
|
|
102
|
+
### `WscallClientConfig`
|
|
103
|
+
|
|
104
|
+
| Factory / Builder | Description |
|
|
105
|
+
|-------------------|-------------|
|
|
106
|
+
| `WscallClientConfig.ecdh()` | ECDH + ChaCha20 + auto-reconnect (default) |
|
|
107
|
+
| `WscallClientConfig.plaintext()` | No encryption |
|
|
108
|
+
| `WscallClientConfig.pskChaCha20(key)` | PSK with ChaCha20-Poly1305 |
|
|
109
|
+
| `WscallClientConfig.pskAes256(key)` | PSK with AES-256-GCM |
|
|
110
|
+
| `.withAutoReconnect(bool)` | Enable/disable auto-reconnect |
|
|
111
|
+
| `.withTimeout(ms)` | Default request timeout |
|
|
112
|
+
| `.withMetadata(obj)` | Default metadata sent with requests |
|
|
113
|
+
| `.withFailoverUrl(url)` | Append a failover URL |
|
|
114
|
+
| `.withFailoverUrls(urls)` | Set all failover URLs |
|
|
115
|
+
|
|
116
|
+
### `client`
|
|
117
|
+
|
|
118
|
+
| Method | Description |
|
|
119
|
+
|--------|-------------|
|
|
120
|
+
| `call(route, params?, attachments?, opts?)` | RPC call → `Promise<ApiResponse>` |
|
|
121
|
+
| `sendEvent(name, data?, attachments?, opts?)` | Emit event → `Promise<EventAck>` |
|
|
122
|
+
| `onEvent(name, handler)` | Subscribe to server events |
|
|
123
|
+
| `offEvent(name, handler?)` | Unsubscribe |
|
|
124
|
+
| `onConnected(handler)` | Connection established hook |
|
|
125
|
+
| `onDisconnected(handler)` | Disconnection hook |
|
|
126
|
+
| `close()` | Graceful shutdown (stops reconnect) |
|
|
127
|
+
|
|
128
|
+
### Reconnect behavior
|
|
129
|
+
|
|
130
|
+
1. Unexpected disconnects trigger automatic reconnect (default: enabled).
|
|
131
|
+
2. First retry after 3 s, then exponential backoff (×2), capped at 30 s.
|
|
132
|
+
3. Random sub-second jitter prevents thundering-herd storms.
|
|
133
|
+
4. With `failoverUrls`, each cycle tries all URLs before applying backoff.
|
|
134
|
+
5. `close()` stops all reconnect attempts.
|
|
135
|
+
|
|
136
|
+
## Protocol Compatibility
|
|
137
|
+
|
|
138
|
+
This SDK implements **WSCALL Protocol v3** (5-byte frame header, connection-level encryption). It requires a server running `wscall` ≥ 0.5.1.
|
|
139
|
+
|
|
140
|
+
| SDK version | Protocol | Server compatibility |
|
|
141
|
+
|-------------|----------|---------------------|
|
|
142
|
+
| 0.3.x | v3 | wscall ≥ 0.5.1 |
|
|
143
|
+
| 0.2.x | v2 | wscall 0.4.x – 0.5.0 |
|
|
144
|
+
|
|
145
|
+
## Browser Usage
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<script type="module">
|
|
149
|
+
import { WscallClient, WscallClientConfig } from './node_modules/wscall-client/src/index.js';
|
|
150
|
+
|
|
151
|
+
const client = await WscallClient.connect('ws://localhost:9001/socket', WscallClientConfig.ecdh());
|
|
152
|
+
const res = await client.call('system.echo', { msg: 'from browser' });
|
|
153
|
+
console.log(res.data);
|
|
154
|
+
</script>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
In browsers the `ws` package is not needed — the native `WebSocket` global is used automatically.
|
|
158
|
+
|
|
159
|
+
## Dependencies
|
|
160
|
+
|
|
161
|
+
| Package | Purpose |
|
|
162
|
+
|---------|---------|
|
|
163
|
+
| `@noble/ciphers` | ChaCha20-Poly1305 AEAD (pure JS, audited) |
|
|
164
|
+
| `@noble/curves` | X25519 ECDH key agreement (pure JS, audited) |
|
|
165
|
+
| `ws` *(optional peer)* | WebSocket implementation for Node.js |
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wscall-client",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "High-performance JavaScript client SDK for the WSCALL WebSocket RPC framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src/",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"demo": "node demo/demo.js",
|
|
16
|
+
"test": "node --test test/"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"websocket",
|
|
20
|
+
"rpc",
|
|
21
|
+
"wscall",
|
|
22
|
+
"binary-protocol",
|
|
23
|
+
"realtime",
|
|
24
|
+
"chacha20",
|
|
25
|
+
"aes-gcm",
|
|
26
|
+
"ecdh",
|
|
27
|
+
"x25519",
|
|
28
|
+
"event-driven"
|
|
29
|
+
],
|
|
30
|
+
"author": "Hinsir-zxc",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/Hinsir-zxc/wscall-client-js.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/Hinsir-zxc/wscall-client-js#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/Hinsir-zxc/wscall-client-js/issues"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@noble/ciphers": "^1.2.1",
|
|
45
|
+
"@noble/curves": "^1.6.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"ws": ">=8.0.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"ws": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"ws": "^8.21.1"
|
|
57
|
+
}
|
|
58
|
+
}
|