@derivation/rpc 0.1.5 → 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.
- package/dist/client-handler.d.ts +8 -7
- package/dist/client-handler.js +16 -10
- package/dist/client-message.d.ts +3 -3
- package/dist/client-message.js +3 -3
- package/dist/client.d.ts +3 -2
- package/dist/client.js +8 -8
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/iso.d.ts +1 -1
- package/dist/iso.js +1 -1
- package/dist/messageport-transport.d.ts +13 -0
- package/dist/messageport-transport.js +28 -0
- package/dist/node-web-socket-transport.d.ts +16 -0
- package/dist/node-web-socket-transport.js +33 -0
- package/dist/queue.d.ts +9 -0
- package/dist/queue.js +32 -0
- package/dist/rate-limiter.d.ts +1 -1
- package/dist/rate-limiter.js +13 -8
- package/dist/reactive-map-adapter.d.ts +2 -1
- package/dist/reactive-map-adapter.js +2 -1
- package/dist/reactive-set-adapter.d.ts +2 -1
- package/dist/reactive-set-adapter.js +2 -1
- package/dist/shared-worker-client-handler.d.ts +27 -0
- package/dist/shared-worker-client-handler.js +149 -0
- package/dist/shared-worker-client.d.ts +22 -0
- package/dist/shared-worker-client.js +25 -0
- package/dist/shared-worker-server.d.ts +28 -0
- package/dist/shared-worker-server.js +62 -0
- package/dist/stream-adapter.js +2 -1
- package/dist/stream-types.d.ts +7 -7
- package/dist/transport.d.ts +27 -0
- package/dist/transport.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web-socket-server.d.ts +11 -0
- package/dist/web-socket-server.js +59 -0
- package/dist/web-socket-transport.d.ts +13 -0
- package/dist/web-socket-transport.js +25 -0
- package/dist/websocket-server.d.ts +8 -2
- package/dist/websocket-server.js +29 -5
- package/dist/websocket-transport.d.ts +28 -0
- package/dist/websocket-transport.js +58 -0
- 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
|
|
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;
|
package/dist/websocket-server.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
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.
|
|
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"
|