@zap-socket/server 0.0.6 → 0.0.8

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/dist/server.d.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import { WebSocketServer, WebSocket } from "ws";
2
- import type { EventMap, ZapServerEvent } from "@zap-socket/types";
2
+ import type { EventMap, ZapEvent, ZapServerEvent } from "@zap-socket/types";
3
3
  interface ZapServerConstructorT {
4
4
  port: number;
5
5
  events?: EventMap;
6
6
  }
7
7
  export declare class ZapServer<T extends EventMap> {
8
8
  wss: WebSocketServer;
9
+ onconnect: (handler: (ctx: {
10
+ id: string;
11
+ ws: WebSocket;
12
+ }) => void) => void;
13
+ private onconnectHandler;
9
14
  private wsToId;
10
15
  private idToWs;
11
16
  private _events;
@@ -16,9 +21,9 @@ export declare class ZapServer<T extends EventMap> {
16
21
  broadcastRaw(data: any): void;
17
22
  broadcast(event: keyof T, data: any): void;
18
23
  selectiveBroascast(event: string, data: any, connections: string[]): void;
19
- get event(): { [K in keyof T as T[K] extends ZapServerEvent<any> ? K : never]: {
20
- send: (clientId: string, data?: (T[K] extends ZapServerEvent<any> ? T[K]["data"] : never)) => void;
21
- broadcast: (data?: (T[K] extends ZapServerEvent<any> ? T[K]["data"] : never)) => void;
24
+ get events(): { [K in keyof T as T[K] extends ZapServerEvent<any> | ZapEvent<any, any> ? K : never]: {
25
+ send: (clientId: string, data?: (T[K] extends ZapServerEvent<any> ? T[K]["data"] : T[K] extends ZapEvent<any, any> ? ReturnType<T[K]["process"]> : never)) => void;
26
+ broadcast: (data?: (T[K] extends ZapServerEvent<any> ? T[K]["data"] : T[K] extends ZapEvent<any, any> ? ReturnType<T[K]["process"]> : never)) => void;
22
27
  }; };
23
28
  get clients(): Set<string>;
24
29
  get socketMap(): Map<string, WebSocket>;
package/dist/server.js CHANGED
@@ -5,6 +5,8 @@ const isClientEvent = (event) => {
5
5
  };
6
6
  export class ZapServer {
7
7
  wss;
8
+ onconnect;
9
+ onconnectHandler;
8
10
  wsToId;
9
11
  idToWs;
10
12
  _events = {};
@@ -13,78 +15,88 @@ export class ZapServer {
13
15
  this.wsToId = new Map();
14
16
  this.idToWs = new Map();
15
17
  this._events = events;
18
+ this.onconnectHandler = () => { };
19
+ this.onconnect = (handler) => {
20
+ this.onconnectHandler = handler;
21
+ };
16
22
  this.wss.on("listening", () => {
17
23
  if (callback)
18
24
  callback();
19
25
  });
20
26
  this.wss.on("connection", (ws, req) => {
21
27
  ws.on("message", (message) => {
22
- if (!this.wsToId.get(ws)) {
28
+ if (!this.wsToId.get(ws) && message.toString() === "OPEN") {
23
29
  const id = generateId();
24
30
  this.wsToId.set(ws, id);
25
31
  this.idToWs.set(id, ws);
26
32
  ws.send("ID " + id);
27
- console.log(`client ${id} connected.`);
33
+ this.onconnectHandler({
34
+ id,
35
+ ws
36
+ });
28
37
  return;
29
38
  }
30
39
  const clientId = this.wsToId.get(ws);
31
- for (const [event, eventObj] of Object.entries(this._events)) {
32
- if (!isClientEvent(eventObj))
33
- continue;
34
- const { process, middleware } = eventObj;
35
- const parsedMessage = deserialize(message.toString());
36
- if (parsedMessage &&
37
- (parsedMessage["event"] === event || parsedMessage["stream"] === event)) {
38
- const { data, requestId, streamId } = parsedMessage;
39
- // Do middleware checks
40
- const ctx = {};
41
- if (middleware) {
42
- middleware.forEach((m) => {
43
- const metadata = {
44
- id: clientId,
45
- ip: req.socket.remoteAddress,
46
- timestamp: Date.now(),
47
- size: message.toString().length
48
- };
49
- const msg = {
50
- event,
51
- data: parsedMessage,
52
- metadata
53
- };
54
- if (!m(ctx, msg)) {
55
- return;
56
- }
57
- });
58
- }
59
- // By this point all the middlewares allow to pass through
60
- if (requestId) {
61
- const result = process(data, { server: this, id: this.wsToId.get(ws), buffer: ctx });
62
- const serialized = serialize(requestId ? { requestId, event, data: result } : { event, data: result });
63
- // TODO: throw some nice error: only return stuff that is serializable
64
- // i.e. primary data types and objects
65
- if (!serialized)
66
- return;
67
- ws.send(serialized);
68
- }
69
- else if (streamId) {
70
- const consumeStream = async () => {
71
- const result = process(data, { server: this, id: this.wsToId.get(ws), buffer: ctx });
72
- for await (const x of result) {
73
- const packet = {
74
- streamId,
75
- fragment: x
76
- };
77
- this.sendMessageRaw(clientId, packet);
78
- }
79
- this.sendMessageRaw(clientId, {
80
- streamId,
81
- done: true
82
- });
83
- };
84
- consumeStream();
40
+ const parsedMessage = deserialize(message.toString());
41
+ if (!parsedMessage)
42
+ return;
43
+ const { event, stream, data, requestId, streamId, batch } = parsedMessage;
44
+ const key = event || stream;
45
+ const eventObj = this._events[key];
46
+ if (!eventObj || !isClientEvent(eventObj))
47
+ return;
48
+ const { process, middleware } = eventObj;
49
+ // Setup middleware context
50
+ const ctx = {};
51
+ if (middleware) {
52
+ for (const m of middleware) {
53
+ const metadata = {
54
+ id: clientId,
55
+ ip: req.socket.remoteAddress,
56
+ timestamp: Date.now(),
57
+ size: message.toString().length,
58
+ };
59
+ const msg = {
60
+ event: key,
61
+ data: parsedMessage,
62
+ metadata,
63
+ };
64
+ if (!m(ctx, msg))
65
+ return;
66
+ }
67
+ }
68
+ // All middleware passed
69
+ const context = { server: this, id: this.wsToId.get(ws), buffer: ctx };
70
+ if (requestId) { // req-res premitive
71
+ let result;
72
+ if (batch) {
73
+ if (!data) {
74
+ ws.send("ACK " + requestId);
75
+ return;
85
76
  }
86
- return; // finally return to avoid looping through rest of events unneccessarily
77
+ result = data.map((part) => process(part, context));
87
78
  }
79
+ else {
80
+ result = process(data, context);
81
+ }
82
+ if (result === undefined) { // just ACK the request process returns nothing
83
+ ws.send("ACK " + requestId);
84
+ return;
85
+ }
86
+ const serialized = serialize({ requestId, event: key, data: result });
87
+ if (!serialized)
88
+ return;
89
+ ws.send(serialized);
90
+ }
91
+ else if (streamId) { // stream premitive
92
+ const consumeStream = async () => {
93
+ const result = process(data, context);
94
+ for await (const fragment of result) {
95
+ this.sendMessageRaw(clientId, { streamId, fragment });
96
+ }
97
+ this.sendMessageRaw(clientId, { streamId, done: true });
98
+ };
99
+ consumeStream();
88
100
  }
89
101
  });
90
102
  ws.on("close", () => {
@@ -167,30 +179,28 @@ export class ZapServer {
167
179
  ws.send(serializedPacket);
168
180
  });
169
181
  }
170
- get event() {
182
+ get events() {
171
183
  return Object.fromEntries(Object.keys(this._events).map((eventName) => {
172
- // HACK: use a better method to determine the type of event.
173
- if ("data" in this._events[eventName]) {
174
- // event is server event
175
- return [eventName, {
176
- send: (clientId, data) => {
177
- const packet = {
178
- event: eventName,
179
- data
180
- };
181
- this.sendMessageRaw(clientId, packet);
182
- },
183
- broadcast: (data) => {
184
- const packet = {
185
- event: eventName,
186
- data
187
- };
188
- this.broadcastRaw(packet);
189
- }
190
- }];
191
- }
192
- return null;
193
- }).filter(entry => entry !== null));
184
+ return [
185
+ eventName,
186
+ {
187
+ send: (clientId, data) => {
188
+ const packet = {
189
+ event: eventName,
190
+ data
191
+ };
192
+ this.sendMessageRaw(clientId, packet);
193
+ },
194
+ broadcast: (data) => {
195
+ const packet = {
196
+ event: eventName,
197
+ data
198
+ };
199
+ this.broadcastRaw(packet);
200
+ }
201
+ }
202
+ ];
203
+ }));
194
204
  }
195
205
  get clients() {
196
206
  return new Set(this.idToWs.keys());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-socket/server",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "A fully typesafe tRPC-inspired WebSocket library with Zod validation, req-res model, and native subscriptions.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "vitest": "^3.0.9"
24
24
  },
25
25
  "dependencies": {
26
- "@zap-socket/types": "^0.0.3",
26
+ "@zap-socket/types": "^0.0.4",
27
27
  "zod": "^3.24.2"
28
28
  }
29
29
  }