@sylphx/lens-server 1.0.3 → 1.2.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.
- package/dist/index.d.ts +509 -9
- package/dist/index.js +269 -295
- package/package.json +3 -4
- package/src/e2e/server.test.ts +10 -10
- package/src/server/create.test.ts +11 -11
- package/src/server/create.ts +46 -20
- package/src/state/graph-state-manager.test.ts +215 -0
- package/src/state/graph-state-manager.ts +423 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/server/create.d.ts +0 -226
- package/dist/server/create.d.ts.map +0 -1
- package/dist/sse/handler.d.ts +0 -78
- package/dist/sse/handler.d.ts.map +0 -1
- package/dist/state/graph-state-manager.d.ts +0 -146
- package/dist/state/graph-state-manager.d.ts.map +0 -1
- package/dist/state/index.d.ts +0 -7
- package/dist/state/index.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,510 @@
|
|
|
1
|
+
import { ContextValue, EntityDef, EntityDefinition, EntityResolvers, EntityResolversDefinition, MutationDef, QueryDef, RelationDef, RelationTypeWithForeignKey, RouterDef } from "@sylphx/lens-core";
|
|
2
|
+
import { EntityKey, Update, EmitCommand, InternalFieldUpdate, ArrayOperation } from "@sylphx/lens-core";
|
|
3
|
+
/** Client connection interface */
|
|
4
|
+
interface StateClient {
|
|
5
|
+
id: string;
|
|
6
|
+
send: (message: StateUpdateMessage) => void;
|
|
7
|
+
}
|
|
8
|
+
/** Update message sent to clients */
|
|
9
|
+
interface StateUpdateMessage {
|
|
10
|
+
type: "update";
|
|
11
|
+
entity: string;
|
|
12
|
+
id: string;
|
|
13
|
+
/** Field-level updates with strategy */
|
|
14
|
+
updates: Record<string, Update>;
|
|
15
|
+
}
|
|
16
|
+
/** Full entity update message */
|
|
17
|
+
interface StateFullMessage {
|
|
18
|
+
type: "data";
|
|
19
|
+
entity: string;
|
|
20
|
+
id: string;
|
|
21
|
+
data: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
/** Subscription info */
|
|
24
|
+
interface Subscription {
|
|
25
|
+
clientId: string;
|
|
26
|
+
fields: Set<string> | "*";
|
|
27
|
+
}
|
|
28
|
+
/** Configuration */
|
|
29
|
+
interface GraphStateManagerConfig {
|
|
30
|
+
/** Called when an entity has no more subscribers */
|
|
31
|
+
onEntityUnsubscribed?: (entity: string, id: string) => void;
|
|
32
|
+
}
|
|
1
33
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
34
|
+
* Manages server-side canonical state and syncs to clients.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const manager = new GraphStateManager();
|
|
39
|
+
*
|
|
40
|
+
* // Add client
|
|
41
|
+
* manager.addClient({
|
|
42
|
+
* id: "client-1",
|
|
43
|
+
* send: (msg) => ws.send(JSON.stringify(msg)),
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* // Subscribe client to entity
|
|
47
|
+
* manager.subscribe("client-1", "Post", "123", ["title", "content"]);
|
|
48
|
+
*
|
|
49
|
+
* // Emit updates (from resolvers)
|
|
50
|
+
* manager.emit("Post", "123", { content: "Updated content" });
|
|
51
|
+
* // → Automatically computes diff and sends to subscribed clients
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare class GraphStateManager {
|
|
55
|
+
/** Connected clients */
|
|
56
|
+
private clients;
|
|
57
|
+
/** Canonical state per entity (server truth) */
|
|
58
|
+
private canonical;
|
|
59
|
+
/** Canonical array state per entity (server truth for array outputs) */
|
|
60
|
+
private canonicalArrays;
|
|
61
|
+
/** Per-client state tracking */
|
|
62
|
+
private clientStates;
|
|
63
|
+
/** Per-client array state tracking */
|
|
64
|
+
private clientArrayStates;
|
|
65
|
+
/** Entity → subscribed client IDs */
|
|
66
|
+
private entitySubscribers;
|
|
67
|
+
/** Configuration */
|
|
68
|
+
private config;
|
|
69
|
+
constructor(config?: GraphStateManagerConfig);
|
|
70
|
+
/**
|
|
71
|
+
* Add a client connection
|
|
72
|
+
*/
|
|
73
|
+
addClient(client: StateClient): void;
|
|
74
|
+
/**
|
|
75
|
+
* Remove a client and cleanup all subscriptions
|
|
76
|
+
*/
|
|
77
|
+
removeClient(clientId: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Subscribe a client to an entity
|
|
80
|
+
*/
|
|
81
|
+
subscribe(clientId: string, entity: string, id: string, fields?: string[] | "*"): void;
|
|
82
|
+
/**
|
|
83
|
+
* Unsubscribe a client from an entity
|
|
84
|
+
*/
|
|
85
|
+
unsubscribe(clientId: string, entity: string, id: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Update subscription fields for a client
|
|
88
|
+
*/
|
|
89
|
+
updateSubscription(clientId: string, entity: string, id: string, fields: string[] | "*"): void;
|
|
90
|
+
/**
|
|
91
|
+
* Emit data for an entity.
|
|
92
|
+
* This is the core method called by resolvers.
|
|
93
|
+
*
|
|
94
|
+
* @param entity - Entity name
|
|
95
|
+
* @param id - Entity ID
|
|
96
|
+
* @param data - Full or partial entity data
|
|
97
|
+
* @param options - Emit options
|
|
98
|
+
*/
|
|
99
|
+
emit(entity: string, id: string, data: Record<string, unknown>, options?: {
|
|
100
|
+
replace?: boolean;
|
|
101
|
+
}): void;
|
|
102
|
+
/**
|
|
103
|
+
* Emit a field-level update with a specific strategy.
|
|
104
|
+
* Applies the update to canonical state and pushes to clients.
|
|
105
|
+
*
|
|
106
|
+
* @param entity - Entity name
|
|
107
|
+
* @param id - Entity ID
|
|
108
|
+
* @param field - Field name to update
|
|
109
|
+
* @param update - Update with strategy (value/delta/patch)
|
|
110
|
+
*/
|
|
111
|
+
emitField(entity: string, id: string, field: string, update: Update): void;
|
|
112
|
+
/**
|
|
113
|
+
* Emit multiple field updates in a batch.
|
|
114
|
+
* More efficient than multiple emitField calls.
|
|
115
|
+
*
|
|
116
|
+
* @param entity - Entity name
|
|
117
|
+
* @param id - Entity ID
|
|
118
|
+
* @param updates - Array of field updates
|
|
119
|
+
*/
|
|
120
|
+
emitBatch(entity: string, id: string, updates: InternalFieldUpdate[]): void;
|
|
121
|
+
/**
|
|
122
|
+
* Process an EmitCommand from the Emit API.
|
|
123
|
+
* Routes to appropriate emit method.
|
|
124
|
+
*
|
|
125
|
+
* @param entity - Entity name
|
|
126
|
+
* @param id - Entity ID
|
|
127
|
+
* @param command - Emit command from resolver
|
|
128
|
+
*/
|
|
129
|
+
processCommand(entity: string, id: string, command: EmitCommand): void;
|
|
130
|
+
/**
|
|
131
|
+
* Emit array data (replace entire array).
|
|
132
|
+
*
|
|
133
|
+
* @param entity - Entity name
|
|
134
|
+
* @param id - Entity ID
|
|
135
|
+
* @param items - Array items
|
|
136
|
+
*/
|
|
137
|
+
emitArray(entity: string, id: string, items: unknown[]): void;
|
|
138
|
+
/**
|
|
139
|
+
* Apply an array operation to the canonical state.
|
|
140
|
+
*
|
|
141
|
+
* @param entity - Entity name
|
|
142
|
+
* @param id - Entity ID
|
|
143
|
+
* @param operation - Array operation to apply
|
|
144
|
+
*/
|
|
145
|
+
emitArrayOperation(entity: string, id: string, operation: ArrayOperation): void;
|
|
146
|
+
/**
|
|
147
|
+
* Apply an array operation and return new array.
|
|
148
|
+
*/
|
|
149
|
+
private applyArrayOperation;
|
|
150
|
+
/**
|
|
151
|
+
* Push array update to a specific client.
|
|
152
|
+
* Computes optimal diff strategy.
|
|
153
|
+
*/
|
|
154
|
+
private pushArrayToClient;
|
|
155
|
+
/**
|
|
156
|
+
* Get current canonical array state
|
|
157
|
+
*/
|
|
158
|
+
getArrayState(entity: string, id: string): unknown[] | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Get current canonical state for an entity
|
|
161
|
+
*/
|
|
162
|
+
getState(entity: string, id: string): Record<string, unknown> | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Check if entity has any subscribers
|
|
165
|
+
*/
|
|
166
|
+
hasSubscribers(entity: string, id: string): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Push update to a specific client
|
|
169
|
+
*/
|
|
170
|
+
private pushToClient;
|
|
171
|
+
/**
|
|
172
|
+
* Push a single field update to a client.
|
|
173
|
+
* Computes optimal transfer strategy.
|
|
174
|
+
*/
|
|
175
|
+
private pushFieldToClient;
|
|
176
|
+
/**
|
|
177
|
+
* Push multiple field updates to a client.
|
|
178
|
+
* Computes optimal transfer strategy for each field.
|
|
179
|
+
*/
|
|
180
|
+
private pushFieldsToClient;
|
|
181
|
+
/**
|
|
182
|
+
* Send initial data to a newly subscribed client
|
|
183
|
+
*/
|
|
184
|
+
private sendInitialData;
|
|
185
|
+
/**
|
|
186
|
+
* Cleanup entity when no subscribers remain
|
|
187
|
+
*/
|
|
188
|
+
private cleanupEntity;
|
|
189
|
+
private makeKey;
|
|
190
|
+
/**
|
|
191
|
+
* Get statistics
|
|
192
|
+
*/
|
|
193
|
+
getStats(): {
|
|
194
|
+
clients: number;
|
|
195
|
+
entities: number;
|
|
196
|
+
totalSubscriptions: number;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Clear all state (for testing)
|
|
200
|
+
*/
|
|
201
|
+
clear(): void;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a GraphStateManager instance
|
|
205
|
+
*/
|
|
206
|
+
declare function createGraphStateManager(config?: GraphStateManagerConfig): GraphStateManager;
|
|
207
|
+
/** Selection object type for nested field selection */
|
|
208
|
+
interface SelectionObject {
|
|
209
|
+
[key: string]: boolean | SelectionObject | {
|
|
210
|
+
select: SelectionObject;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/** Entity map type */
|
|
214
|
+
type EntitiesMap = Record<string, EntityDef<string, any>>;
|
|
215
|
+
/** Queries map type */
|
|
216
|
+
type QueriesMap = Record<string, QueryDef<unknown, unknown>>;
|
|
217
|
+
/** Mutations map type */
|
|
218
|
+
type MutationsMap = Record<string, MutationDef<unknown, unknown>>;
|
|
219
|
+
/** Relations array type */
|
|
220
|
+
type RelationsArray = RelationDef<EntityDef<string, EntityDefinition>, Record<string, RelationTypeWithForeignKey>>[];
|
|
221
|
+
/** Operation metadata for handshake */
|
|
222
|
+
interface OperationMeta {
|
|
223
|
+
type: "query" | "mutation";
|
|
224
|
+
optimistic?: unknown;
|
|
225
|
+
}
|
|
226
|
+
/** Nested operations structure for handshake */
|
|
227
|
+
type OperationsMap = {
|
|
228
|
+
[key: string]: OperationMeta | OperationsMap;
|
|
229
|
+
};
|
|
230
|
+
/** Server configuration */
|
|
231
|
+
interface LensServerConfig<TContext extends ContextValue = ContextValue> {
|
|
232
|
+
/** Entity definitions */
|
|
233
|
+
entities?: EntitiesMap;
|
|
234
|
+
/** Relation definitions */
|
|
235
|
+
relations?: RelationsArray;
|
|
236
|
+
/** Router definition (namespaced operations) */
|
|
237
|
+
router?: RouterDef;
|
|
238
|
+
/** Query definitions (flat, legacy) */
|
|
239
|
+
queries?: QueriesMap;
|
|
240
|
+
/** Mutation definitions (flat, legacy) */
|
|
241
|
+
mutations?: MutationsMap;
|
|
242
|
+
/** Entity resolvers */
|
|
243
|
+
resolvers?: EntityResolvers<EntityResolversDefinition>;
|
|
244
|
+
/** Context factory */
|
|
245
|
+
context?: (req?: unknown) => TContext | Promise<TContext>;
|
|
246
|
+
/** Server version */
|
|
247
|
+
version?: string;
|
|
248
|
+
}
|
|
249
|
+
/** Server metadata for transport handshake */
|
|
250
|
+
interface ServerMetadata {
|
|
251
|
+
/** Server version */
|
|
252
|
+
version: string;
|
|
253
|
+
/** Operations metadata map */
|
|
254
|
+
operations: OperationsMap;
|
|
255
|
+
}
|
|
256
|
+
/** Operation for in-process transport */
|
|
257
|
+
interface LensOperation {
|
|
258
|
+
/** Operation path (e.g., 'user.get', 'session.create') */
|
|
259
|
+
path: string;
|
|
260
|
+
/** Operation input */
|
|
261
|
+
input?: unknown;
|
|
262
|
+
}
|
|
263
|
+
/** Result from operation execution */
|
|
264
|
+
interface LensResult<T = unknown> {
|
|
265
|
+
/** Success data */
|
|
266
|
+
data?: T;
|
|
267
|
+
/** Error if operation failed */
|
|
268
|
+
error?: Error;
|
|
269
|
+
}
|
|
270
|
+
/** Lens server interface */
|
|
271
|
+
interface LensServer {
|
|
272
|
+
/** Get server metadata for transport handshake */
|
|
273
|
+
getMetadata(): ServerMetadata;
|
|
274
|
+
/** Execute operation - auto-detects query vs mutation from registered operations */
|
|
275
|
+
execute(op: LensOperation): Promise<LensResult>;
|
|
276
|
+
/** Execute a query (one-time) */
|
|
277
|
+
executeQuery<
|
|
278
|
+
TInput,
|
|
279
|
+
TOutput
|
|
280
|
+
>(name: string, input?: TInput): Promise<TOutput>;
|
|
281
|
+
/** Execute a mutation */
|
|
282
|
+
executeMutation<
|
|
283
|
+
TInput,
|
|
284
|
+
TOutput
|
|
285
|
+
>(name: string, input: TInput): Promise<TOutput>;
|
|
286
|
+
/** Handle WebSocket connection */
|
|
287
|
+
handleWebSocket(ws: WebSocketLike): void;
|
|
288
|
+
/** Handle HTTP request */
|
|
289
|
+
handleRequest(req: Request): Promise<Response>;
|
|
290
|
+
/** Get GraphStateManager for external access */
|
|
291
|
+
getStateManager(): GraphStateManager;
|
|
292
|
+
/** Start server */
|
|
293
|
+
listen(port: number): Promise<void>;
|
|
294
|
+
/** Close server */
|
|
295
|
+
close(): Promise<void>;
|
|
296
|
+
}
|
|
297
|
+
/** WebSocket interface */
|
|
298
|
+
interface WebSocketLike {
|
|
299
|
+
send(data: string): void;
|
|
300
|
+
close(): void;
|
|
301
|
+
onmessage?: ((event: {
|
|
302
|
+
data: string;
|
|
303
|
+
}) => void) | null;
|
|
304
|
+
onclose?: (() => void) | null;
|
|
305
|
+
onerror?: ((error: unknown) => void) | null;
|
|
306
|
+
}
|
|
307
|
+
declare class LensServerImpl<
|
|
308
|
+
Q extends QueriesMap = QueriesMap,
|
|
309
|
+
M extends MutationsMap = MutationsMap,
|
|
310
|
+
TContext extends ContextValue = ContextValue
|
|
311
|
+
> implements LensServer {
|
|
312
|
+
private queries;
|
|
313
|
+
private mutations;
|
|
314
|
+
private entities;
|
|
315
|
+
private resolvers?;
|
|
316
|
+
private contextFactory;
|
|
317
|
+
private version;
|
|
318
|
+
private ctx;
|
|
319
|
+
/** GraphStateManager for per-client state tracking */
|
|
320
|
+
private stateManager;
|
|
321
|
+
/** DataLoaders for N+1 batching (per-request) */
|
|
322
|
+
private loaders;
|
|
323
|
+
/** Client connections */
|
|
324
|
+
private connections;
|
|
325
|
+
private connectionCounter;
|
|
326
|
+
/** Server instance */
|
|
327
|
+
private server;
|
|
328
|
+
constructor(config: LensServerConfig<TContext> & {
|
|
329
|
+
queries?: Q;
|
|
330
|
+
mutations?: M;
|
|
331
|
+
});
|
|
332
|
+
getStateManager(): GraphStateManager;
|
|
333
|
+
/**
|
|
334
|
+
* Get server metadata for transport handshake.
|
|
335
|
+
* Used by inProcess transport for direct access.
|
|
336
|
+
*/
|
|
337
|
+
getMetadata(): ServerMetadata;
|
|
338
|
+
/**
|
|
339
|
+
* Execute operation - auto-detects query vs mutation from registered operations.
|
|
340
|
+
* Used by inProcess transport for direct server calls.
|
|
341
|
+
*/
|
|
342
|
+
execute(op: LensOperation): Promise<LensResult>;
|
|
343
|
+
/**
|
|
344
|
+
* Build nested operations map for handshake response
|
|
345
|
+
* Converts flat "user.get", "user.create" into nested { user: { get: {...}, create: {...} } }
|
|
346
|
+
*/
|
|
347
|
+
private buildOperationsMap;
|
|
348
|
+
handleWebSocket(ws: WebSocketLike): void;
|
|
349
|
+
private handleMessage;
|
|
350
|
+
private handleHandshake;
|
|
351
|
+
private handleSubscribe;
|
|
352
|
+
private executeSubscription;
|
|
353
|
+
private handleUpdateFields;
|
|
354
|
+
private handleUnsubscribe;
|
|
355
|
+
private handleQuery;
|
|
356
|
+
private handleMutation;
|
|
357
|
+
private handleDisconnect;
|
|
358
|
+
executeQuery<
|
|
359
|
+
TInput,
|
|
360
|
+
TOutput
|
|
361
|
+
>(name: string, input?: TInput): Promise<TOutput>;
|
|
362
|
+
executeMutation<
|
|
363
|
+
TInput,
|
|
364
|
+
TOutput
|
|
365
|
+
>(name: string, input: TInput): Promise<TOutput>;
|
|
366
|
+
handleRequest(req: Request): Promise<Response>;
|
|
367
|
+
listen(port: number): Promise<void>;
|
|
368
|
+
close(): Promise<void>;
|
|
369
|
+
private findConnectionByWs;
|
|
370
|
+
private getEntityNameFromOutput;
|
|
371
|
+
private getEntityNameFromMutation;
|
|
372
|
+
private extractEntities;
|
|
373
|
+
private applySelection;
|
|
374
|
+
private applySelectionToObject;
|
|
375
|
+
/**
|
|
376
|
+
* Execute entity resolvers for nested data.
|
|
377
|
+
* Processes the selection object and resolves relation fields.
|
|
378
|
+
*/
|
|
379
|
+
private executeEntityResolvers;
|
|
380
|
+
/**
|
|
381
|
+
* Get target entity name for a relation field.
|
|
382
|
+
*/
|
|
383
|
+
private getRelationTargetEntity;
|
|
384
|
+
/**
|
|
385
|
+
* Serialize entity data for transport.
|
|
386
|
+
* Auto-calls serialize() on field types (Date → ISO string, etc.)
|
|
387
|
+
*/
|
|
388
|
+
private serializeEntity;
|
|
389
|
+
/**
|
|
390
|
+
* Process query result: execute entity resolvers, apply selection, serialize
|
|
391
|
+
*/
|
|
392
|
+
private processQueryResult;
|
|
393
|
+
private computeUpdates;
|
|
394
|
+
private deepEqual;
|
|
395
|
+
private clearLoaders;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Infer input type from a query/mutation definition
|
|
399
|
+
*/
|
|
400
|
+
type InferInput<T> = T extends QueryDef<infer I, unknown> ? I extends void ? void : I : T extends MutationDef<infer I, unknown> ? I : never;
|
|
401
|
+
/**
|
|
402
|
+
* Infer output type from a query/mutation definition
|
|
403
|
+
*/
|
|
404
|
+
type InferOutput<T> = T extends QueryDef<unknown, infer O> ? O : T extends MutationDef<unknown, infer O> ? O : never;
|
|
405
|
+
/**
|
|
406
|
+
* API type for client inference
|
|
407
|
+
* Export this type for client-side type safety
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* // Server
|
|
412
|
+
* const server = createLensServer({ queries, mutations });
|
|
413
|
+
* type Api = InferApi<typeof server>;
|
|
414
|
+
*
|
|
415
|
+
* // Client (only imports TYPE)
|
|
416
|
+
* import type { Api } from './server';
|
|
417
|
+
* const client = createClient<Api>({ links: [...] });
|
|
418
|
+
* ```
|
|
419
|
+
*/
|
|
420
|
+
type InferApi<T extends LensServer> = T extends LensServerImpl<infer Q, infer M> ? {
|
|
421
|
+
queries: Q;
|
|
422
|
+
mutations: M;
|
|
423
|
+
} : never;
|
|
424
|
+
/**
|
|
425
|
+
* Create Lens server with Operations API + Optimization Layer
|
|
426
|
+
*/
|
|
427
|
+
declare function createServer<
|
|
428
|
+
TContext extends ContextValue = ContextValue,
|
|
429
|
+
Q extends QueriesMap = QueriesMap,
|
|
430
|
+
M extends MutationsMap = MutationsMap
|
|
431
|
+
>(config: LensServerConfig<TContext> & {
|
|
432
|
+
queries?: Q;
|
|
433
|
+
mutations?: M;
|
|
434
|
+
}): LensServer & {
|
|
435
|
+
_types: {
|
|
436
|
+
queries: Q;
|
|
437
|
+
mutations: M;
|
|
438
|
+
};
|
|
439
|
+
};
|
|
440
|
+
/** SSE handler configuration */
|
|
441
|
+
interface SSEHandlerConfig {
|
|
442
|
+
/** GraphStateManager instance (required) */
|
|
443
|
+
stateManager: GraphStateManager;
|
|
444
|
+
/** Heartbeat interval in ms (default: 30000) */
|
|
445
|
+
heartbeatInterval?: number;
|
|
446
|
+
}
|
|
447
|
+
/** SSE client info */
|
|
448
|
+
interface SSEClientInfo {
|
|
449
|
+
id: string;
|
|
450
|
+
connectedAt: number;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* SSE transport adapter for GraphStateManager.
|
|
454
|
+
*
|
|
455
|
+
* This is a thin adapter that:
|
|
456
|
+
* - Creates SSE connections
|
|
457
|
+
* - Registers clients with GraphStateManager
|
|
458
|
+
* - Forwards updates to SSE streams
|
|
459
|
+
*
|
|
460
|
+
* All state/subscription logic is handled by GraphStateManager.
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* ```typescript
|
|
464
|
+
* const stateManager = new GraphStateManager();
|
|
465
|
+
* const sse = new SSEHandler({ stateManager });
|
|
466
|
+
*
|
|
467
|
+
* // Handle SSE connection
|
|
468
|
+
* app.get('/events', (req) => sse.handleConnection(req));
|
|
469
|
+
*
|
|
470
|
+
* // Subscribe via separate endpoint or message
|
|
471
|
+
* stateManager.subscribe(clientId, "Post", "123", "*");
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
declare class SSEHandler {
|
|
475
|
+
private stateManager;
|
|
476
|
+
private heartbeatInterval;
|
|
477
|
+
private clients;
|
|
478
|
+
private clientCounter;
|
|
479
|
+
constructor(config: SSEHandlerConfig);
|
|
480
|
+
/**
|
|
481
|
+
* Handle new SSE connection
|
|
482
|
+
* Returns a Response with SSE stream
|
|
483
|
+
*/
|
|
484
|
+
handleConnection(req?: Request): Response;
|
|
485
|
+
/**
|
|
486
|
+
* Remove client and cleanup
|
|
487
|
+
*/
|
|
488
|
+
private removeClient;
|
|
489
|
+
/**
|
|
490
|
+
* Close specific client connection
|
|
491
|
+
*/
|
|
492
|
+
closeClient(clientId: string): void;
|
|
493
|
+
/**
|
|
494
|
+
* Get connected client count
|
|
495
|
+
*/
|
|
496
|
+
getClientCount(): number;
|
|
497
|
+
/**
|
|
498
|
+
* Get connected client IDs
|
|
499
|
+
*/
|
|
500
|
+
getClientIds(): string[];
|
|
501
|
+
/**
|
|
502
|
+
* Close all connections
|
|
503
|
+
*/
|
|
504
|
+
closeAll(): void;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Create SSE handler (transport adapter)
|
|
508
|
+
*/
|
|
509
|
+
declare function createSSEHandler(config: SSEHandlerConfig): SSEHandler;
|
|
510
|
+
export { createServer, createSSEHandler, createGraphStateManager, WebSocketLike, Subscription, StateUpdateMessage, StateFullMessage, StateClient, ServerMetadata, LensServerConfig as ServerConfig, SelectionObject, SSEHandlerConfig, SSEHandler, SSEClientInfo, RelationsArray, QueriesMap, OperationsMap, OperationMeta, MutationsMap, LensServer, LensResult, LensOperation, InferOutput, InferInput, InferApi, GraphStateManagerConfig, GraphStateManager, EntityKey, EntitiesMap };
|