@zap-socket/server 0.0.17 → 0.0.19

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,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { EventInput, ZapEvent, ZapStream, ZapServerEvent, MiddlewareType, MiddlwareContext } from "@zap-socket/types";
3
- import { ZapServer } from "./server";
3
+ import { ZapServer } from "./server.js";
4
4
  export type Context = {
5
5
  server: ZapServer<any>;
6
6
  id: string;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./events";
2
- export * from "./server";
1
+ export * from "./events.js";
2
+ export * from "./server.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from "./events";
2
- export * from "./server";
1
+ export * from "./events.js";
2
+ export * from "./server.js";
package/dist/server.d.ts CHANGED
@@ -25,11 +25,13 @@ export declare class ZapServer<T extends EventMap> {
25
25
  private onconnectHandler;
26
26
  private wsToId;
27
27
  private idToWs;
28
+ private persistantContext;
28
29
  private _events;
29
30
  private heartbeatMiss;
30
31
  constructor({ port, events, options }: ZapServerConstructorT, callback?: () => void);
31
32
  private removeClient;
32
33
  private heartbeat;
34
+ private handleMessage;
33
35
  sendMessageRaw(clientId: string, data: any): void;
34
36
  sendMessage(event: keyof T, clientId: string, data: any): void;
35
37
  broadcastRaw(data: any): void;
package/dist/server.js CHANGED
@@ -1,8 +1,12 @@
1
1
  import { WebSocketServer } from "ws";
2
- import { serialize, deserialize, generateId } from "./utils";
2
+ import { serialize, deserialize, generateId } from "./utils.js";
3
3
  const isClientEvent = (event) => {
4
4
  return "process" in event; // both zapEvent and zapStream have process in them.
5
5
  };
6
+ // make the server class abstracted away
7
+ // or atleast the ws interactions
8
+ // so that we can change the backends
9
+ // with ease (ws & uWebSocket).
6
10
  export class ZapServer {
7
11
  // public server: http.Server;
8
12
  wss;
@@ -10,41 +14,14 @@ export class ZapServer {
10
14
  onconnectHandler;
11
15
  wsToId;
12
16
  idToWs;
17
+ persistantContext;
13
18
  _events = {};
14
19
  heartbeatMiss = new Map();
15
20
  constructor({ port, events = {}, options }, callback) {
16
- // this.server = http.createServer((req, res) => {
17
- //
18
- // if (cors) {
19
- // const origin = req.headers.origin;
20
- //
21
- // if (origin && cors.origin && (cors.origin.includes(origin) || cors.origin.includes("*"))) {
22
- // res.setHeader('Access-Control-Allow-Origin', origin);
23
- // }
24
- // if (cors.methods) {
25
- // res.setHeader("Access-Control-Allow-Methods", cors.methods.join(", "));
26
- // }
27
- // if (cors.headers) {
28
- // res.setHeader("Access-Control-Allow-Headers", cors.headers.join(", "));
29
- // }
30
- // if (cors.credentials !== undefined) {
31
- // res.setHeader("Access-Control-Allow-Credentials", cors.credentials ? "true" : "false");
32
- // }
33
- // }
34
- //
35
- // // pre-flight response
36
- // if (req.method === "OPTIONS") {
37
- // res.writeHead(204);
38
- // res.end();
39
- // return;
40
- // }
41
- //
42
- // res.writeHead(404);
43
- // res.end();
44
- // });
45
21
  this.wss = new WebSocketServer({ port });
46
22
  this.wsToId = new Map();
47
23
  this.idToWs = new Map();
24
+ this.persistantContext = new Map();
48
25
  this._events = events;
49
26
  this.onconnectHandler = () => { };
50
27
  this.onconnect = (handler) => {
@@ -58,95 +35,8 @@ export class ZapServer {
58
35
  callback();
59
36
  });
60
37
  this.wss.on("connection", (ws, req) => {
61
- ws.on("message", async (message) => {
62
- const id = this.wsToId.get(ws);
63
- // setting up socket id
64
- if (!id && message.toString() === "OPEN") {
65
- const id = generateId();
66
- this.wsToId.set(ws, id);
67
- this.idToWs.set(id, ws);
68
- ws.send("ID " + id);
69
- this.onconnectHandler({
70
- id,
71
- ws
72
- });
73
- return;
74
- }
75
- else if (id && message.toString() === "heartbeat") {
76
- this.heartbeatMiss.set(id, 0);
77
- }
78
- const clientId = this.wsToId.get(ws);
79
- const parsedMessage = deserialize(message.toString());
80
- if (!parsedMessage)
81
- return;
82
- const { event, stream, data, requestId, streamId, batch } = parsedMessage;
83
- const key = event || stream;
84
- const eventObj = this._events[key];
85
- if (!eventObj || !isClientEvent(eventObj))
86
- return;
87
- // Type validation.
88
- const inputType = eventObj.input;
89
- const { success, error } = inputType.safeParse(data);
90
- if (!success && error) {
91
- // check if the message is of req-res
92
- if (requestId) {
93
- }
94
- return;
95
- }
96
- const { process, middleware } = eventObj;
97
- // Setup middleware context
98
- const ctx = {};
99
- if (middleware) {
100
- for (const m of middleware) {
101
- const metadata = {
102
- id: clientId,
103
- ip: req.socket.remoteAddress,
104
- timestamp: Date.now(),
105
- size: message.toString().length,
106
- };
107
- const msg = {
108
- event: key,
109
- data: parsedMessage,
110
- metadata,
111
- };
112
- let shouldPass = m(ctx, msg);
113
- shouldPass = shouldPass instanceof Promise ? await shouldPass : shouldPass;
114
- if (!shouldPass)
115
- return;
116
- }
117
- }
118
- // All middleware passed
119
- const context = { server: this, id: this.wsToId.get(ws), buffer: ctx };
120
- if (requestId) { // req-res premitive
121
- let result;
122
- if (batch) {
123
- result = data.map((part) => process(part, context));
124
- }
125
- else {
126
- result = process(data, context);
127
- if (result instanceof Promise) {
128
- result = await result;
129
- }
130
- }
131
- if (result === undefined) { // just ACK the request process returns nothing
132
- ws.send("ACK " + requestId);
133
- return;
134
- }
135
- const serialized = serialize({ requestId, event: key, data: result });
136
- if (!serialized)
137
- return;
138
- ws.send(serialized);
139
- }
140
- else if (streamId) { // stream premitive
141
- const consumeStream = async () => {
142
- const result = process(data, context);
143
- for await (const fragment of result) {
144
- this.sendMessageRaw(clientId, { streamId, fragment });
145
- }
146
- this.sendMessageRaw(clientId, { streamId, done: true });
147
- };
148
- consumeStream();
149
- }
38
+ ws.on("message", (message) => {
39
+ this.handleMessage(ws, req, message);
150
40
  });
151
41
  ws.on("close", () => {
152
42
  this.removeClient(ws);
@@ -178,6 +68,100 @@ export class ZapServer {
178
68
  });
179
69
  this.broadcastRaw("heartbeat");
180
70
  }
71
+ async handleMessage(ws, req, message) {
72
+ const id = this.wsToId.get(ws);
73
+ // setting up socket id
74
+ if (!id && message.toString() === "OPEN") {
75
+ const id = generateId();
76
+ this.wsToId.set(ws, id);
77
+ this.idToWs.set(id, ws);
78
+ ws.send("ID " + id);
79
+ this.onconnectHandler({
80
+ id,
81
+ ws
82
+ });
83
+ return;
84
+ }
85
+ else if (id && message.toString() === "heartbeat") {
86
+ this.heartbeatMiss.set(id, 0);
87
+ }
88
+ const clientId = this.wsToId.get(ws);
89
+ const parsedMessage = deserialize(message.toString());
90
+ if (!parsedMessage)
91
+ return;
92
+ const { event, stream, data, requestId, streamId, batch } = parsedMessage;
93
+ const key = event || stream;
94
+ const eventObj = this._events[key];
95
+ if (!eventObj || !isClientEvent(eventObj))
96
+ return;
97
+ // Type validation.
98
+ const inputType = eventObj.input;
99
+ const { success, error } = inputType.safeParse(data);
100
+ if (!success && error) {
101
+ // check if the message is of req-res
102
+ if (requestId) {
103
+ }
104
+ return;
105
+ }
106
+ const { process, middleware } = eventObj;
107
+ if (!id) {
108
+ ws.close();
109
+ return;
110
+ }
111
+ const buffer = this.persistantContext.get(id);
112
+ const ctx = { buffer };
113
+ if (middleware) {
114
+ for (const m of middleware) {
115
+ const metadata = {
116
+ id: clientId,
117
+ ip: req.socket.remoteAddress,
118
+ timestamp: Date.now(),
119
+ size: message.toString().length,
120
+ };
121
+ const msg = {
122
+ event: key,
123
+ data: parsedMessage,
124
+ metadata,
125
+ };
126
+ let shouldPass = m(ctx, msg);
127
+ shouldPass = shouldPass instanceof Promise ? await shouldPass : shouldPass;
128
+ if (!shouldPass)
129
+ return;
130
+ }
131
+ }
132
+ // All middleware passed
133
+ const context = { server: this, id: this.wsToId.get(ws), buffer: ctx };
134
+ if (requestId) { // req-res premitive
135
+ let result;
136
+ if (batch) {
137
+ result = data.map((part) => process(part, context));
138
+ }
139
+ else {
140
+ result = process(data, context);
141
+ if (result instanceof Promise) {
142
+ result = await result;
143
+ }
144
+ }
145
+ if (result === undefined) { // just ACK the request process returns nothing
146
+ ws.send("ACK " + requestId);
147
+ return;
148
+ }
149
+ const serialized = serialize({ requestId, event: key, data: result });
150
+ if (!serialized)
151
+ return;
152
+ ws.send(serialized);
153
+ }
154
+ else if (streamId) { // stream premitive
155
+ const consumeStream = async () => {
156
+ const result = process(data, context);
157
+ for await (const fragment of result) {
158
+ this.sendMessageRaw(clientId, { streamId, fragment });
159
+ }
160
+ this.sendMessageRaw(clientId, { streamId, done: true });
161
+ };
162
+ consumeStream();
163
+ }
164
+ }
181
165
  sendMessageRaw(clientId, data) {
182
166
  const ws = this.idToWs.get(clientId);
183
167
  // TODO: throw a nice error
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zap-socket/server",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
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",
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@zap-socket/types": "^0.0.9",
27
+ "uWebSockets.js": "uNetworking/uWebSockets.js#v20.51.0",
27
28
  "zod": "^3.24.2"
28
29
  }
29
30
  }