@rool-dev/client 0.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.
- package/README.md +186 -0
- package/dist/auth.d.ts +75 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +375 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +129 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +343 -0
- package/dist/client.js.map +1 -0
- package/dist/event-emitter.d.ts +38 -0
- package/dist/event-emitter.d.ts.map +1 -0
- package/dist/event-emitter.js +80 -0
- package/dist/event-emitter.js.map +1 -0
- package/dist/graph.d.ts +240 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +573 -0
- package/dist/graph.js.map +1 -0
- package/dist/graphql.d.ts +33 -0
- package/dist/graphql.d.ts.map +1 -0
- package/dist/graphql.js +269 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/media.d.ts +36 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +105 -0
- package/dist/media.js.map +1 -0
- package/dist/subscription.d.ts +30 -0
- package/dist/subscription.d.ts.map +1 -0
- package/dist/subscription.js +161 -0
- package/dist/subscription.js.map +1 -0
- package/dist/types.d.ts +180 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { EventEmitter } from './event-emitter.js';
|
|
2
|
+
import { RoolGraph } from './graph.js';
|
|
3
|
+
import type { RoolClientConfig, RoolClientEvents, RoolGraphInfo, Account, UserResult, UserInfo } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Rool Client - Manages authentication, graph lifecycle, and shared infrastructure.
|
|
6
|
+
*
|
|
7
|
+
* The client is lightweight - most graph operations happen on Graph instances
|
|
8
|
+
* obtained via openGraph() or createGraph().
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Authentication (login, logout, token management)
|
|
12
|
+
* - Graph lifecycle (list, open, create, delete)
|
|
13
|
+
* - Shared SSE subscription with event routing
|
|
14
|
+
* - Media operations
|
|
15
|
+
* - AI operations (promptGraph, image generation)
|
|
16
|
+
*/
|
|
17
|
+
export declare class RoolClient extends EventEmitter<RoolClientEvents> {
|
|
18
|
+
private config;
|
|
19
|
+
private authManager;
|
|
20
|
+
private graphqlClient;
|
|
21
|
+
private subscriptionManager;
|
|
22
|
+
private connectionId;
|
|
23
|
+
private subscribedGraphs;
|
|
24
|
+
constructor(config: RoolClientConfig);
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the client - should be called on app startup.
|
|
27
|
+
* Processes any auth callback in the URL and sets up auto-refresh.
|
|
28
|
+
* @returns true if an auth callback was processed
|
|
29
|
+
*/
|
|
30
|
+
initialize(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Clean up resources - call when destroying the client.
|
|
33
|
+
*/
|
|
34
|
+
destroy(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Initiate login by redirecting to auth page.
|
|
37
|
+
*/
|
|
38
|
+
login(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Logout - clear all tokens and state.
|
|
41
|
+
*/
|
|
42
|
+
logout(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Process auth callback from URL fragment.
|
|
45
|
+
* Called automatically by initialize(), but can be called manually.
|
|
46
|
+
*/
|
|
47
|
+
processAuthCallback(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Check if user is currently authenticated.
|
|
50
|
+
*/
|
|
51
|
+
isAuthenticated(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Get current access token.
|
|
54
|
+
* Returns undefined if not authenticated.
|
|
55
|
+
*/
|
|
56
|
+
getToken(): Promise<string | undefined>;
|
|
57
|
+
/**
|
|
58
|
+
* Get user info decoded from JWT token.
|
|
59
|
+
*/
|
|
60
|
+
getUser(): UserInfo;
|
|
61
|
+
/**
|
|
62
|
+
* List all graphs accessible to the user.
|
|
63
|
+
*/
|
|
64
|
+
listGraphs(): Promise<RoolGraphInfo[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Open an existing graph.
|
|
67
|
+
* Loads the graph data from the server and returns a Graph instance.
|
|
68
|
+
*/
|
|
69
|
+
openGraph(graphId: string): Promise<RoolGraph>;
|
|
70
|
+
/**
|
|
71
|
+
* Create a new graph.
|
|
72
|
+
* Creates on server and returns a Graph instance.
|
|
73
|
+
*/
|
|
74
|
+
createGraph(name?: string): Promise<RoolGraph>;
|
|
75
|
+
/**
|
|
76
|
+
* Delete a graph.
|
|
77
|
+
* Note: This does not affect any open Graph instances - they become stale.
|
|
78
|
+
*/
|
|
79
|
+
deleteGraph(graphId: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Get account info from server (plan, credits, etc).
|
|
82
|
+
*/
|
|
83
|
+
getAccount(): Promise<Account>;
|
|
84
|
+
/**
|
|
85
|
+
* Search for a user by email.
|
|
86
|
+
*/
|
|
87
|
+
searchUser(email: string): Promise<UserResult | null>;
|
|
88
|
+
private get mediaClient();
|
|
89
|
+
/**
|
|
90
|
+
* Subscribe to real-time events.
|
|
91
|
+
* Client receives graph lifecycle events; graph-level events are routed
|
|
92
|
+
* to subscribed Graph instances.
|
|
93
|
+
*/
|
|
94
|
+
subscribe(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Unsubscribe from real-time events.
|
|
97
|
+
*/
|
|
98
|
+
unsubscribe(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Check if currently subscribed to events.
|
|
101
|
+
*/
|
|
102
|
+
isSubscribed(): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Get the connection ID used for subscriptions.
|
|
105
|
+
* Events triggered by this connection won't be echoed back.
|
|
106
|
+
*/
|
|
107
|
+
getConnectionId(): string;
|
|
108
|
+
/**
|
|
109
|
+
* Generate a unique entity ID.
|
|
110
|
+
* 6-character alphanumeric string (62^6 = 56.8 billion possible values).
|
|
111
|
+
* Also available as top-level generateEntityId() export.
|
|
112
|
+
*/
|
|
113
|
+
static generateId(): string;
|
|
114
|
+
/**
|
|
115
|
+
* Execute an arbitrary GraphQL query or mutation.
|
|
116
|
+
* Use this escape hatch for app-specific operations not covered by the typed API.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const result = await client.graphql<{ lastMessages: Message[] }>(
|
|
120
|
+
* `query LastMessages($graphId: String!) { lastMessages(graphId: $graphId) }`,
|
|
121
|
+
* { graphId: 'abc123' }
|
|
122
|
+
* );
|
|
123
|
+
*/
|
|
124
|
+
graphql<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
125
|
+
private registerGraphForEvents;
|
|
126
|
+
private unregisterGraphFromEvents;
|
|
127
|
+
private handleGraphEvent;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,OAAO,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAEhB,aAAa,EAEb,OAAO,EACP,UAAU,EACV,QAAQ,EAET,MAAM,YAAY,CAAC;AASpB;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAC5D,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,MAAM,EAAE,gBAAgB;IA8BpC;;;;OAIG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACH,OAAO,IAAI,IAAI;IAiBf;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,MAAM,IAAI,IAAI;IAWd;;;OAGG;IACH,mBAAmB,IAAI,OAAO;IAI9B;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAI7C;;OAEG;IACH,OAAO,IAAI,QAAQ;IAQnB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAI5C;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAoBpD;;;OAGG;IACG,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAoBpD;;;OAGG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAIpC;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAQ3D,OAAO,KAAK,WAAW,GAKtB;IAMD;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBhC;;OAEG;IACH,WAAW,IAAI,IAAI;IAOnB;;OAEG;IACH,YAAY,IAAI,OAAO;IAQvB;;;OAGG;IACH,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM;IAI3B;;;;;;;;;OASG;IACG,OAAO,CAAC,CAAC,EACb,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,CAAC,CAAC;IAQb,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,gBAAgB;CA6DzB"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Rool Client
|
|
3
|
+
// Lightweight client for auth, graph lifecycle, and shared infrastructure
|
|
4
|
+
// =============================================================================
|
|
5
|
+
import { EventEmitter } from './event-emitter.js';
|
|
6
|
+
import { AuthManager } from './auth.js';
|
|
7
|
+
import { GraphQLClient } from './graphql.js';
|
|
8
|
+
import { SubscriptionManager } from './subscription.js';
|
|
9
|
+
import { MediaClient } from './media.js';
|
|
10
|
+
import { RoolGraph, generateEntityId } from './graph.js';
|
|
11
|
+
const DEFAULT_STORAGE_PREFIX = 'rool_';
|
|
12
|
+
/**
|
|
13
|
+
* Rool Client - Manages authentication, graph lifecycle, and shared infrastructure.
|
|
14
|
+
*
|
|
15
|
+
* The client is lightweight - most graph operations happen on Graph instances
|
|
16
|
+
* obtained via openGraph() or createGraph().
|
|
17
|
+
*
|
|
18
|
+
* Features:
|
|
19
|
+
* - Authentication (login, logout, token management)
|
|
20
|
+
* - Graph lifecycle (list, open, create, delete)
|
|
21
|
+
* - Shared SSE subscription with event routing
|
|
22
|
+
* - Media operations
|
|
23
|
+
* - AI operations (promptGraph, image generation)
|
|
24
|
+
*/
|
|
25
|
+
export class RoolClient extends EventEmitter {
|
|
26
|
+
config;
|
|
27
|
+
authManager;
|
|
28
|
+
graphqlClient;
|
|
29
|
+
subscriptionManager = null;
|
|
30
|
+
connectionId;
|
|
31
|
+
// Registry of open graphs for event routing
|
|
32
|
+
subscribedGraphs = new Map();
|
|
33
|
+
constructor(config) {
|
|
34
|
+
super();
|
|
35
|
+
this.config = {
|
|
36
|
+
baseUrl: config.baseUrl.replace(/\/+$/, ''), // Remove trailing slashes
|
|
37
|
+
storagePrefix: config.storagePrefix ?? DEFAULT_STORAGE_PREFIX,
|
|
38
|
+
};
|
|
39
|
+
this.connectionId = generateEntityId();
|
|
40
|
+
this.authManager = new AuthManager({
|
|
41
|
+
baseUrl: this.config.baseUrl,
|
|
42
|
+
storagePrefix: this.config.storagePrefix,
|
|
43
|
+
authProvider: config.authProvider,
|
|
44
|
+
onAuthStateChanged: (authenticated) => {
|
|
45
|
+
this.emit('authStateChanged', authenticated);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
this.graphqlClient = new GraphQLClient({
|
|
49
|
+
baseUrl: this.config.baseUrl,
|
|
50
|
+
authManager: this.authManager,
|
|
51
|
+
getConnectionId: () => this.connectionId,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ===========================================================================
|
|
55
|
+
// Initialization
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
/**
|
|
58
|
+
* Initialize the client - should be called on app startup.
|
|
59
|
+
* Processes any auth callback in the URL and sets up auto-refresh.
|
|
60
|
+
* @returns true if an auth callback was processed
|
|
61
|
+
*/
|
|
62
|
+
initialize() {
|
|
63
|
+
return this.authManager.initialize();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Clean up resources - call when destroying the client.
|
|
67
|
+
*/
|
|
68
|
+
destroy() {
|
|
69
|
+
this.authManager.destroy();
|
|
70
|
+
this.subscriptionManager?.destroy();
|
|
71
|
+
// Close all open graphs
|
|
72
|
+
for (const graph of this.subscribedGraphs.values()) {
|
|
73
|
+
graph.close();
|
|
74
|
+
}
|
|
75
|
+
this.subscribedGraphs.clear();
|
|
76
|
+
this.removeAllListeners();
|
|
77
|
+
}
|
|
78
|
+
// ===========================================================================
|
|
79
|
+
// Authentication
|
|
80
|
+
// ===========================================================================
|
|
81
|
+
/**
|
|
82
|
+
* Initiate login by redirecting to auth page.
|
|
83
|
+
*/
|
|
84
|
+
login() {
|
|
85
|
+
this.authManager.login();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Logout - clear all tokens and state.
|
|
89
|
+
*/
|
|
90
|
+
logout() {
|
|
91
|
+
this.authManager.logout();
|
|
92
|
+
this.unsubscribe();
|
|
93
|
+
// Close all open graphs
|
|
94
|
+
for (const graph of this.subscribedGraphs.values()) {
|
|
95
|
+
graph.close();
|
|
96
|
+
}
|
|
97
|
+
this.subscribedGraphs.clear();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Process auth callback from URL fragment.
|
|
101
|
+
* Called automatically by initialize(), but can be called manually.
|
|
102
|
+
*/
|
|
103
|
+
processAuthCallback() {
|
|
104
|
+
return this.authManager.processCallback();
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if user is currently authenticated.
|
|
108
|
+
*/
|
|
109
|
+
isAuthenticated() {
|
|
110
|
+
return this.authManager.isAuthenticated();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get current access token.
|
|
114
|
+
* Returns undefined if not authenticated.
|
|
115
|
+
*/
|
|
116
|
+
async getToken() {
|
|
117
|
+
return this.authManager.getToken();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get user info decoded from JWT token.
|
|
121
|
+
*/
|
|
122
|
+
getUser() {
|
|
123
|
+
return this.authManager.getUser();
|
|
124
|
+
}
|
|
125
|
+
// ===========================================================================
|
|
126
|
+
// Graph Lifecycle
|
|
127
|
+
// ===========================================================================
|
|
128
|
+
/**
|
|
129
|
+
* List all graphs accessible to the user.
|
|
130
|
+
*/
|
|
131
|
+
async listGraphs() {
|
|
132
|
+
return this.graphqlClient.listGraphs();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Open an existing graph.
|
|
136
|
+
* Loads the graph data from the server and returns a Graph instance.
|
|
137
|
+
*/
|
|
138
|
+
async openGraph(graphId) {
|
|
139
|
+
const [graphData, graphList] = await Promise.all([
|
|
140
|
+
this.graphqlClient.getGraph(graphId),
|
|
141
|
+
this.graphqlClient.listGraphs(),
|
|
142
|
+
]);
|
|
143
|
+
const graphInfo = graphList.find(g => g.id === graphId);
|
|
144
|
+
return new RoolGraph({
|
|
145
|
+
id: graphId,
|
|
146
|
+
name: graphInfo?.name ?? graphId,
|
|
147
|
+
role: graphInfo?.role ?? 'viewer',
|
|
148
|
+
initialData: graphData,
|
|
149
|
+
graphqlClient: this.graphqlClient,
|
|
150
|
+
mediaClient: this.mediaClient,
|
|
151
|
+
onRegisterForEvents: (id, graph) => this.registerGraphForEvents(id, graph),
|
|
152
|
+
onUnregisterFromEvents: (id) => this.unregisterGraphFromEvents(id),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create a new graph.
|
|
157
|
+
* Creates on server and returns a Graph instance.
|
|
158
|
+
*/
|
|
159
|
+
async createGraph(name) {
|
|
160
|
+
const graphId = generateEntityId();
|
|
161
|
+
const graphName = name ?? graphId;
|
|
162
|
+
const initialData = { nodes: {}, edges: {}, _meta: {} };
|
|
163
|
+
// Create on server
|
|
164
|
+
await this.graphqlClient.setGraph(graphId, initialData);
|
|
165
|
+
return new RoolGraph({
|
|
166
|
+
id: graphId,
|
|
167
|
+
name: graphName,
|
|
168
|
+
role: 'owner',
|
|
169
|
+
initialData,
|
|
170
|
+
graphqlClient: this.graphqlClient,
|
|
171
|
+
mediaClient: this.mediaClient,
|
|
172
|
+
onRegisterForEvents: (id, graph) => this.registerGraphForEvents(id, graph),
|
|
173
|
+
onUnregisterFromEvents: (id) => this.unregisterGraphFromEvents(id),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Delete a graph.
|
|
178
|
+
* Note: This does not affect any open Graph instances - they become stale.
|
|
179
|
+
*/
|
|
180
|
+
async deleteGraph(graphId) {
|
|
181
|
+
await this.graphqlClient.deleteGraph(graphId);
|
|
182
|
+
// Client-level event will be emitted via SSE subscription
|
|
183
|
+
}
|
|
184
|
+
// ===========================================================================
|
|
185
|
+
// User Operations
|
|
186
|
+
// ===========================================================================
|
|
187
|
+
/**
|
|
188
|
+
* Get account info from server (plan, credits, etc).
|
|
189
|
+
*/
|
|
190
|
+
async getAccount() {
|
|
191
|
+
return this.graphqlClient.getAccount();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Search for a user by email.
|
|
195
|
+
*/
|
|
196
|
+
async searchUser(email) {
|
|
197
|
+
return this.graphqlClient.searchUser(email);
|
|
198
|
+
}
|
|
199
|
+
// ===========================================================================
|
|
200
|
+
// Media Client (used internally by Graph instances)
|
|
201
|
+
// ===========================================================================
|
|
202
|
+
get mediaClient() {
|
|
203
|
+
return new MediaClient({
|
|
204
|
+
baseUrl: this.config.baseUrl,
|
|
205
|
+
authManager: this.authManager,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// ===========================================================================
|
|
209
|
+
// Subscriptions
|
|
210
|
+
// ===========================================================================
|
|
211
|
+
/**
|
|
212
|
+
* Subscribe to real-time events.
|
|
213
|
+
* Client receives graph lifecycle events; graph-level events are routed
|
|
214
|
+
* to subscribed Graph instances.
|
|
215
|
+
*/
|
|
216
|
+
async subscribe() {
|
|
217
|
+
if (this.subscriptionManager)
|
|
218
|
+
return;
|
|
219
|
+
this.subscriptionManager = new SubscriptionManager({
|
|
220
|
+
baseUrl: this.config.baseUrl,
|
|
221
|
+
authManager: this.authManager,
|
|
222
|
+
connectionId: this.connectionId,
|
|
223
|
+
onEvent: (event) => this.handleGraphEvent(event),
|
|
224
|
+
onConnectionStateChanged: (state) => {
|
|
225
|
+
this.emit('connectionStateChanged', state);
|
|
226
|
+
},
|
|
227
|
+
onError: (error) => {
|
|
228
|
+
this.emit('error', error, 'subscription');
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
await this.subscriptionManager.subscribe();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Unsubscribe from real-time events.
|
|
235
|
+
*/
|
|
236
|
+
unsubscribe() {
|
|
237
|
+
if (this.subscriptionManager) {
|
|
238
|
+
this.subscriptionManager.destroy();
|
|
239
|
+
this.subscriptionManager = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check if currently subscribed to events.
|
|
244
|
+
*/
|
|
245
|
+
isSubscribed() {
|
|
246
|
+
return this.subscriptionManager?.isSubscribed ?? false;
|
|
247
|
+
}
|
|
248
|
+
// ===========================================================================
|
|
249
|
+
// Utilities
|
|
250
|
+
// ===========================================================================
|
|
251
|
+
/**
|
|
252
|
+
* Get the connection ID used for subscriptions.
|
|
253
|
+
* Events triggered by this connection won't be echoed back.
|
|
254
|
+
*/
|
|
255
|
+
getConnectionId() {
|
|
256
|
+
return this.connectionId;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Generate a unique entity ID.
|
|
260
|
+
* 6-character alphanumeric string (62^6 = 56.8 billion possible values).
|
|
261
|
+
* Also available as top-level generateEntityId() export.
|
|
262
|
+
*/
|
|
263
|
+
static generateId() {
|
|
264
|
+
return generateEntityId();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Execute an arbitrary GraphQL query or mutation.
|
|
268
|
+
* Use this escape hatch for app-specific operations not covered by the typed API.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* const result = await client.graphql<{ lastMessages: Message[] }>(
|
|
272
|
+
* `query LastMessages($graphId: String!) { lastMessages(graphId: $graphId) }`,
|
|
273
|
+
* { graphId: 'abc123' }
|
|
274
|
+
* );
|
|
275
|
+
*/
|
|
276
|
+
async graphql(query, variables) {
|
|
277
|
+
return this.graphqlClient.query(query, variables);
|
|
278
|
+
}
|
|
279
|
+
// ===========================================================================
|
|
280
|
+
// Private Methods - Graph Registry
|
|
281
|
+
// ===========================================================================
|
|
282
|
+
registerGraphForEvents(graphId, graph) {
|
|
283
|
+
this.subscribedGraphs.set(graphId, graph);
|
|
284
|
+
}
|
|
285
|
+
unregisterGraphFromEvents(graphId) {
|
|
286
|
+
this.subscribedGraphs.delete(graphId);
|
|
287
|
+
}
|
|
288
|
+
// ===========================================================================
|
|
289
|
+
// Private Methods - Event Handling
|
|
290
|
+
// ===========================================================================
|
|
291
|
+
handleGraphEvent(event) {
|
|
292
|
+
const { type, graphId, patch } = event;
|
|
293
|
+
switch (type) {
|
|
294
|
+
case 'graph_patched':
|
|
295
|
+
// Route to subscribed Graph instance
|
|
296
|
+
if (patch) {
|
|
297
|
+
const graph = this.subscribedGraphs.get(graphId);
|
|
298
|
+
if (graph) {
|
|
299
|
+
graph.handleRemotePatch(patch);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
break;
|
|
303
|
+
case 'graph_changed':
|
|
304
|
+
// Route to subscribed Graph instance
|
|
305
|
+
{
|
|
306
|
+
const graph = this.subscribedGraphs.get(graphId);
|
|
307
|
+
if (graph) {
|
|
308
|
+
// Reload graph data and notify
|
|
309
|
+
void this.graphqlClient.getGraph(graphId).then((data) => {
|
|
310
|
+
graph.handleRemoteChange(data);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
case 'graph_name_changed':
|
|
316
|
+
// Emit client-level event and update any open Graph
|
|
317
|
+
{
|
|
318
|
+
// Fetch updated name
|
|
319
|
+
void this.graphqlClient.listGraphs().then((graphs) => {
|
|
320
|
+
const info = graphs.find(g => g.id === graphId);
|
|
321
|
+
if (info) {
|
|
322
|
+
const graph = this.subscribedGraphs.get(graphId);
|
|
323
|
+
if (graph) {
|
|
324
|
+
graph.handleRemoteRename(info.name);
|
|
325
|
+
}
|
|
326
|
+
this.emit('graphRenamed', graphId, info.name);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
break;
|
|
331
|
+
case 'graph_created':
|
|
332
|
+
// Client-level event only
|
|
333
|
+
this.emit('graphCreated', graphId);
|
|
334
|
+
break;
|
|
335
|
+
case 'graph_deleted':
|
|
336
|
+
// Client-level event
|
|
337
|
+
this.emit('graphDeleted', graphId);
|
|
338
|
+
// Note: Any open Graph instances become stale
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic event map type - keys are event names, values are listener signatures
|
|
3
|
+
*/
|
|
4
|
+
export type EventMap = Record<string, (...args: any[]) => void>;
|
|
5
|
+
/**
|
|
6
|
+
* Simple typed EventEmitter implementation.
|
|
7
|
+
* Works in browser and Node.js environments without dependencies.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EventEmitter<Events extends EventMap> {
|
|
10
|
+
private listeners;
|
|
11
|
+
/**
|
|
12
|
+
* Register an event listener.
|
|
13
|
+
* @returns Unsubscribe function
|
|
14
|
+
*/
|
|
15
|
+
on<K extends keyof Events>(event: K, listener: Events[K]): () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Remove an event listener.
|
|
18
|
+
*/
|
|
19
|
+
off<K extends keyof Events>(event: K, listener: Events[K]): void;
|
|
20
|
+
/**
|
|
21
|
+
* Register a one-time event listener.
|
|
22
|
+
* @returns Unsubscribe function
|
|
23
|
+
*/
|
|
24
|
+
once<K extends keyof Events>(event: K, listener: Events[K]): () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Emit an event to all registered listeners.
|
|
27
|
+
*/
|
|
28
|
+
protected emit<K extends keyof Events>(event: K, ...args: Parameters<Events[K]>): void;
|
|
29
|
+
/**
|
|
30
|
+
* Remove all listeners for a specific event, or all listeners if no event specified.
|
|
31
|
+
*/
|
|
32
|
+
removeAllListeners<K extends keyof Events>(event?: K): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get the number of listeners for a specific event.
|
|
35
|
+
*/
|
|
36
|
+
listenerCount<K extends keyof Events>(event: K): number;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=event-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../src/event-emitter.ts"],"names":[],"mappings":"AAKA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC;AAEhE;;;GAGG;AACH,qBAAa,YAAY,CAAC,MAAM,SAAS,QAAQ;IAC/C,OAAO,CAAC,SAAS,CAAsD;IAEvE;;;OAGG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IASrE;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAUhE;;;OAGG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IASvE;;OAEG;IACH,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,EACnC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAC7B,IAAI;IAcP;;OAEG;IACH,kBAAkB,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI;IAQ3D;;OAEG;IACH,aAAa,CAAC,CAAC,SAAS,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM;CAGxD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Typed EventEmitter
|
|
3
|
+
// Framework-agnostic event emitter that works in browser and Node.js
|
|
4
|
+
// =============================================================================
|
|
5
|
+
/**
|
|
6
|
+
* Simple typed EventEmitter implementation.
|
|
7
|
+
* Works in browser and Node.js environments without dependencies.
|
|
8
|
+
*/
|
|
9
|
+
export class EventEmitter {
|
|
10
|
+
listeners = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Register an event listener.
|
|
13
|
+
* @returns Unsubscribe function
|
|
14
|
+
*/
|
|
15
|
+
on(event, listener) {
|
|
16
|
+
if (!this.listeners.has(event)) {
|
|
17
|
+
this.listeners.set(event, new Set());
|
|
18
|
+
}
|
|
19
|
+
this.listeners.get(event).add(listener);
|
|
20
|
+
return () => this.off(event, listener);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Remove an event listener.
|
|
24
|
+
*/
|
|
25
|
+
off(event, listener) {
|
|
26
|
+
const set = this.listeners.get(event);
|
|
27
|
+
if (set) {
|
|
28
|
+
set.delete(listener);
|
|
29
|
+
if (set.size === 0) {
|
|
30
|
+
this.listeners.delete(event);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Register a one-time event listener.
|
|
36
|
+
* @returns Unsubscribe function
|
|
37
|
+
*/
|
|
38
|
+
once(event, listener) {
|
|
39
|
+
const wrapper = ((...args) => {
|
|
40
|
+
this.off(event, wrapper);
|
|
41
|
+
listener(...args);
|
|
42
|
+
});
|
|
43
|
+
return this.on(event, wrapper);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Emit an event to all registered listeners.
|
|
47
|
+
*/
|
|
48
|
+
emit(event, ...args) {
|
|
49
|
+
const set = this.listeners.get(event);
|
|
50
|
+
if (set) {
|
|
51
|
+
// Copy to array to allow listeners to unsubscribe during emit
|
|
52
|
+
for (const listener of Array.from(set)) {
|
|
53
|
+
try {
|
|
54
|
+
listener(...args);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(`Error in event listener for "${String(event)}":`, error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Remove all listeners for a specific event, or all listeners if no event specified.
|
|
64
|
+
*/
|
|
65
|
+
removeAllListeners(event) {
|
|
66
|
+
if (event !== undefined) {
|
|
67
|
+
this.listeners.delete(event);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.listeners.clear();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the number of listeners for a specific event.
|
|
75
|
+
*/
|
|
76
|
+
listenerCount(event) {
|
|
77
|
+
return this.listeners.get(event)?.size ?? 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=event-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../src/event-emitter.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,qBAAqB;AACrB,qEAAqE;AACrE,gFAAgF;AAQhF;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,SAAS,GAAG,IAAI,GAAG,EAA2C,CAAC;IAEvE;;;OAGG;IACH,EAAE,CAAyB,KAAQ,EAAE,QAAmB;QACtD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEzC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,GAAG,CAAyB,KAAQ,EAAE,QAAmB;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,GAAG,EAAE,CAAC;YACR,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACrB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,IAAI,CAAyB,KAAQ,EAAE,QAAmB;QACxD,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,IAA2B,EAAE,EAAE;YAClD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAoB,CAAC,CAAC;YACrC,QAAqD,CAAC,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC,CAAc,CAAC;QAEhB,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACO,IAAI,CACZ,KAAQ,EACR,GAAG,IAA2B;QAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,GAAG,EAAE,CAAC;YACR,8DAA8D;YAC9D,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACF,QAAqD,CAAC,GAAG,IAAI,CAAC,CAAC;gBAClE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC1E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAyB,KAAS;QAClD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa,CAAyB,KAAQ;QAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;IAC9C,CAAC;CACF"}
|