@zap-socket/server 0.0.5 → 0.0.6

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/events.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { EventInput, Context, ZapEvent, ZapServerEvent, MiddlewareType } from "@zap-socket/types";
2
+ import type { EventInput, Context, ZapEvent, ZapStream, ZapServerEvent, MiddlewareType } from "@zap-socket/types";
3
3
  export declare const zapEvent: <T extends EventInput, R>(eventObj: T extends z.ZodTypeAny ? {
4
4
  input: T;
5
5
  middleware?: MiddlewareType[];
@@ -8,6 +8,14 @@ export declare const zapEvent: <T extends EventInput, R>(eventObj: T extends z.Z
8
8
  middleware?: MiddlewareType[];
9
9
  process: (ctx: Context) => R;
10
10
  }) => ZapEvent<T, R>;
11
+ export declare const zapStream: <T extends EventInput, R>(eventObj: T extends z.ZodTypeAny ? {
12
+ input: T;
13
+ middleware?: MiddlewareType[];
14
+ process: (input: z.infer<T>, ctx: Context) => AsyncGenerator<R, void, unknown>;
15
+ } : {
16
+ middleware?: MiddlewareType[];
17
+ process: (ctx: Context) => AsyncGenerator<R, void, unknown>;
18
+ }) => ZapStream<T, R>;
11
19
  export declare const zapServerEvent: <T extends z.ZodTypeAny>(eventObj: {
12
20
  data: T;
13
21
  }) => ZapServerEvent<T>;
package/dist/events.js CHANGED
@@ -8,6 +8,15 @@ export const zapEvent = (eventObj) => {
8
8
  process: eventObj.process
9
9
  };
10
10
  };
11
+ export const zapStream = (eventObj) => {
12
+ if ("input" in eventObj) {
13
+ return eventObj;
14
+ }
15
+ return {
16
+ input: z.void(),
17
+ process: eventObj.process
18
+ };
19
+ };
11
20
  export const zapServerEvent = (eventObj) => {
12
21
  return {
13
22
  data: eventObj.data
package/dist/server.d.ts CHANGED
@@ -1,19 +1,27 @@
1
+ import { WebSocketServer, WebSocket } from "ws";
1
2
  import type { EventMap, ZapServerEvent } from "@zap-socket/types";
2
3
  interface ZapServerConstructorT {
3
4
  port: number;
4
5
  events?: EventMap;
5
6
  }
6
7
  export declare class ZapServer<T extends EventMap> {
7
- private wss;
8
+ wss: WebSocketServer;
8
9
  private wsToId;
9
10
  private idToWs;
10
11
  private _events;
11
12
  constructor({ port, events }: ZapServerConstructorT, callback?: () => void);
12
13
  private removeClient;
13
14
  sendMessageRaw(clientId: string, data: any): void;
15
+ sendMessage(event: keyof T, clientId: string, data: any): void;
16
+ broadcastRaw(data: any): void;
17
+ broadcast(event: keyof T, data: any): void;
18
+ selectiveBroascast(event: string, data: any, connections: string[]): void;
14
19
  get event(): { [K in keyof T as T[K] extends ZapServerEvent<any> ? K : never]: {
15
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;
16
22
  }; };
23
+ get clients(): Set<string>;
24
+ get socketMap(): Map<string, WebSocket>;
17
25
  }
18
26
  export declare const createZapServer: <T extends EventMap>({ port, events }: ZapServerConstructorT, callback?: () => void) => ZapServer<T>;
19
27
  export {};
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { WebSocketServer } from "ws";
2
2
  import { serialize, deserialize, generateId } from "./utils";
3
- const isZapEvent = (event) => {
4
- return "process" in event;
3
+ const isClientEvent = (event) => {
4
+ return "process" in event; // both zapEvent and zapStream have process in them.
5
5
  };
6
6
  export class ZapServer {
7
7
  wss;
@@ -29,13 +29,13 @@ export class ZapServer {
29
29
  }
30
30
  const clientId = this.wsToId.get(ws);
31
31
  for (const [event, eventObj] of Object.entries(this._events)) {
32
- if (!isZapEvent(eventObj))
33
- continue; // skip server events
32
+ if (!isClientEvent(eventObj))
33
+ continue;
34
34
  const { process, middleware } = eventObj;
35
35
  const parsedMessage = deserialize(message.toString());
36
36
  if (parsedMessage &&
37
- parsedMessage["event"] === event) {
38
- const { data, requestId } = parsedMessage;
37
+ (parsedMessage["event"] === event || parsedMessage["stream"] === event)) {
38
+ const { data, requestId, streamId } = parsedMessage;
39
39
  // Do middleware checks
40
40
  const ctx = {};
41
41
  if (middleware) {
@@ -57,13 +57,32 @@ export class ZapServer {
57
57
  });
58
58
  }
59
59
  // By this point all the middlewares allow to pass through
60
- const result = process(data, { server: this, id: this.wsToId.get(ws), buffer: ctx });
61
- const serialized = serialize({ requestId, event, data: result });
62
- // TODO: throw some nice error: only return stuff that is serializable
63
- // i.e. primary data types and objects
64
- if (!serialized)
65
- return;
66
- ws.send(serialized);
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();
85
+ }
67
86
  return; // finally return to avoid looping through rest of events unneccessarily
68
87
  }
69
88
  }
@@ -94,6 +113,60 @@ export class ZapServer {
94
113
  return;
95
114
  ws.send(serializedData);
96
115
  }
116
+ sendMessage(event, clientId, data) {
117
+ const ws = this.idToWs.get(clientId);
118
+ // TODO: throw a nice error
119
+ if (!ws)
120
+ return;
121
+ const packet = {
122
+ event,
123
+ data
124
+ };
125
+ const serializedPacket = serialize(packet);
126
+ // TODO: throw a nice error
127
+ if (!serializedPacket)
128
+ return;
129
+ ws.send(serializedPacket);
130
+ }
131
+ broadcastRaw(data) {
132
+ const serializedData = serialize(data);
133
+ if (!serializedData) {
134
+ // TODO: throw a nice error
135
+ return;
136
+ }
137
+ this.idToWs.forEach((ws) => {
138
+ ws.send(serializedData);
139
+ });
140
+ }
141
+ broadcast(event, data) {
142
+ const packet = {
143
+ event,
144
+ data
145
+ };
146
+ const serializedPacket = serialize(packet);
147
+ if (!serializedPacket)
148
+ return;
149
+ this.idToWs.forEach((ws) => {
150
+ ws.send(serializedPacket);
151
+ });
152
+ }
153
+ selectiveBroascast(event, data, connections) {
154
+ const serialized = serialize(data);
155
+ if (!serialized) {
156
+ // TODO: throw a nice error
157
+ return;
158
+ }
159
+ const packet = {
160
+ event,
161
+ data
162
+ };
163
+ const serializedPacket = serialize(packet); // if data is serializable then packet is too, so no need to check
164
+ connections
165
+ .flatMap(x => this.idToWs.get(x) ?? [])
166
+ .forEach((ws) => {
167
+ ws.send(serializedPacket);
168
+ });
169
+ }
97
170
  get event() {
98
171
  return Object.fromEntries(Object.keys(this._events).map((eventName) => {
99
172
  // HACK: use a better method to determine the type of event.
@@ -106,12 +179,25 @@ export class ZapServer {
106
179
  data
107
180
  };
108
181
  this.sendMessageRaw(clientId, packet);
182
+ },
183
+ broadcast: (data) => {
184
+ const packet = {
185
+ event: eventName,
186
+ data
187
+ };
188
+ this.broadcastRaw(packet);
109
189
  }
110
190
  }];
111
191
  }
112
192
  return null;
113
193
  }).filter(entry => entry !== null));
114
194
  }
195
+ get clients() {
196
+ return new Set(this.idToWs.keys());
197
+ }
198
+ get socketMap() {
199
+ return this.idToWs;
200
+ }
115
201
  }
116
202
  export const createZapServer = ({ port, events }, callback) => {
117
203
  const server = new ZapServer({ port, events }, callback);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-socket/server",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
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.2",
26
+ "@zap-socket/types": "^0.0.3",
27
27
  "zod": "^3.24.2"
28
28
  }
29
29
  }