@sylphx/lens-server 1.11.3 → 2.1.0

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.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @sylphx/lens-server - Handlers
3
+ *
4
+ * Protocol handlers for bridging the Lens app to various transports.
5
+ */
6
+
7
+ // =============================================================================
8
+ // Unified Handler (HTTP + SSE)
9
+ // =============================================================================
10
+
11
+ export { createHandler, type Handler, type HandlerOptions } from "./unified.js";
12
+
13
+ // =============================================================================
14
+ // Framework Handler Utilities
15
+ // =============================================================================
16
+
17
+ export {
18
+ createFrameworkHandler,
19
+ createServerClientProxy,
20
+ type FrameworkHandlerOptions,
21
+ handleWebMutation,
22
+ handleWebQuery,
23
+ handleWebSSE,
24
+ } from "./framework.js";
25
+
26
+ // =============================================================================
27
+ // SSE Handler
28
+ // =============================================================================
29
+
30
+ export {
31
+ createSSEHandler,
32
+ type SSEClient,
33
+ SSEHandler,
34
+ type SSEHandlerConfig as SSEHandlerOptions,
35
+ } from "../sse/handler.js";
36
+
37
+ // =============================================================================
38
+ // HTTP Handler
39
+ // =============================================================================
40
+
41
+ export {
42
+ createHTTPHandler,
43
+ type HTTPHandler,
44
+ type HTTPHandlerOptions,
45
+ } from "./http.js";
46
+
47
+ // =============================================================================
48
+ // WebSocket Handler
49
+ // =============================================================================
50
+
51
+ export {
52
+ createWSHandler,
53
+ type WSHandler,
54
+ type WSHandlerOptions,
55
+ } from "./ws.js";
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @sylphx/lens-server - Unified Handler
3
+ *
4
+ * Creates a combined HTTP + SSE handler from a Lens app.
5
+ * Pure routing - no state management.
6
+ */
7
+
8
+ import type { LensServer } from "../server/create.js";
9
+ import { type SSEClient, SSEHandler } from "../sse/handler.js";
10
+ import { createHTTPHandler, type HTTPHandlerOptions } from "./http.js";
11
+
12
+ // =============================================================================
13
+ // Types
14
+ // =============================================================================
15
+
16
+ export interface HandlerOptions extends HTTPHandlerOptions {
17
+ /**
18
+ * SSE endpoint path.
19
+ * Default: "/__lens/sse"
20
+ */
21
+ ssePath?: string;
22
+
23
+ /**
24
+ * Heartbeat interval for SSE connections in ms.
25
+ * Default: 30000
26
+ */
27
+ heartbeatInterval?: number;
28
+ }
29
+
30
+ export interface Handler {
31
+ /**
32
+ * Handle HTTP/SSE request.
33
+ * Compatible with fetch API (Bun, Cloudflare Workers, Vercel).
34
+ */
35
+ (request: Request): Promise<Response>;
36
+
37
+ /**
38
+ * Alternative method-style call.
39
+ */
40
+ handle(request: Request): Promise<Response>;
41
+
42
+ /**
43
+ * Access the SSE handler for manual operations.
44
+ */
45
+ sse: SSEHandler;
46
+ }
47
+
48
+ // =============================================================================
49
+ // Unified Handler Factory
50
+ // =============================================================================
51
+
52
+ /**
53
+ * Create a unified HTTP + SSE handler from a Lens app.
54
+ *
55
+ * Automatically routes:
56
+ * - GET {ssePath} → SSE connection
57
+ * - Other requests → HTTP handler
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * import { createApp, createHandler } from '@sylphx/lens-server'
62
+ *
63
+ * const app = createApp({ router })
64
+ * const handler = createHandler(app)
65
+ *
66
+ * // Bun
67
+ * Bun.serve({ port: 3000, fetch: handler })
68
+ *
69
+ * // SSE endpoint: GET /__lens/sse
70
+ * // HTTP endpoints: POST /, GET /__lens/metadata
71
+ * ```
72
+ */
73
+ export function createHandler(server: LensServer, options: HandlerOptions = {}): Handler {
74
+ const { ssePath = "/__lens/sse", heartbeatInterval, ...httpOptions } = options;
75
+
76
+ const pathPrefix = httpOptions.pathPrefix ?? "";
77
+ const fullSsePath = `${pathPrefix}${ssePath}`;
78
+
79
+ // Create HTTP handler
80
+ const httpHandler = createHTTPHandler(server, httpOptions);
81
+
82
+ // Create SSE handler with plugin integration
83
+ const pluginManager = server.getPluginManager();
84
+ const sseHandler = new SSEHandler({
85
+ ...(heartbeatInterval !== undefined && { heartbeatInterval }),
86
+ onConnect: (client: SSEClient) => {
87
+ // Notify plugins of connection
88
+ pluginManager.runOnConnect({ clientId: client.id });
89
+ },
90
+ onDisconnect: (clientId: string) => {
91
+ // Notify plugins of disconnection
92
+ pluginManager.runOnDisconnect({ clientId, subscriptionCount: 0 });
93
+ },
94
+ });
95
+
96
+ const handler = async (request: Request): Promise<Response> => {
97
+ const url = new URL(request.url);
98
+
99
+ // Route SSE requests
100
+ if (request.method === "GET" && url.pathname === fullSsePath) {
101
+ return sseHandler.handleConnection(request);
102
+ }
103
+
104
+ // All other requests go to HTTP handler
105
+ return httpHandler(request);
106
+ };
107
+
108
+ // Make it callable as both function and object
109
+ const result = handler as Handler;
110
+ result.handle = handler;
111
+ result.sse = sseHandler;
112
+
113
+ return result;
114
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @sylphx/lens-server - WebSocket Handler Types
3
+ *
4
+ * Type definitions for WebSocket protocol handling.
5
+ */
6
+
7
+ import type { ReconnectMessage } from "@sylphx/lens-core";
8
+ import type { SelectionObject, WebSocketLike } from "../server/create.js";
9
+
10
+ // =============================================================================
11
+ // Handler Types
12
+ // =============================================================================
13
+
14
+ export interface WSHandlerOptions {
15
+ /**
16
+ * Logger for debugging.
17
+ */
18
+ logger?: {
19
+ info?: (message: string, ...args: unknown[]) => void;
20
+ warn?: (message: string, ...args: unknown[]) => void;
21
+ error?: (message: string, ...args: unknown[]) => void;
22
+ };
23
+ }
24
+
25
+ /**
26
+ * WebSocket adapter for Bun's websocket handler.
27
+ */
28
+ export interface WSHandler {
29
+ /**
30
+ * Handle a new WebSocket connection.
31
+ * Call this when a WebSocket connection is established.
32
+ */
33
+ handleConnection(ws: WebSocketLike): void;
34
+
35
+ /**
36
+ * Bun-compatible websocket handler object.
37
+ * Use directly with Bun.serve({ websocket: wsHandler.handler })
38
+ */
39
+ handler: {
40
+ message(ws: unknown, message: string | Buffer): void;
41
+ close(ws: unknown): void;
42
+ open?(ws: unknown): void;
43
+ };
44
+
45
+ /**
46
+ * Close all connections and cleanup.
47
+ */
48
+ close(): Promise<void>;
49
+ }
50
+
51
+ // =============================================================================
52
+ // Protocol Messages
53
+ // =============================================================================
54
+
55
+ export interface SubscribeMessage {
56
+ type: "subscribe";
57
+ id: string;
58
+ operation: string;
59
+ input?: unknown;
60
+ fields: string[] | "*";
61
+ select?: SelectionObject;
62
+ }
63
+
64
+ export interface UpdateFieldsMessage {
65
+ type: "updateFields";
66
+ id: string;
67
+ addFields?: string[];
68
+ removeFields?: string[];
69
+ setFields?: string[];
70
+ }
71
+
72
+ export interface UnsubscribeMessage {
73
+ type: "unsubscribe";
74
+ id: string;
75
+ }
76
+
77
+ export interface QueryMessage {
78
+ type: "query";
79
+ id: string;
80
+ operation: string;
81
+ input?: unknown;
82
+ fields?: string[] | "*";
83
+ select?: SelectionObject;
84
+ }
85
+
86
+ export interface MutationMessage {
87
+ type: "mutation";
88
+ id: string;
89
+ operation: string;
90
+ input: unknown;
91
+ }
92
+
93
+ export interface HandshakeMessage {
94
+ type: "handshake";
95
+ id: string;
96
+ clientVersion?: string;
97
+ }
98
+
99
+ export type ClientMessage =
100
+ | SubscribeMessage
101
+ | UpdateFieldsMessage
102
+ | UnsubscribeMessage
103
+ | QueryMessage
104
+ | MutationMessage
105
+ | HandshakeMessage
106
+ | ReconnectMessage;
107
+
108
+ // =============================================================================
109
+ // Client Connection
110
+ // =============================================================================
111
+
112
+ export interface ClientConnection {
113
+ id: string;
114
+ ws: WebSocketLike;
115
+ subscriptions: Map<string, ClientSubscription>;
116
+ }
117
+
118
+ export interface ClientSubscription {
119
+ id: string;
120
+ operation: string;
121
+ input: unknown;
122
+ fields: string[] | "*";
123
+ entityKeys: Set<string>;
124
+ cleanups: (() => void)[];
125
+ lastData: unknown;
126
+ }