itty-sockets 0.1.0 → 0.2.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 CHANGED
@@ -20,45 +20,28 @@ Tiny messaging client in under 400 bytes. No backend needed.
20
20
 
21
21
  ## Example (using ittysockets.io public channels)
22
22
  ```ts
23
- import { connect } from 'itty-sockets' // ~400 bytes
23
+ import { connect } from 'itty-sockets' // ~340 bytes
24
24
 
25
- // create a channel instance
26
- const foo = connect('foo', { echo: true }) // echo messages back to sender
25
+ // connect to a channel (optionally echo messages back to yourself)
26
+ const foo = connect('my-secret-room-name', { echo: true })
27
27
 
28
- // listen for messages
29
- foo.listen(e => {
30
- console.log(e.alias ?? e.uid, 'says', e.message, 'at', e.date)
31
- })
32
-
33
- // send some messages
34
28
  foo
35
- .send('hello world!')
36
- .send([1,2,3]) // no need to stringify
37
- .send({ foo: 'bar' })
38
-
39
- // or connect, send, and close - all in one call
40
- foo.push('this will open, send, and close the connection')
41
- ```
42
-
43
- ## Example (other WebSocket servers)
44
- ```ts
45
- import { ws } from 'itty-sockets' // ~340 bytes
46
-
47
- const foo = ws('wss://example.com', { json: true })
29
+ // we can listen for messages
30
+ .on('message', e => console.log(e.message))
48
31
 
49
- foo
50
- .listen(console.log) // this will auto-parse JSON messages from the server
51
- .send('hello world!')
52
- .send([1,2,3])
53
- .send({ foo: 'bar' })
32
+ // and/or send some
33
+ .send('Hello World!') // "Hello World!"
34
+ .send([1, 2, 3]) // [1, 2, 3]
35
+ .send({ foo: 'bar' }) // { foo: "bar" }
54
36
  ```
55
37
 
56
38
  ## Features
57
39
 
58
40
  - Simple and powerful API for sending and receiving messages & data.
59
- - Prevents WebSocket race conditions.
60
41
  - No backend service needed. Ours is fast and private.
61
42
  - Full TypeScript support, including custom types for messages.
43
+ - Prevents WebSocket race conditions. Automatically connects when needed to send/listen.
44
+ - Chainable. Every method returns the channel again.
62
45
  - Ultra-tiny. It's an itty library, after all.
63
46
 
64
47
  ## What is itty-sockets?
@@ -82,11 +65,11 @@ There is intentionally no message logging or tracking of any kind. It's easier
82
65
 
83
66
  ## Browser Usage
84
67
 
85
- If you want to send/receive messages from the browser (e.g. for sending information from one web page or tab to another), copy and paste this snippet directly into your browser console, then use as normal.
68
+ For use in browser/DevTools scripting, copy and paste this snippet directly into your browser console, then use as normal:
86
69
 
87
70
  <!-- BEGIN SNIPPET -->
88
71
  ```ts
89
- let connect=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,l)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),r()??l)),push:(e,s)=>(a=1,l.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??l),close:()=>(1==t?.readyState?t.close():a=1,l)}[s])})};
72
+ let connect=(e,s={})=>{let o,t=[],n=[],a=0,r={},c=()=>(o||(o=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),o.onopen=()=>{for(;t.length;)o?.send(t.shift());r.open?.(),a&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of n)e({...s,date:new Date(s.date)})},o.onclose=()=>(a=0,o=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==o?.readyState?o.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==o?.readyState?o.send(e)??l:(t.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(n.push(s),c()):l)}[s])});return l};
90
73
  ```
91
74
  <!-- END SNIPPET -->
92
75
 
@@ -100,11 +83,15 @@ connect('foo').push('hello world!')
100
83
 
101
84
  | METHOD | DESCRIPTION | EXAMPLE |
102
85
  | --- | --- | --- |
103
- | **connect(id, options)** | Creates a new connect | `connect('foo')` |
104
- | **send(message)** | Sends a message to the room | `room.send({ type: 'chat', text: 'hello' })` |
105
- | **push(message)** | Sends a message and closes the connection | `room.push({ type: 'goodbye' })` |
106
- | **listen(fn)** | Adds a message listener | `room.listen(msg => console.log(msg))` |
107
- | **close()** | Closes the connection | `room.close()` |
86
+ | **connect(id, options)** | Creates a new channel connection | `connect('foo')` |
87
+ | **.open()** | Opens/re-opens the connection (manually, usually not needed) | `channel.open()` |
88
+ | **.close()** | Closes the connection | `channel.close()` |
89
+ | **.send(message)** | Sends a message to the room | `channel.send({ type: 'chat', text: 'hello' })` |
90
+ | **.push(message)** | Sends a message and closes the connection | `channel.push({ type: 'goodbye' })` |
91
+ | **.on('message', listener)** | Adds a message listener (multiple allowed) | `channel.on('message', event => console.log(event))` |
92
+ | **.on('open', listener)** | Executes a listener on channel open (one allowed) | `channel.on('open', () => console.log('channel opened'))` |
93
+ | **.on('close', listener)** | Executes a listener on channel close (one allowed) | `channel.on('close', () => console.log('channel closed'))` |
94
+
108
95
 
109
96
  ### Available Options
110
97
 
@@ -114,10 +101,12 @@ connect('foo').push('hello world!')
114
101
  | **echo** | Whether to echo messages back to the sender | `false` | `{ echo: true }` |
115
102
 
116
103
 
117
- ## Message Format
104
+ ## MessageEvent Format
118
105
  ```ts
119
- type Message = {
106
+ type MessageEvent = {
120
107
  id: string // unique message ID
108
+ uid: string // unique user ID
109
+ alias: string? // optional display name
121
110
  date: Date // JavaScript Date object
122
111
  message: any // the message payload
123
112
  }
package/connect.d.ts CHANGED
@@ -1,16 +1,22 @@
1
- export type AllowedProperty = 'ws' | 'send' | 'push' | 'listen' | 'close';
1
+ export type AllowedProperty = 'open' | 'close' | 'send' | 'push' | 'on';
2
2
  export type MessageEvent<MessageType = any> = {
3
3
  date: Date;
4
4
  uid?: string;
5
5
  alias?: string;
6
6
  message: MessageType;
7
7
  };
8
- export type SendMessage = <MessageFormat = any>(message: MessageFormat, recipient?: string) => Connection;
9
- export type Connection = {
10
- ws?: WebSocket;
8
+ export type SendMessage = <MessageFormat = any>(message: MessageFormat, recipient?: string) => IttySocket;
9
+ export type IttySocket = {
10
+ open: () => IttySocket;
11
+ close: () => IttySocket;
12
+ connected: boolean;
11
13
  send: SendMessage;
12
14
  push: SendMessage;
13
- listen: <MessageType = any>(listener: (event: MessageEvent<MessageType>) => any, when?: (event: MessageEvent<MessageType>) => any) => Connection;
14
- close: () => Connection;
15
+ on: <T extends string, MessageType = any>(type: T, listener: T extends 'message' ? (event: MessageEvent<MessageType>) => any : () => any) => IttySocket;
15
16
  };
16
- export declare const connect: (id: string, options?: Record<string, any>) => Connection;
17
+ export type IttySocketOptions = {
18
+ as?: string;
19
+ alias?: string;
20
+ echo?: boolean;
21
+ };
22
+ export declare const connect: (id: string, options?: IttySocketOptions) => IttySocket;
package/connect.js CHANGED
@@ -1 +1 @@
1
- "use strict";exports.connect=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,c)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??c:(n.push(e),r()??c)),push:(e,s)=>(a=1,c.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??c),close:()=>(1==t?.readyState?t.close():a=1,c)}[s])})};
1
+ "use strict";exports.connect=(e,s={})=>{let t,n=[],o=[],a=0,r={},c=()=>(t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());r.open?.(),a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==t?.readyState?t.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(o.push(s),c()):l)}[s])});return l};
package/connect.mjs CHANGED
@@ -1 +1 @@
1
- const e=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,l)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),r()??l)),push:(e,s)=>(a=1,l.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??l),close:()=>(1==t?.readyState?t.close():a=1,l)}[s])})};export{e as connect};
1
+ const e=(e,s={})=>{let o,t=[],n=[],a=0,r={},c=()=>(o||(o=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),o.onopen=()=>{for(;t.length;)o?.send(t.shift());r.open?.(),a&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of n)e({...s,date:new Date(s.date)})},o.onclose=()=>(a=0,o=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==o?.readyState?o.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==o?.readyState?o.send(e)??l:(t.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(n.push(s),c()):l)}[s])});return l};export{e as connect};
@@ -1 +1 @@
1
- let connect=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,l)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),r()??l)),push:(e,s)=>(a=1,l.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??l),close:()=>(1==t?.readyState?t.close():a=1,l)}[s])})};
1
+ let connect=(e,s={})=>{let o,t=[],n=[],a=0,r={},c=()=>(o||(o=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),o.onopen=()=>{for(;t.length;)o?.send(t.shift());r.open?.(),a&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of n)e({...s,date:new Date(s.date)})},o.onclose=()=>(a=0,o=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==o?.readyState?o.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==o?.readyState?o.send(e)??l:(t.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(n.push(s),c()):l)}[s])});return l};
package/index.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export * from './connect';
2
- export * from './ws';
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";exports.connect=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,l)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),r()??l)),push:(e,s)=>(a=1,l.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??l),close:()=>(1==t?.readyState?t.close():a=1,l)}[s])})},exports.ws=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(e),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,t=(s.json?JSON.parse(e.data):e.data))=>{for(let e of o)e(t)},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,l,d)=>({ws:t,send:e=>(e=s.json?JSON.stringify(e):e,1==t?.readyState?t.send(e)??d:(n.push(e),r()??d)),push:e=>(a=1,d.send(e)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??d),close:()=>(1==t?.readyState?t.close():a=1,d)}[l])})};
1
+ "use strict";exports.connect=(e,s={})=>{let t,n=[],o=[],a=0,r={},c=()=>(t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());r.open?.(),a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==t?.readyState?t.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(o.push(s),c()):l)}[s])});return l};
package/index.mjs CHANGED
@@ -1 +1 @@
1
- const e=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of o)e({...s,date:new Date(s.date)})},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,s,l)=>({ws:t,send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==t?.readyState?t.send(e)??l:(n.push(e),r()??l)),push:(e,s)=>(a=1,l.send(e,s)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??l),close:()=>(1==t?.readyState?t.close():a=1,l)}[s])})},s=(e,s={})=>{let t,n=[],o=[],a=0,r=()=>{t||(t=new WebSocket(e),t.onopen=()=>{for(;n.length;)t?.send(n.shift());a&&t?.close()},t.onmessage=(e,t=(s.json?JSON.parse(e.data):e.data))=>{for(let e of o)e(t)},t.onclose=()=>(a=0,t=null))};return new Proxy(r,{get:(e,l,d)=>({ws:t,send:e=>(e=s.json?JSON.stringify(e):e,1==t?.readyState?t.send(e)??d:(n.push(e),r()??d)),push:e=>(a=1,d.send(e)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),r()??d),close:()=>(1==t?.readyState?t.close():a=1,d)}[l])})};export{e as connect,s as ws};
1
+ const e=(e,s={})=>{let o,t=[],n=[],a=0,r={},c=()=>(o||(o=new WebSocket(`wss://ittysockets.io/r/${e??""}?${new URLSearchParams(s)}`),o.onopen=()=>{for(;t.length;)o?.send(t.shift());r.open?.(),a&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of n)e({...s,date:new Date(s.date)})},o.onclose=()=>(a=0,o=null,r.close?.())),l);const l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==o?.readyState?o.close():a=1,l),send:(e,s)=>(e=JSON.stringify(e),e=s?`@@${s}@@${e}`:e,1==o?.readyState?o.send(e)??l:(t.push(e),c())),push:(e,s)=>(a=1,l.send(e,s)),on:(e,s)=>(r[e]=s,"message"==e?(n.push(s),c()):l)}[s])});return l};export{e as connect};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itty-sockets",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "An easier way to handle WebSockets, in an itty package.",
5
5
  "main": "./sockets.js",
6
6
  "module": "./sockets.mjs",
@@ -56,11 +56,6 @@
56
56
  "import": "./connect.mjs",
57
57
  "require": "./connect.js",
58
58
  "types": "./connect.d.ts"
59
- },
60
- "./ws": {
61
- "import": "./ws.mjs",
62
- "require": "./ws.js",
63
- "types": "./ws.d.ts"
64
59
  }
65
60
  }
66
61
  }
package/ws.d.ts DELETED
@@ -1,13 +0,0 @@
1
- type SendMessage = <MessageFormat = any>(message: MessageFormat) => Connection;
2
- export type Connection = {
3
- ws?: WebSocket | null;
4
- send: SendMessage;
5
- push: SendMessage;
6
- listen: <MessageType = any>(listener: (message: MessageType) => any, when?: (message: MessageType) => any) => Connection;
7
- close: () => Connection;
8
- };
9
- export type ConnectionOptions = {
10
- json?: boolean;
11
- };
12
- export declare const ws: (url: string, options?: ConnectionOptions) => Connection;
13
- export {};
package/ws.js DELETED
@@ -1 +0,0 @@
1
- "use strict";exports.ws=(e,s={})=>{let t,n=[],o=[],r=0,a=()=>{t||(t=new WebSocket(e),t.onopen=()=>{for(;n.length;)t?.send(n.shift());r&&t?.close()},t.onmessage=(e,t=(s.json?JSON.parse(e.data):e.data))=>{for(let e of o)e(t)},t.onclose=()=>(r=0,t=null))};return new Proxy(a,{get:(e,l,d)=>({ws:t,send:e=>(e=s.json?JSON.stringify(e):e,1==t?.readyState?t.send(e)??d:(n.push(e),a()??d)),push:e=>(r=1,d.send(e)),listen:(e,s)=>(o.push((t=>(!s||s(t))&&e(t))),a()??d),close:()=>(1==t?.readyState?t.close():r=1,d)}[l])})};
package/ws.mjs DELETED
@@ -1 +0,0 @@
1
- const e=(e,s={})=>{let n,o=[],t=[],a=0,l=()=>{n||(n=new WebSocket(e),n.onopen=()=>{for(;o.length;)n?.send(o.shift());a&&n?.close()},n.onmessage=(e,n=(s.json?JSON.parse(e.data):e.data))=>{for(let e of t)e(n)},n.onclose=()=>(a=0,n=null))};return new Proxy(l,{get:(e,r,d)=>({ws:n,send:e=>(e=s.json?JSON.stringify(e):e,1==n?.readyState?n.send(e)??d:(o.push(e),l()??d)),push:e=>(a=1,d.send(e)),listen:(e,s)=>(t.push((n=>(!s||s(n))&&e(n))),l()??d),close:()=>(1==n?.readyState?n.close():a=1,d)}[r])})};export{e as ws};