itty-sockets 0.5.2 → 0.5.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ ## Changelog
2
+ CAUTION: Pre v1.0.0, this should be considered an alpha release, with minor updates allowing for breaking changes to the interface.
3
+
4
+ #### v0.5.0
5
+ - BREAKING: removed base (url) option - instead, simply pass a full wss:// path as the channelId to use an external compatible server.
6
+ #### v0.4.0
7
+ - added: base (url) option
8
+ #### v0.3.1
9
+ - fixes: module export
10
+ - removes extra NPM files
11
+ #### v0.3.0
12
+ - breaking: every event has multiple listeners (previously only on('message') allowed multiple)
13
+ - added: join/leave/error event types
14
+ - added: .remove('event-name', listener) to remove listeners
15
+ #### v0.2.3
16
+ - fix type hinting on listeners
17
+ - improve type hinting on send/push
18
+ #### v0.2.0
19
+ - alpha release 2
20
+ #### v0.1.0
21
+ - alpha release 1
package/README.md CHANGED
@@ -16,43 +16,46 @@
16
16
 
17
17
  ---
18
18
 
19
- Tiny realtime messaging client in under 500 bytes. **No backend needed.**
19
+ # WebSockets : simplified and minified.
20
20
 
21
- ## What does this solve?
22
-
23
- Itty Sockets simplifies sending/receiving realtime data.
21
+ Zero-config. Pick a channel and go.
22
+ ```ts
23
+ // CLIENT 1 (listens for messages)
24
+ connect('unique-channel-name')
25
+ // listen for all messages
26
+ .on('message', e => console.log(e.message))
24
27
 
25
- By pairing an ultra-tiny client (this) with the public **[ittysockets.io](https://ittysockets.io)** backend, you
26
- can focus on sending/receiving messages, instead of building a transport layer.
28
+ // or just our custom messages
29
+ .on('my-chat-message', ({ user, text }) => console.log(user, 'says:', text))
30
+ ```
27
31
 
28
- The idea is simple:
32
+ ```ts
33
+ // CLIENT 2 (sends messages)
34
+ const channel = connect('unique-channel-name')
35
+ .send({ foo: 'bar' })
36
+ .send({ type: 'my-chat-message', user: 'Halsey', text: 'Meow!' })
29
37
 
30
- 1. One or more parties connect to a channel (by name).
31
- 2. They send/receive messages (this can be anything) in the channel.
32
- 3. That's it!
33
38
 
34
- # Example
35
- ```ts
36
- import { connect } from 'itty-sockets'
39
+ channel.send('what else can this do?')
40
+ ```
37
41
 
38
- // connect to a channel
39
- const foo = connect('my-secret-room-name')
40
42
 
41
- foo
42
- // we can listen for messages
43
- .on('message', e => console.log(e.message))
43
+ ## Or simply use `connect` as a tiny WebSocket client that brings the following:
44
44
 
45
- // and/or send some
46
- .send('Hello World!') // "Hello World!"
47
- .send([1, 2, 3]) // [1, 2, 3]
48
- .send({ foo: 'bar' }) // { foo: "bar" }
49
- ```
45
+ - JSON parsing/stringifying
46
+ - message queing - sending automatically connects and queue is flushed on open
47
+ - easy reconnection (listeners keep working)
48
+ - custom listeners/filters
49
+ - chainable syntax (it's just handy)
50
50
 
51
- ### Important Considerations
51
+ ```ts
52
+ const ws = connect('wss://somewhere.else')
53
+ .on('message', console.log) // log all messages
54
+ .send({ foo: 'bar' }) // send immediately, no waiting
52
55
 
53
- 1. **There is no history/replay/storage.** It's a live stream only.
54
- 2. **We don't authenticate.** [ittysockets.io](https://ittysockets.io) leverages security through obfuscation (a near-infinite number of channel names). Choose a more unique channel for more privacy. Need more? Consider encrypting/decrypting your payloads before transmission (this is easy).
55
- 3. **There are no guarantees of delivery.** While [ittysockets.io](https://ittysockets.io) is *extremely* stable, it's a free public service that is provided without any guarantees of delivery or uptime. Manage risk accordingly.
56
+ // optional - reconnect every second (no effect if open)
57
+ setInterval(ws.open, 1000)
58
+ ```
56
59
 
57
60
  <br />
58
61
 
@@ -66,8 +69,7 @@ import { connect } from 'itty-sockets'
66
69
  ...or simply paste this into your environment/console:
67
70
  <!-- BEGIN SNIPPET -->
68
71
  ```ts
69
- let connect=(e,s={})=>{let o,t=0,n=[],a={},r=()=>(o||(o=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),o.onclose=()=>{t=0,o=null;for(let e of a.close??[])e()},o.onopen=()=>{for(;n.length;)o?.send(n.shift());for(let e of a.open??[])e();t&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of a[s.type??"message"]??[])e({...s,date:new Date(s.date)})}),l);const l=new Proxy(r,{get:(e,s)=>({close:()=>(1==o?.readyState?o.close():t=1,l),open:r,send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==o?.readyState?(o.send(e),l):(n.push(e),r())),push:(e,s)=>(t=1,l.send(e,s)),on:(e,s)=>((a[e]??=[]).push(s),r()),remove:(e,s,o=a[e],t=o?.indexOf(s)??-1)=>(~t&&o?.splice(t,1),r())}[s])});return l};
70
- ```
72
+ let connect=(e,s={})=>{let t,a=0,n=[],p=[],o={},l=()=>(t||(t=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),t.onmessage=(e,s=JSON.parse(e.data),t=s?.message,a={...null==t?.[0]&&t,...s,...s.date&&{date:new Date(s.date)}})=>{o[s?.type??t?.type]?.map(e=>e(a)),s?.type||o.message?.map(e=>e(a)),p.map(([e,s])=>e(a)&&s(a))},t.onopen=()=>(n.splice(0).map(e=>t?.send(e)),o.open?.map(e=>e()),a&&t?.close()),t.onclose=()=>(a=0,t=null,o.close?.map(e=>e()))),c),c=new Proxy(l,{get:(e,s)=>({open:l,close:()=>(1==t?.readyState?t.close():a=1,c),push:(e,s)=>(a=1,c.send(e,s)),send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==t?.readyState?(t.send(e),c):(n.push(e),l())),on:(e,s)=>(s&&(e?.[0]?(o[e]??=[]).push(s):p.push([e,s])),l()),remove:(e,s,t=o[e],a=t?.indexOf(s)??-1)=>(~a&&t?.splice(a,1),l())}[s])});return c};```
71
73
  <!-- END SNIPPET -->
72
74
 
73
75
  <br />
@@ -81,17 +83,17 @@ To start, simply connect to a channel based on a unique name (this can be anythi
81
83
  import { connect } from 'itty-sockets'
82
84
 
83
85
  // basic connection
84
- const channel = connect('my-channels/my-super-secret-channel')
86
+ const channel = connect('my-super-secret-channel')
85
87
 
86
88
  // with options
87
- const channel = connect('my-channels/my-super-secret-channel', {
88
- as: 'Kevin',
89
- announce: true,
90
- echo: true
89
+ const channel = connect('my-super-secret-channel', {
90
+ alias: 'Kevin', // optional non-unique identifier, visible in messages
91
+ announce: true, // shares your uid/alias with the channel on joining
92
+ echo: true // echos your own messages back to you (for testing)
91
93
  })
92
94
 
93
- // an external server
94
- const channel = connect('wss://somewhere.else/entirely')
95
+ // or any external JSON WebSocket server
96
+ const channel = connect('wss://somewhere.else.entirely')
95
97
  ```
96
98
 
97
99
  #### Connection Options
package/connect.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";exports.connect=(e,s={})=>{let t,a=0,n=[],p=[],o={},c=()=>(t||(t=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),t.onmessage=(e,s=JSON.parse(e.data),t=s?.message,a={...null==t?.[0]&&t,...s,...s.date&&{date:new Date(s.date)}})=>{o[s?.type??t?.type]?.map(e=>e(a)),s?.type||o.message?.map(e=>e(a)),p.map(([e,s])=>e(a)&&s(a))},t.onopen=()=>(n.splice(0).map(e=>t?.send(e)),o.open?.map(e=>e()),a&&t?.close()),t.onclose=()=>(a=0,t=null,o.close?.map(e=>e()))),l),l=new Proxy(c,{get:(e,s)=>({open:c,close:()=>(1==t?.readyState?t.close():a=1,l),push:(e,s)=>(a=1,l.send(e,s)),send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==t?.readyState?(t.send(e),l):(n.push(e),c())),on:(e,s)=>(s&&(e?.[0]?(o[e]??=[]).push(s):p.push([e,s])),c()),remove:(e,s,t=o[e],a=t?.indexOf(s)??-1)=>(~a&&t?.splice(a,1),c())}[s])});return l};
package/connect.d.ts CHANGED
@@ -12,7 +12,7 @@ type OptionalUserDetails = {
12
12
  };
13
13
  export type MessageEvent<MessageType = any> = {
14
14
  message: MessageType;
15
- } & Date & UserDetails;
15
+ } & Date & UserDetails & MessageType;
16
16
  export type JoinEvent = {
17
17
  type: 'join';
18
18
  users: number;
@@ -32,11 +32,16 @@ export type IttySocket = {
32
32
  connected: boolean;
33
33
  send: SendMessage;
34
34
  push: SendMessage;
35
- on<MessageFormat = any>(type: 'message', listener: (event: MessageEvent<MessageFormat>) => any): IttySocket;
36
35
  on(type: 'join', listener: (event: JoinEvent) => any): IttySocket;
37
36
  on(type: 'leave', listener: (event: LeaveEvent) => any): IttySocket;
38
37
  on(type: 'error', listener: (event: ErrorEvent) => any): IttySocket;
39
- on(type: Exclude<IttySocketEvent, 'message'>, listener: () => any): IttySocket;
38
+ on<MessageFormat = any>(type: 'message', listener: (event: MessageEvent<MessageFormat>) => any): IttySocket;
39
+ on<MessageFormat = any>(type: string, listener: (event: MessageEvent<MessageFormat & {
40
+ type: string;
41
+ }>) => any): IttySocket;
42
+ on<MessageFormat = any>(type: (event?: any) => any, listener: (event: MessageEvent<MessageFormat & {
43
+ type: string;
44
+ }>) => any): IttySocket;
40
45
  remove(type: IttySocketEvent, listener: () => any): IttySocket;
41
46
  };
42
47
  export type IttySocketOptions = {
@@ -45,5 +50,5 @@ export type IttySocketOptions = {
45
50
  echo?: true;
46
51
  announce?: true;
47
52
  };
48
- export declare const connect: (channelId: string, options?: IttySocketOptions) => IttySocket;
53
+ export declare let connect: (channelId: string, options?: IttySocketOptions) => IttySocket;
49
54
  export {};
package/connect.mjs CHANGED
@@ -1 +1 @@
1
- const e=(e,s={})=>{let o,t=0,n=[],a={},r=()=>(o||(o=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),o.onclose=()=>{t=0,o=null;for(let e of a.close??[])e()},o.onopen=()=>{for(;n.length;)o?.send(n.shift());for(let e of a.open??[])e();t&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of a[s.type??"message"]??[])e({...s,date:new Date(s.date)})}),l);const l=new Proxy(r,{get:(e,s)=>({close:()=>(1==o?.readyState?o.close():t=1,l),open:r,send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==o?.readyState?(o.send(e),l):(n.push(e),r())),push:(e,s)=>(t=1,l.send(e,s)),on:(e,s)=>((a[e]??=[]).push(s),r()),remove:(e,s,o=a[e],t=o?.indexOf(s)??-1)=>(~t&&o?.splice(t,1),r())}[s])});return l};export{e as connect};
1
+ let e=(e,s={})=>{let t,a=0,n=[],p=[],o={},l=()=>(t||(t=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),t.onmessage=(e,s=JSON.parse(e.data),t=s?.message,a={...null==t?.[0]&&t,...s,...s.date&&{date:new Date(s.date)}})=>{o[s?.type??t?.type]?.map(e=>e(a)),s?.type||o.message?.map(e=>e(a)),p.map(([e,s])=>e(a)&&s(a))},t.onopen=()=>(n.splice(0).map(e=>t?.send(e)),o.open?.map(e=>e()),a&&t?.close()),t.onclose=()=>(a=0,t=null,o.close?.map(e=>e()))),c),c=new Proxy(l,{get:(e,s)=>({open:l,close:()=>(1==t?.readyState?t.close():a=1,c),push:(e,s)=>(a=1,c.send(e,s)),send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==t?.readyState?(t.send(e),c):(n.push(e),l())),on:(e,s)=>(s&&(e?.[0]?(o[e]??=[]).push(s):p.push([e,s])),l()),remove:(e,s,t=o[e],a=t?.indexOf(s)??-1)=>(~a&&t?.splice(a,1),l())}[s])});return c};export{e as connect};
package/package.json CHANGED
@@ -1,39 +1,30 @@
1
1
  {
2
2
  "name": "itty-sockets",
3
- "version": "0.5.2",
4
- "description": "Tiny realtime messaging client in under 450 bytes. No backend needed.",
3
+ "version": "0.5.3",
4
+ "description": "WebSockets : simplified and minified.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
- "import": "./index.mjs",
9
- "require": "./index.js",
10
- "types": "./index.d.ts"
11
- },
12
- "./connect": {
13
8
  "import": "./connect.mjs",
14
- "require": "./connect.js",
15
- "types": "./connect.d.ts"
9
+ "types": "./connect.d.ts",
10
+ "require": "./connect.cjs"
16
11
  }
17
12
  },
18
13
  "scripts": {
19
- "dev": "bun test --watch",
20
- "lint": "bun eslint src",
14
+ "dev": "bun test --watch --coverage",
15
+ "lint": "itty lint",
21
16
  "verify": "echo 'verifying module...' && bun run build && bun test",
22
17
  "prerelease": "bun run verify",
23
18
  "prerelease:next": "bun run verify",
24
- "prebuild": "rimraf dist && mkdir dist",
25
- "build": "rollup -c && bun readme-inject.mjs",
26
- "release": "release --tag --push --patch --src=dist",
27
- "release:next": "release --tag --push --type=next --src=dist"
19
+ "build": "itty build --snippet=connect --hybrid",
20
+ "release:dry": "itty publish --patch --tag --dry-run",
21
+ "release": "itty publish --tag --push --patch --src=dist",
22
+ "release:next": "itty publish --tag --push --type=next --src=dist"
28
23
  },
29
24
  "keywords": [
30
25
  "websockets",
31
26
  "realtime",
32
- "public",
33
- "messages",
34
- "tiny",
35
- "free",
36
- "p2p"
27
+ "client"
37
28
  ],
38
29
  "repository": {
39
30
  "type": "git",
@@ -45,18 +36,7 @@
45
36
  "url": "https://github.com/kwhitley/itty-sockets/issues"
46
37
  },
47
38
  "devDependencies": {
48
- "@rollup/plugin-terser": "^0.4.4",
49
- "@rollup/plugin-typescript": "^11.1.6",
50
39
  "@types/bun": "^1.2.3",
51
- "@typescript-eslint/eslint-plugin": "^8.18.0",
52
- "@typescript-eslint/parser": "^8.18.0",
53
- "eslint": "^9.17.0",
54
- "globby": "^14.1.0",
55
- "rimraf": "^6.0.1",
56
- "rollup": "^4.28.1",
57
- "rollup-plugin-bundle-size": "^1.0.3",
58
- "rollup-plugin-copy": "^3.5.0",
59
- "typescript": "^5.7.2",
60
- "yarn-release": "^1.10.6"
40
+ "itty-packager": "^1.0.2"
61
41
  }
62
42
  }
package/connect.js DELETED
@@ -1 +0,0 @@
1
- "use strict";exports.connect=(e,s={})=>{let t,o=0,n=[],r={},a=()=>(t||(t=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),t.onclose=()=>{o=0,t=null;for(let e of r.close??[])e()},t.onopen=()=>{for(;n.length;)t?.send(n.shift());for(let e of r.open??[])e();o&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of r[s.type??"message"]??[])e({...s,date:new Date(s.date)})}),c);const c=new Proxy(a,{get:(e,s)=>({close:()=>(1==t?.readyState?t.close():o=1,c),open:a,send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==t?.readyState?(t.send(e),c):(n.push(e),a())),push:(e,s)=>(o=1,c.send(e,s)),on:(e,s)=>((r[e]??=[]).push(s),a()),remove:(e,s,t=r[e],o=t?.indexOf(s)??-1)=>(~o&&t?.splice(o,1),a())}[s])});return c};
package/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from './connect';
package/index.js DELETED
@@ -1 +0,0 @@
1
- "use strict";exports.connect=(e,s={})=>{let t,o=0,n=[],r={},a=()=>(t||(t=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),t.onclose=()=>{o=0,t=null;for(let e of r.close??[])e()},t.onopen=()=>{for(;n.length;)t?.send(n.shift());for(let e of r.open??[])e();o&&t?.close()},t.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of r[s.type??"message"]??[])e({...s,date:new Date(s.date)})}),c);const c=new Proxy(a,{get:(e,s)=>({close:()=>(1==t?.readyState?t.close():o=1,c),open:a,send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==t?.readyState?(t.send(e),c):(n.push(e),a())),push:(e,s)=>(o=1,c.send(e,s)),on:(e,s)=>((r[e]??=[]).push(s),a()),remove:(e,s,t=r[e],o=t?.indexOf(s)??-1)=>(~o&&t?.splice(o,1),a())}[s])});return c};
package/index.mjs DELETED
@@ -1 +0,0 @@
1
- const e=(e,s={})=>{let o,t=0,n=[],a={},r=()=>(o||(o=new WebSocket((/^wss?:/.test(e)?e:"wss://ittysockets.io/c/"+e)+"?"+new URLSearchParams(s)),o.onclose=()=>{t=0,o=null;for(let e of a.close??[])e()},o.onopen=()=>{for(;n.length;)o?.send(n.shift());for(let e of a.open??[])e();t&&o?.close()},o.onmessage=(e,s=JSON.parse(e.data))=>{for(let e of a[s.type??"message"]??[])e({...s,date:new Date(s.date)})}),l);const l=new Proxy(r,{get:(e,s)=>({close:()=>(1==o?.readyState?o.close():t=1,l),open:r,send:(e,s)=>(e=JSON.stringify(e),e=s?"@@"+s+"@@"+e:e,1==o?.readyState?(o.send(e),l):(n.push(e),r())),push:(e,s)=>(t=1,l.send(e,s)),on:(e,s)=>((a[e]??=[]).push(s),r()),remove:(e,s,o=a[e],t=o?.indexOf(s)??-1)=>(~t&&o?.splice(t,1),r())}[s])});return l};export{e as connect};