itty-sockets 0.5.4-next.0 → 0.5.4-next.1
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/README.md +33 -185
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,204 +18,52 @@
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
## Type-safe WebSocket routing in 540 bytes
|
|
22
|
+
|
|
23
|
+
## Features ✨
|
|
24
|
+
1. **Quality of Life Improvements (over native WebSocket)**
|
|
25
|
+
- auto JSON handling
|
|
26
|
+
- top-level payload access (`text` instead of `e.data.text`)
|
|
27
|
+
- easy reconnections
|
|
28
|
+
- message queuing eliminates race conditions
|
|
29
|
+
- chainable API
|
|
30
|
+
1. **Powerful Routing**
|
|
31
|
+
- all messages - `.on('message', data => console.log(data))`
|
|
32
|
+
- custom types - `.on('chat', ({ text }) => console.log(text))`
|
|
33
|
+
- custom filters - `.on(isOver20, ({ value }) => console.log(value))`
|
|
34
|
+
1. **Type-safety**
|
|
35
|
+
- `.on<Chat>('chat', ({ text }) => console.log(text))`
|
|
36
|
+
- `.send<Chat>({ type: 'chat', text: 'hello' })`
|
|
37
|
+
1. **Works with any JSON-based WebSocket server**
|
|
38
|
+
1. **Tiny footprint** - 540 bytes is smaller than most WebSocket boilerplate
|
|
39
|
+
|
|
40
|
+
## Basic Example
|
|
24
41
|
```ts
|
|
25
|
-
|
|
26
|
-
connect('unique-channel-name')
|
|
27
|
-
// listen for all messages
|
|
28
|
-
.on('message', e => console.log(e.message))
|
|
42
|
+
import { connect } from 'itty-sockets'
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
.on('greeting',
|
|
32
|
-
({ user, text }) => console.log(user, 'says:', text)
|
|
33
|
-
)
|
|
34
|
-
```
|
|
44
|
+
const ws = connect('wss://example.com')
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
ws
|
|
47
|
+
.on('message', e => console.log(e.message))
|
|
48
|
+
.send('hey!')
|
|
39
49
|
.send({ foo: 'bar' })
|
|
40
|
-
.send({ type: 'greeting', user: 'Halsey', text: 'Meow!' })
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
channel.send('what else can this do?')
|
|
44
50
|
```
|
|
45
51
|
|
|
52
|
+
## Installation
|
|
46
53
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- JSON parsing/stringifying
|
|
50
|
-
- message queing - sending automatically connects and queue is flushed on open
|
|
51
|
-
- easy reconnection (listeners keep working)
|
|
52
|
-
- custom listeners/filters
|
|
53
|
-
- chainable syntax (it's just handy)
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
const ws = connect('wss://somewhere.else')
|
|
57
|
-
.on('message', console.log) // log all messages
|
|
58
|
-
.send({ foo: 'bar' }) // send immediately, no waiting
|
|
59
|
-
|
|
60
|
-
// optional - reconnect every second (no effect if open)
|
|
61
|
-
setInterval(ws.open, 1000)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
<br />
|
|
65
|
-
|
|
66
|
-
# Getting Started
|
|
67
|
-
|
|
68
|
-
### 1. Import the [tiny client](https://npmjs.com/package/itty-sockets).
|
|
54
|
+
**Option 1: Import**
|
|
69
55
|
```ts
|
|
70
56
|
import { connect } from 'itty-sockets'
|
|
71
57
|
```
|
|
72
58
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
let connect=(e,s={})=>{let p,a=0,n=[],t=[],o={},l=()=>(p||(p=new WebSocket((/^wss?:/.test(e)?e:"wss://c.itty.ws/"+e)+"?"+new URLSearchParams(s)),p.onmessage=(e,s=JSON.parse(e.data),p=s?.message,a={...null==p?.[0]&&p,...s})=>{o[s?.type??p?.type]?.map((e=>e(a))),s?.type||o.message?.map((e=>e(a))),t.map((([e,s])=>e(a)&&s(a)))},p.onopen=()=>(n.splice(0).map((e=>p?.send(e))),o.open?.map((e=>e())),a&&p?.close()),p.onclose=()=>(a=0,p=null,o.close?.map((e=>e())))),m),m=new Proxy(l,{get:(e,s)=>({open:l,close:()=>(1==p?.readyState?p.close():a=1,m),push:(e,s)=>(a=1,m.send(e,s)),send:(e,s)=>(e=JSON.stringify(e),e=s?""+s+""+e:e,1==p?.readyState?(p.send(e),m):(n.push(e),l())),on:(e,s)=>(s&&(e?.[0]?(o[e]??=[]).push(s):t.push([e,s])),l()),remove:(e,s,p=o[e],a=p?.indexOf(s)??-1)=>(~a&&p?.splice(a,1),l())}[s])});return m};
|
|
77
|
-
```
|
|
78
|
-
<!-- END SNIPPET -->
|
|
79
|
-
|
|
80
|
-
<br />
|
|
81
|
-
|
|
82
|
-
### 2. Connect to a Channel (or external server)
|
|
83
|
-
To start, simply connect to a channel based on a unique name (this can be anything).
|
|
84
|
-
|
|
85
|
-
> **NOTE:** Pass a valid `ws://` or `wss://` URL as the channel identifier to bypass the public [ittysockets.io](https://ittysockets.io) service and use your own.
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
import { connect } from 'itty-sockets'
|
|
89
|
-
|
|
90
|
-
// basic connection
|
|
91
|
-
const channel = connect('my-super-secret-channel')
|
|
92
|
-
|
|
93
|
-
// with options
|
|
94
|
-
const channel = connect('my-super-secret-channel', {
|
|
95
|
-
alias: 'Kevin', // optional non-unique identifier, visible in messages
|
|
96
|
-
announce: true, // shares your uid/alias with the channel on joining
|
|
97
|
-
echo: true // echos your own messages back to you (for testing)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
// or any external JSON WebSocket server
|
|
101
|
-
const channel = connect('wss://somewhere.else.entirely')
|
|
59
|
+
**Option 2: Just copy this snippet:**
|
|
60
|
+
```js
|
|
61
|
+
let connect=(e,s={})=>{let p,t=0,a=[],n=[],o={},l=()=>(p||(p=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),p.onmessage=(e,s=JSON.parse(e.data),p=s?.message,t={...null==p?.[0]&&p,...s})=>{o[s?.type??p?.type]?.map((e=>e(t))),s?.type||o.message?.map((e=>e(t))),n.map((([e,s])=>e(t)&&s(t)))},p.onopen=()=>(a.splice(0).map((e=>p?.send(e))),o.open?.map((e=>e())),t&&p?.close()),p.onclose=()=>(t=0,p=null,o.close?.map((e=>e())))),c),c=new Proxy(l,{get:(e,s)=>({open:l,close:()=>(1==p?.readyState?p.close():t=1,c),push:(e,s)=>(t=1,c.send(e,s)),send:(e,s)=>(e=JSON.stringify(e),e=s?""+s+""+e:e,1==p?.readyState?(p.send(e),c):(a.push(e),l())),on:(e,s)=>(s&&(e?.[0]?(o[e]??=[]).push(s):n.push([e,s])),l()),remove:(e,s,p=o[e],t=p?.indexOf(s)??-1)=>(~t&&p?.splice(t,1),l())}[s])});return c};
|
|
102
62
|
```
|
|
63
|
+
Note: This will lose TypeScript support, but is great for adding to your browser console (via script extensions, etc).
|
|
103
64
|
|
|
104
|
-
#### Connection Options
|
|
105
|
-
|
|
106
|
-
| option | default value | description |
|
|
107
|
-
| --- | --- | --- |
|
|
108
|
-
| `{ alias: 'any-string' }` | `undefined` | An optional display name to be included in your messages. |
|
|
109
|
-
| `{ as: 'any-string' }` | `undefined` | An optional display name to be included in your message (same as alias). |
|
|
110
|
-
| `{ announce: true }` | `false` | Shares your uid/alias when joining/leaving. |
|
|
111
|
-
| `{ echo: true }` | `false` | Echos messages back to original sender (good for testing). |
|
|
112
|
-
|
|
113
|
-
<br />
|
|
114
|
-
|
|
115
|
-
### 3. Use the channel.
|
|
116
|
-
With the channel connected, simply call methods on it. Every method is chainable, returning the connection again (for more chaining).
|
|
117
|
-
|
|
118
|
-
| method | description | example |
|
|
119
|
-
| --- | --- | --- |
|
|
120
|
-
| **`.open()`** | Opens/re-opens the connection (manually, usually not needed). |
|
|
121
|
-
| **`.close()`** | Closes the connection. | `channel.close()` |
|
|
122
|
-
| **`.send(message: any)`** | Sends a message to the channel. This can be anything serializable with JSON.stringify. | `channel.send({ type: 'chat', text: 'hello' })` |
|
|
123
|
-
| **`.push(message: any)`** | Sends a message and immediately closes the connection. | `channel.push('Hello World!')` |
|
|
124
|
-
| **`.on(eventName: string, listener)`** | Add an event listener. | `channel.on('close', () => console.log('channel closed'))` |
|
|
125
|
-
| **`.remove(eventName: string, listener)`** | Remove an event listener. The 2nd argument must be the same listener function registered in the `on` method. | `channel.remove('open', myListenerFunction)` |
|
|
126
|
-
|
|
127
|
-
#### Example
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
|
|
131
|
-
// connect
|
|
132
|
-
const channel = connect('my-secret-channel')
|
|
133
|
-
|
|
134
|
-
// add event listeners or send messages
|
|
135
|
-
|
|
136
|
-
channel
|
|
137
|
-
.on('message', ({ alias, uid, message, date }) =>
|
|
138
|
-
console.log(`${alias ?? uid} says: ${message} @ ${date.toLocaleTimeString()}`)
|
|
139
|
-
)
|
|
140
|
-
.on('join', ({ users }) =>
|
|
141
|
-
console.log(`A user has joined. There are now ${users} in the channel.`)
|
|
142
|
-
)
|
|
143
|
-
.on('leave', ({ users }) =>
|
|
144
|
-
console.log(`A user has left. There are now ${users} in the channel.`)
|
|
145
|
-
)
|
|
146
|
-
.send('Hello World!') // this will queue up and send the message once connected
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
<br />
|
|
150
|
-
|
|
151
|
-
# Events
|
|
152
|
-
Each event can have multiple listeners registered on it. These are stable, even if the underlying WebSocket is broken/re-established.
|
|
153
|
-
| event name | description | payload | example |
|
|
154
|
-
| --- | --- | --- | --- |
|
|
155
|
-
| `message` | Triggered when receiving a message event. | [MessageEvent](#messageevent) | `channel.on<MessageType = any>('message', listener)` |
|
|
156
|
-
| `join` | Triggered when a user (including self) joins the channel. This alerts all users that someone has joined, and informs them of the total number of users in the channel. If the joining party connected with { announce: true }, their user details will be shared with the channel. | [JoinEvent](#joineevent) | `channel.on('join', e => console.log('There are now', e.users, 'users in the channel.')` |
|
|
157
|
-
| `leave` | Triggered when a user leaves the channel. This alerts all users that someone has left, and informs them of the total number of users in the channel. If the leaving party connected with { announce: true }, their user details will be shared with the channel. | [LeaveEvent](#leaveeevent) | `channel.on('leave', e => console.log('There are now', e.users, 'users in the channel.')` |
|
|
158
|
-
| `error` | Triggered when the server sends an error to the user. This is rare. | [ErrorEvent](#error) | `channel.on('error', e => console.error('IttySockets Error:', e.message)` |
|
|
159
|
-
| `open` | Triggered when the connection is established. | none | `channel.on('open', () => console.log('connected to channel.')` |
|
|
160
|
-
| `close` | Triggered when the connection is closed. | none | `channel.on('close', () => console.log('disconnected from channel.')` |
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<br />
|
|
164
|
-
|
|
165
|
-
## EventTypes
|
|
166
|
-
All event types *other* than `message` are identified with a `type` attribute. For the sake of smaller payloads, `type` is omitted on normal messages.
|
|
167
|
-
|
|
168
|
-
#### MessageEvent
|
|
169
|
-
```ts
|
|
170
|
-
type MessageEvent = {
|
|
171
|
-
id: string // unique message ID
|
|
172
|
-
uid: string // unique user ID
|
|
173
|
-
alias: string? // optional display name
|
|
174
|
-
date: Date // JavaScript Date object
|
|
175
|
-
message: any // the message payload
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
#### JoinEvent <a id="joinevent" />
|
|
180
|
-
```ts
|
|
181
|
-
type JoinEvent = {
|
|
182
|
-
type: 'join' // type of event
|
|
183
|
-
uid?: string // uid of joiner if { announce: true }
|
|
184
|
-
alias: string? // alias of joiner if { announce: true }
|
|
185
|
-
date: Date // date of event
|
|
186
|
-
users: number // new number of users in the channel
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
#### LeaveEvent
|
|
191
|
-
```ts
|
|
192
|
-
type LeaveEvent = {
|
|
193
|
-
type: 'leave' // type of event
|
|
194
|
-
uid?: string // uid of leaver if { announce: true }
|
|
195
|
-
alias: string? // alias of leaver if { announce: true }
|
|
196
|
-
date: Date // date of event
|
|
197
|
-
users: number // new number of users in the channel
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
#### ErrorEvent
|
|
202
|
-
```ts
|
|
203
|
-
type MessageEvent = {
|
|
204
|
-
type: 'error' // error event identifier
|
|
205
|
-
date: Date // JavaScript Date object
|
|
206
|
-
message: any // the message payload
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
<br />
|
|
211
|
-
|
|
212
|
-
# Privacy
|
|
213
|
-
[ittysockets.io](https://ittysockets.io) is a free, public-use, but _private_ service.
|
|
214
|
-
|
|
215
|
-
It was designed by me (a developer), to help myself and other developers achieve cool things. As such:
|
|
216
|
-
|
|
217
|
-
1. Your messages are never transmitted to anything other than the sockets on the channel you're connected to. No third-party service, no loggers, no storage (local or otherwise), not even a collection in memory. This protects your privacy/data, but keeps my costs to virtually zero, allowing me to share this service with the world... hopefully indefinitely.
|
|
218
65
|
|
|
219
|
-
|
|
66
|
+
## Next Steps
|
|
220
67
|
|
|
68
|
+
- [Getting Started](https://itty.dev/itty-sockets/getting-started) - Basic setup and first connections
|
|
221
69
|
|