@sylphx/lens-server 1.11.2 → 2.0.1
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/index.d.ts +1244 -260
- package/dist/index.js +1700 -1158
- package/package.json +2 -2
- package/src/context/index.test.ts +425 -0
- package/src/context/index.ts +90 -0
- package/src/e2e/server.test.ts +215 -433
- package/src/handlers/framework.ts +294 -0
- package/src/handlers/http.test.ts +215 -0
- package/src/handlers/http.ts +189 -0
- package/src/handlers/index.ts +55 -0
- package/src/handlers/unified.ts +114 -0
- package/src/handlers/ws-types.ts +126 -0
- package/src/handlers/ws.ts +669 -0
- package/src/index.ts +127 -24
- package/src/plugin/index.ts +41 -0
- package/src/plugin/op-log.ts +286 -0
- package/src/plugin/optimistic.ts +375 -0
- package/src/plugin/types.ts +551 -0
- package/src/reconnect/index.ts +9 -0
- package/src/reconnect/operation-log.test.ts +480 -0
- package/src/reconnect/operation-log.ts +450 -0
- package/src/server/create.test.ts +256 -2193
- package/src/server/create.ts +285 -1481
- package/src/server/dataloader.ts +60 -0
- package/src/server/selection.ts +44 -0
- package/src/server/types.ts +289 -0
- package/src/sse/handler.ts +123 -56
- package/src/state/index.ts +9 -11
- package/src/storage/index.ts +26 -0
- package/src/storage/memory.ts +279 -0
- package/src/storage/types.ts +205 -0
- package/src/state/graph-state-manager.test.ts +0 -1105
- package/src/state/graph-state-manager.ts +0 -890
|
@@ -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
|
+
}
|