itty-sockets 0.8.1 → 0.9.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/README.md +40 -102
- package/connect.d.ts +21 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,125 +14,63 @@
|
|
|
14
14
|
[](https://github.com/kwhitley/itty-sockets/issues)
|
|
15
15
|
[](https://discord.gg/53vyrZAu9u)
|
|
16
16
|
|
|
17
|
-
### [Documentation](https://itty.
|
|
17
|
+
### [Full Documentation](https://itty.ws/docs) | [Discord](https://discord.gg/53vyrZAu9u)
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
# Zero-Config WebSockets.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
No accounts, no API keys, nothing to deploy. Just connect and start sending.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
**~466 bytes** min+gzip • **$0/month** • **Free forever**
|
|
26
26
|
|
|
27
|
-
## Features
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
## Features
|
|
28
|
+
- **Zero Configuration** - No accounts, no API keys, no server. Pick a channel name and you're live.
|
|
29
|
+
- **Zero Cost** - No tiers. No credit card. Built for the community.
|
|
30
|
+
- **Private by Default** - No logging, no tracking, no storage. Messages are relayed and forgotten.
|
|
31
|
+
- **Send Anything** - Strings, objects, arrays — anything JSON-serializable.
|
|
32
|
+
- **Access Control** - [Reserve a namespace](https://ittysockets.com/reservations) to control who can join or send on your channels.
|
|
33
|
+
- **Use Anywhere** - No vendor lock. This client works with *any* WebSocket server. Want to host your own? No problem.
|
|
34
|
+
- **Tiny Client** - Only 466 bytes gzipped.
|
|
34
35
|
|
|
35
|
-
##
|
|
36
|
+
## Quick Start
|
|
36
37
|
```ts
|
|
37
|
-
import { connect } from 'itty-sockets'
|
|
38
|
-
|
|
39
|
-
// connect to the channel
|
|
40
|
-
const channel = connect('wss://example.com')
|
|
41
|
-
|
|
42
|
-
channel
|
|
43
|
-
// log all messages
|
|
44
|
-
.on('message', e => console.log(e.message))
|
|
45
|
-
|
|
46
|
-
// send some messages
|
|
47
|
-
.send('hey!')
|
|
48
|
-
.send({ foo: 'bar' })
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Optional use with `itty.ws` public, privacy-first server
|
|
52
|
-
`itty-sockets` has been designed to work with the public [itty.ws](https://itty.ws) service for even easier integrations. With this path, it's possible to add realtime features without hosting a backend server at all. We recommend using this for testing, prototyping, or simple projects. As your needs expand, you can always replace [itty.ws](https://itty.ws) with your own server(s) - nothing in the client changes.
|
|
53
|
-
|
|
54
|
-
Using [itty.ws](https://itty.ws) channels provides a few features to the client (fully typed by passing the `UseItty` generic to `connect`):
|
|
38
|
+
import { connect } from 'itty-sockets' // ~466 bytes
|
|
55
39
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
1
|
|
60
|
-
|
|
61
|
-
## Installation
|
|
62
|
-
|
|
63
|
-
**Option 1: Import**
|
|
64
|
-
```bash
|
|
65
|
-
npm install itty-sockets
|
|
40
|
+
connect('my-channel')
|
|
41
|
+
.on('message', ({ message }) => console.log(message))
|
|
42
|
+
.send('hello world') // strings
|
|
43
|
+
.send([1, 2, 3]) // arrays
|
|
44
|
+
.send({ foo: 'bar' }) // objects
|
|
66
45
|
```
|
|
67
46
|
|
|
47
|
+
## Chat Example
|
|
68
48
|
```ts
|
|
69
49
|
import { connect } from 'itty-sockets'
|
|
70
|
-
```
|
|
71
50
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
let connect=(e,s={})=>{let a,t,n=[],p={},o=()=>(a||(a=new WebSocket((/^wss?:/.test(e)?e:"wss://itty.ws/c/"+e)+"?"+new URLSearchParams(s)),a.onmessage=(e,s=JSON.parse(e.data),a=s?.message,t={...null==a?.[0]&&a,...s})=>[t.type,s.type?0:"message","*"].map(e=>p[e]?.map(e=>e(t))),a.onopen=()=>(n.splice(0).map(e=>a.send(e)),p.open?.map(e=>e(t)),t&&a?.close()),a.onclose=()=>(t=a=null,p.close?.map(e=>e(t)))),l),l={open:o,send:(e,s)=>(e=(s?`${s}`:"")+JSON.stringify(e),1&a?.readyState?a.send(e):n.push(e),o()),on:(e,s)=>((p[e?.[0]?e:"*"]??=[]).push(e?.[0]?s:a=>e?.(a)&&s(a)),o()),remove:(e,s)=>(p[e]=p[e]?.filter(e=>e!=s),l),close:()=>(1&a?.readyState?a.close():t=1,l),push:(e,s)=>(t=1,l.send(e,s))};return l};
|
|
76
|
-
```
|
|
77
|
-
<!-- END SNIPPET -->
|
|
78
|
-
*Note: This will lose TypeScript support.*
|
|
51
|
+
// two users, same channel
|
|
52
|
+
const alice = connect('chat-room', { as: 'Alice' })
|
|
53
|
+
const bob = connect('chat-room', { as: 'Bob' })
|
|
79
54
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
import { connect } from 'itty-sockets'
|
|
55
|
+
alice.on('message', ({ message, alias }) =>
|
|
56
|
+
console.log(`${alias}: ${message}`)
|
|
57
|
+
)
|
|
84
58
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// listen for every message
|
|
88
|
-
.on('message', console.log)
|
|
89
|
-
|
|
90
|
-
// and just { type: 'chat' }
|
|
91
|
-
.on('chat',
|
|
92
|
-
({ user, text }) => console.log(`${user} says: ${text}`)
|
|
93
|
-
)
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Now let's assume the following 2 messages are sent:
|
|
97
|
-
```json
|
|
98
|
-
// message 1
|
|
99
|
-
{
|
|
100
|
-
"type": "chat",
|
|
101
|
-
"user": "Kevin",
|
|
102
|
-
"text": "Hey!"
|
|
103
|
-
}
|
|
59
|
+
bob.send('hey Alice!')
|
|
60
|
+
// → "Bob: hey Alice!"
|
|
104
61
|
```
|
|
105
62
|
|
|
106
|
-
|
|
107
|
-
// message 2
|
|
108
|
-
{
|
|
109
|
-
"date": 1754659171196,
|
|
110
|
-
"items": [1, 2, 3],
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
This will output the following to the console:
|
|
115
|
-
```js
|
|
116
|
-
// message 1
|
|
117
|
-
{ type: "chat", user: "Kevin", text: "Hey!" }
|
|
118
|
-
"Kevin says: Hey!"
|
|
119
|
-
|
|
120
|
-
// message 2
|
|
121
|
-
{ date: 1754659171196, items: [1, 2, 3] }
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Example 3 - Reconnection
|
|
125
|
-
Using `itty-sockets`, you can safely fire `.open()` on the connection at any time, even if already connected. All listeners will continue to work perfectly once reconnected.
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
const channel = connect('wss://example.com')
|
|
129
|
-
.on('message', console.log)
|
|
130
|
-
.on('open', () => console.log('connected'))
|
|
131
|
-
.on('close', () => console.log('disconnected'))
|
|
132
|
-
|
|
133
|
-
// we'll just reconnect every second - this is safe!
|
|
134
|
-
setInterval(channel.open, 1000)
|
|
135
|
-
```
|
|
63
|
+
## API at a Glance
|
|
136
64
|
|
|
137
|
-
|
|
65
|
+
| Method | Description |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `connect(channel, options?)` | Connect to a channel (or raw `wss://` URL) |
|
|
68
|
+
| `.on(type, listener)` | Listen for events (`'message'`, `'join'`, `'leave'`, `'open'`, `'close'`, `'error'`, custom types, or `'*'`) |
|
|
69
|
+
| `.on(filterFn, listener)` | Listen with a custom filter function |
|
|
70
|
+
| `.send(message, uid?)` | Send a message (optionally to a specific user) |
|
|
71
|
+
| `.push(message, uid?)` | Send a message and disconnect |
|
|
72
|
+
| `.open()` | (Re)connect — safe to call anytime, listeners are preserved |
|
|
73
|
+
| `.close()` | Disconnect |
|
|
74
|
+
| `.remove(type, listener)` | Remove a listener |
|
|
138
75
|
|
|
76
|
+
## See the [full documentation](https://itty.ws/docs) for more!
|
package/connect.d.ts
CHANGED
|
@@ -15,11 +15,17 @@ export type MessageEvent<T = any> = {
|
|
|
15
15
|
} & EventBase;
|
|
16
16
|
export type JoinEvent = {
|
|
17
17
|
type: 'join';
|
|
18
|
-
|
|
18
|
+
total: number;
|
|
19
|
+
self?: boolean;
|
|
20
|
+
users?: {
|
|
21
|
+
uid: string;
|
|
22
|
+
alias?: string;
|
|
23
|
+
self?: boolean;
|
|
24
|
+
}[];
|
|
19
25
|
} & EventBase;
|
|
20
26
|
export type LeaveEvent = {
|
|
21
27
|
type: 'leave';
|
|
22
|
-
|
|
28
|
+
total: number;
|
|
23
29
|
} & EventBase;
|
|
24
30
|
export type ErrorEvent = {
|
|
25
31
|
type: 'error';
|
|
@@ -30,6 +36,7 @@ export type IttySocketOptions = {
|
|
|
30
36
|
alias?: string;
|
|
31
37
|
echo?: true;
|
|
32
38
|
announce?: true;
|
|
39
|
+
list?: true;
|
|
33
40
|
};
|
|
34
41
|
type EventUnion<Events> = {
|
|
35
42
|
[K in Exclude<keyof Events & string, 'message'>]: {
|
|
@@ -49,7 +56,7 @@ export type IttySocket<Base = object, Events extends Record<string, any> = Empty
|
|
|
49
56
|
close: () => IttySocket<Base, Events>;
|
|
50
57
|
send: SendFn<Base, Events>;
|
|
51
58
|
push: SendFn<Base, Events>;
|
|
52
|
-
remove(type: string, listener: () => any): IttySocket<Base, Events>;
|
|
59
|
+
remove(type: string, listener: (...args: any[]) => any): IttySocket<Base, Events>;
|
|
53
60
|
on(type: 'open', listener: () => any): IttySocket<Base, Events>;
|
|
54
61
|
on(type: 'close', listener: () => any): IttySocket<Base, Events>;
|
|
55
62
|
on<K extends keyof Events & string>(type: K, listener: (event: Base & Events[K] & {
|
|
@@ -63,8 +70,7 @@ export type IttySocket<Base = object, Events extends Record<string, any> = Empty
|
|
|
63
70
|
on(type: 'join', listener: (event: JoinEvent) => any): IttySocket<Base, Events>;
|
|
64
71
|
on(type: 'leave', listener: (event: LeaveEvent) => any): IttySocket<Base, Events>;
|
|
65
72
|
on(type: 'error', listener: (event: ErrorEvent) => any): IttySocket<Base, Events>;
|
|
66
|
-
|
|
67
|
-
on<T = Record<string, any>>(type: string, listener: (event: Base & T & {
|
|
73
|
+
on<T = Record<string, any>, K extends string = string>(type: K extends 'open' | 'close' | 'message' | 'join' | 'leave' | 'error' | keyof Events ? never : K, listener: (event: Base & T & {
|
|
68
74
|
type: string;
|
|
69
75
|
message: T;
|
|
70
76
|
}) => any): IttySocket<Base, Events>;
|
|
@@ -72,6 +78,15 @@ export type IttySocket<Base = object, Events extends Record<string, any> = Empty
|
|
|
72
78
|
type: string;
|
|
73
79
|
message: T;
|
|
74
80
|
}) => any): IttySocket<Base, Events>;
|
|
75
|
-
}
|
|
81
|
+
} : {
|
|
82
|
+
on<T = Record<string, any>, K extends string = string>(type: K extends 'open' | 'close' | 'message' | keyof Events ? never : K, listener: (event: Base & T & {
|
|
83
|
+
type: string;
|
|
84
|
+
message: T;
|
|
85
|
+
}) => any): IttySocket<Base, Events>;
|
|
86
|
+
on<T = Record<string, any>>(type: (event?: any) => any, listener: (event: Base & T & {
|
|
87
|
+
type: string;
|
|
88
|
+
message: T;
|
|
89
|
+
}) => any): IttySocket<Base, Events>;
|
|
90
|
+
});
|
|
76
91
|
export declare let connect: IttySocketConnect;
|
|
77
92
|
export {};
|