@derivation/rpc 0.1.6 → 0.1.7

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.
Files changed (40) hide show
  1. package/dist/client-handler.d.ts +8 -7
  2. package/dist/client-handler.js +16 -10
  3. package/dist/client.d.ts +3 -2
  4. package/dist/client.js +7 -7
  5. package/dist/index.d.ts +4 -4
  6. package/dist/index.js +4 -4
  7. package/dist/iso.d.ts +1 -1
  8. package/dist/iso.js +1 -1
  9. package/dist/messageport-transport.d.ts +13 -0
  10. package/dist/messageport-transport.js +28 -0
  11. package/dist/node-web-socket-transport.d.ts +16 -0
  12. package/dist/node-web-socket-transport.js +33 -0
  13. package/dist/queue.d.ts +9 -0
  14. package/dist/queue.js +32 -0
  15. package/dist/rate-limiter.d.ts +1 -1
  16. package/dist/rate-limiter.js +13 -8
  17. package/dist/reactive-map-adapter.d.ts +2 -1
  18. package/dist/reactive-map-adapter.js +2 -1
  19. package/dist/reactive-set-adapter.d.ts +2 -1
  20. package/dist/reactive-set-adapter.js +2 -1
  21. package/dist/shared-worker-client-handler.d.ts +27 -0
  22. package/dist/shared-worker-client-handler.js +149 -0
  23. package/dist/shared-worker-client.d.ts +22 -0
  24. package/dist/shared-worker-client.js +25 -0
  25. package/dist/shared-worker-server.d.ts +28 -0
  26. package/dist/shared-worker-server.js +62 -0
  27. package/dist/stream-adapter.js +2 -1
  28. package/dist/stream-types.d.ts +4 -4
  29. package/dist/transport.d.ts +27 -0
  30. package/dist/transport.js +1 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/web-socket-server.d.ts +11 -0
  33. package/dist/web-socket-server.js +59 -0
  34. package/dist/web-socket-transport.d.ts +13 -0
  35. package/dist/web-socket-transport.js +25 -0
  36. package/dist/websocket-server.d.ts +8 -2
  37. package/dist/websocket-server.js +29 -5
  38. package/dist/websocket-transport.d.ts +28 -0
  39. package/dist/websocket-transport.js +58 -0
  40. package/package.json +23 -2
@@ -0,0 +1,59 @@
1
+ import { parse } from "url";
2
+ import { WebSocketServer } from "ws";
3
+ import { ClientHandler } from "./client-handler";
4
+ import WeakList from "./weak-list";
5
+ import { NodeWebSocketTransport } from "./node-web-socket-transport";
6
+ export function setupWebSocketServer(graph, server, streamEndpoints, mutationEndpoints, options) {
7
+ const { createContext, presenceHandler, path = "/api/ws" } = options;
8
+ const clients = new WeakList();
9
+ graph.afterStep(() => {
10
+ for (const client of clients) {
11
+ client.handleStep();
12
+ }
13
+ });
14
+ const wss = new WebSocketServer({ noServer: true, maxPayload: 100 * 1024 });
15
+ // Handle WebSocket connections for reactive streams
16
+ wss.on("connection", (ws, req) => {
17
+ const { pathname } = parse(req.url || "/", true);
18
+ if (pathname === path) {
19
+ const messageBuffer = [];
20
+ let client = null;
21
+ // Set up temporary message handler to buffer messages
22
+ const tempMessageHandler = (msg) => {
23
+ messageBuffer.push(msg);
24
+ };
25
+ ws.on("message", tempMessageHandler);
26
+ // Create context (handle both sync and async)
27
+ Promise.resolve(createContext(ws, req))
28
+ .then((context) => {
29
+ // Remove temporary handler
30
+ ws.removeListener("message", tempMessageHandler);
31
+ // Create transport and client handler
32
+ const transport = new NodeWebSocketTransport(ws);
33
+ client = new ClientHandler(transport, context, streamEndpoints, mutationEndpoints, presenceHandler);
34
+ clients.add(client);
35
+ // Process buffered messages
36
+ for (const msg of messageBuffer) {
37
+ client.handleMessage(msg.toString());
38
+ }
39
+ messageBuffer.length = 0;
40
+ })
41
+ .catch((err) => {
42
+ console.error("Error creating context:", err);
43
+ ws.close();
44
+ });
45
+ }
46
+ });
47
+ // Handle HTTP upgrade (for /api/ws)
48
+ server.on("upgrade", (req, socket, head) => {
49
+ const { pathname } = parse(req.url || "/", true);
50
+ if (pathname === "/api/ws") {
51
+ wss.handleUpgrade(req, socket, head, (ws) => {
52
+ wss.emit("connection", ws, req);
53
+ });
54
+ }
55
+ else {
56
+ socket.destroy();
57
+ }
58
+ });
59
+ }
@@ -0,0 +1,13 @@
1
+ import { Transport } from "./transport";
2
+ /**
3
+ * Transport implementation for browser WebSocket (client-side).
4
+ */
5
+ export declare class WebSocketTransport implements Transport {
6
+ private ws;
7
+ constructor(ws: globalThis.WebSocket);
8
+ send(data: string): void;
9
+ onMessage(handler: (data: string) => void): void;
10
+ onClose(handler: () => void): void;
11
+ close(): void;
12
+ get bufferedAmount(): number;
13
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Transport implementation for browser WebSocket (client-side).
3
+ */
4
+ export class WebSocketTransport {
5
+ constructor(ws) {
6
+ this.ws = ws;
7
+ }
8
+ send(data) {
9
+ this.ws.send(data);
10
+ }
11
+ onMessage(handler) {
12
+ this.ws.onmessage = (event) => {
13
+ handler(event.data);
14
+ };
15
+ }
16
+ onClose(handler) {
17
+ this.ws.onclose = handler;
18
+ }
19
+ close() {
20
+ this.ws.close();
21
+ }
22
+ get bufferedAmount() {
23
+ return this.ws.bufferedAmount;
24
+ }
25
+ }
@@ -1,5 +1,11 @@
1
- import { Server } from "http";
1
+ import { Server, IncomingMessage } from "http";
2
+ import { WebSocket } from "ws";
2
3
  import { StreamEndpoints, MutationEndpoints, RPCDefinition } from "./stream-types";
3
4
  import { Graph } from "derivation";
4
5
  import { PresenceHandler } from "./presence-manager";
5
- export declare function setupWebSocketServer<Defs extends RPCDefinition>(graph: Graph, server: Server, streamEndpoints: StreamEndpoints<Defs["streams"]>, mutationEndpoints: MutationEndpoints<Defs["mutations"]>, presenceHandler?: PresenceHandler, path?: string): void;
6
+ export type WebSocketServerOptions<Ctx> = {
7
+ createContext: (ws: WebSocket, req: IncomingMessage) => Ctx | Promise<Ctx>;
8
+ presenceHandler?: PresenceHandler;
9
+ path?: string;
10
+ };
11
+ export declare function setupWebSocketServer<Defs extends RPCDefinition, Ctx = void>(graph: Graph, server: Server, streamEndpoints: StreamEndpoints<Defs["streams"], Ctx>, mutationEndpoints: MutationEndpoints<Defs["mutations"], Ctx>, options: WebSocketServerOptions<Ctx>): void;
@@ -2,7 +2,9 @@ import { parse } from "url";
2
2
  import { WebSocketServer } from "ws";
3
3
  import { ClientHandler } from "./client-handler";
4
4
  import WeakList from "./weak-list";
5
- export function setupWebSocketServer(graph, server, streamEndpoints, mutationEndpoints, presenceHandler, path = "/api/ws") {
5
+ import { NodeWebSocketTransport } from "./websocket-transport";
6
+ export function setupWebSocketServer(graph, server, streamEndpoints, mutationEndpoints, options) {
7
+ const { createContext, presenceHandler, path = "/api/ws" } = options;
6
8
  const clients = new WeakList();
7
9
  graph.afterStep(() => {
8
10
  for (const client of clients) {
@@ -14,10 +16,32 @@ export function setupWebSocketServer(graph, server, streamEndpoints, mutationEnd
14
16
  wss.on("connection", (ws, req) => {
15
17
  const { pathname } = parse(req.url || "/", true);
16
18
  if (pathname === path) {
17
- const client = new ClientHandler(ws, streamEndpoints, mutationEndpoints, presenceHandler);
18
- clients.add(client);
19
- ws.on("message", (msg) => client.handleMessage(msg));
20
- ws.on("close", () => client.handleDisconnect());
19
+ const messageBuffer = [];
20
+ let client = null;
21
+ // Set up temporary message handler to buffer messages
22
+ const tempMessageHandler = (msg) => {
23
+ messageBuffer.push(msg);
24
+ };
25
+ ws.on("message", tempMessageHandler);
26
+ // Create context (handle both sync and async)
27
+ Promise.resolve(createContext(ws, req))
28
+ .then((context) => {
29
+ // Remove temporary handler
30
+ ws.removeListener("message", tempMessageHandler);
31
+ // Create transport and client handler
32
+ const transport = new NodeWebSocketTransport(ws);
33
+ client = new ClientHandler(transport, context, streamEndpoints, mutationEndpoints, presenceHandler);
34
+ clients.add(client);
35
+ // Process buffered messages
36
+ for (const msg of messageBuffer) {
37
+ client.handleMessage(msg.toString());
38
+ }
39
+ messageBuffer.length = 0;
40
+ })
41
+ .catch((err) => {
42
+ console.error("Error creating context:", err);
43
+ ws.close();
44
+ });
21
45
  }
22
46
  });
23
47
  // Handle HTTP upgrade (for /api/ws)
@@ -0,0 +1,28 @@
1
+ import { WebSocket } from "ws";
2
+ import { Transport } from "./transport";
3
+ /**
4
+ * Transport implementation for Node.js WebSocket (server-side using 'ws' library).
5
+ */
6
+ export declare class NodeWebSocketTransport implements Transport {
7
+ private ws;
8
+ private messageHandlerSet;
9
+ private closeHandlerSet;
10
+ constructor(ws: WebSocket);
11
+ send(data: string): void;
12
+ onMessage(handler: (data: string) => void): void;
13
+ onClose(handler: () => void): void;
14
+ close(): void;
15
+ get bufferedAmount(): number;
16
+ }
17
+ /**
18
+ * Transport implementation for browser WebSocket (client-side).
19
+ */
20
+ export declare class WebSocketTransport implements Transport {
21
+ private ws;
22
+ constructor(ws: globalThis.WebSocket);
23
+ send(data: string): void;
24
+ onMessage(handler: (data: string) => void): void;
25
+ onClose(handler: () => void): void;
26
+ close(): void;
27
+ get bufferedAmount(): number;
28
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Transport implementation for Node.js WebSocket (server-side using 'ws' library).
3
+ */
4
+ export class NodeWebSocketTransport {
5
+ constructor(ws) {
6
+ this.ws = ws;
7
+ this.messageHandlerSet = false;
8
+ this.closeHandlerSet = false;
9
+ }
10
+ send(data) {
11
+ this.ws.send(data);
12
+ }
13
+ onMessage(handler) {
14
+ if (!this.messageHandlerSet) {
15
+ this.ws.on("message", (data) => {
16
+ handler(data.toString());
17
+ });
18
+ this.messageHandlerSet = true;
19
+ }
20
+ }
21
+ onClose(handler) {
22
+ if (!this.closeHandlerSet) {
23
+ this.ws.on("close", handler);
24
+ this.closeHandlerSet = true;
25
+ }
26
+ }
27
+ close() {
28
+ this.ws.close();
29
+ }
30
+ get bufferedAmount() {
31
+ return this.ws.bufferedAmount;
32
+ }
33
+ }
34
+ /**
35
+ * Transport implementation for browser WebSocket (client-side).
36
+ */
37
+ export class WebSocketTransport {
38
+ constructor(ws) {
39
+ this.ws = ws;
40
+ }
41
+ send(data) {
42
+ this.ws.send(data);
43
+ }
44
+ onMessage(handler) {
45
+ this.ws.onmessage = (event) => {
46
+ handler(event.data);
47
+ };
48
+ }
49
+ onClose(handler) {
50
+ this.ws.onclose = handler;
51
+ }
52
+ close() {
53
+ this.ws.close();
54
+ }
55
+ get bufferedAmount() {
56
+ return this.ws.bufferedAmount;
57
+ }
58
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@derivation/rpc",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "homepage": "https://github.com/derivationjs/rpc",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,6 +20,26 @@
20
20
  "./iso": {
21
21
  "types": "./dist/iso.d.ts",
22
22
  "import": "./dist/iso.js"
23
+ },
24
+ "./worker": {
25
+ "types": "./dist/shared-worker-server.d.ts",
26
+ "import": "./dist/shared-worker-server.js"
27
+ },
28
+ "./client": {
29
+ "types": "./dist/shared-worker-client.d.ts",
30
+ "import": "./dist/shared-worker-client.js"
31
+ },
32
+ "./transport": {
33
+ "types": "./dist/transport.d.ts",
34
+ "import": "./dist/transport.js"
35
+ },
36
+ "./browser": {
37
+ "types": "./dist/web-socket-transport.d.ts",
38
+ "import": "./dist/web-socket-transport.js"
39
+ },
40
+ "./server": {
41
+ "types": "./dist/web-socket-server.d.ts",
42
+ "import": "./dist/web-socket-server.js"
23
43
  }
24
44
  },
25
45
  "files": [
@@ -34,7 +54,8 @@
34
54
  "dependencies": {
35
55
  "@types/node": "^25.0.3",
36
56
  "@types/ws": "^8.18.1",
37
- "derivation": "^0.1.6",
57
+ "derivation": "^0.1.7",
58
+ "@derivation/relational": "^0.1.7",
38
59
  "immutable": "^5.1.4",
39
60
  "ws": "^8.18.3",
40
61
  "zod": "^4.3.3"