@kyro-cms/core 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.
Files changed (88) hide show
  1. package/README.md +241 -0
  2. package/dist/base-CQkFzqQl.d.ts +62 -0
  3. package/dist/base-DlhVlwnN.d.cts +62 -0
  4. package/dist/chunk-3Q3FS5J4.cjs +273 -0
  5. package/dist/chunk-3Q3FS5J4.cjs.map +1 -0
  6. package/dist/chunk-3TPQ2BU6.js +423 -0
  7. package/dist/chunk-3TPQ2BU6.js.map +1 -0
  8. package/dist/chunk-3VZCX4DF.cjs +384 -0
  9. package/dist/chunk-3VZCX4DF.cjs.map +1 -0
  10. package/dist/chunk-BXMWDUED.js +115 -0
  11. package/dist/chunk-BXMWDUED.js.map +1 -0
  12. package/dist/chunk-DIC236EW.js +290 -0
  13. package/dist/chunk-DIC236EW.js.map +1 -0
  14. package/dist/chunk-DKSMFC3L.js +268 -0
  15. package/dist/chunk-DKSMFC3L.js.map +1 -0
  16. package/dist/chunk-DVD5P72E.cjs +428 -0
  17. package/dist/chunk-DVD5P72E.cjs.map +1 -0
  18. package/dist/chunk-HT6VE4NW.cjs +293 -0
  19. package/dist/chunk-HT6VE4NW.cjs.map +1 -0
  20. package/dist/chunk-K7QF2QCM.cjs +311 -0
  21. package/dist/chunk-K7QF2QCM.cjs.map +1 -0
  22. package/dist/chunk-OG3KX56O.js +308 -0
  23. package/dist/chunk-OG3KX56O.js.map +1 -0
  24. package/dist/chunk-R3XIBBAW.cjs +34 -0
  25. package/dist/chunk-R3XIBBAW.cjs.map +1 -0
  26. package/dist/chunk-RLTG4YZM.cjs +117 -0
  27. package/dist/chunk-RLTG4YZM.cjs.map +1 -0
  28. package/dist/chunk-SDMNUYVU.js +30 -0
  29. package/dist/chunk-SDMNUYVU.js.map +1 -0
  30. package/dist/chunk-UEG7KMKC.cjs +228 -0
  31. package/dist/chunk-UEG7KMKC.cjs.map +1 -0
  32. package/dist/chunk-UEYC46RL.js +374 -0
  33. package/dist/chunk-UEYC46RL.js.map +1 -0
  34. package/dist/chunk-YPAFJ7EV.js +225 -0
  35. package/dist/chunk-YPAFJ7EV.js.map +1 -0
  36. package/dist/cli/index.cjs +306 -0
  37. package/dist/cli/index.cjs.map +1 -0
  38. package/dist/cli/index.d.cts +1 -0
  39. package/dist/cli/index.d.ts +1 -0
  40. package/dist/cli/index.js +303 -0
  41. package/dist/cli/index.js.map +1 -0
  42. package/dist/drizzle/index.cjs +25 -0
  43. package/dist/drizzle/index.cjs.map +1 -0
  44. package/dist/drizzle/index.d.cts +49 -0
  45. package/dist/drizzle/index.d.ts +49 -0
  46. package/dist/drizzle/index.js +4 -0
  47. package/dist/drizzle/index.js.map +1 -0
  48. package/dist/graphql/index.cjs +16 -0
  49. package/dist/graphql/index.cjs.map +1 -0
  50. package/dist/graphql/index.d.cts +20 -0
  51. package/dist/graphql/index.d.ts +20 -0
  52. package/dist/graphql/index.js +3 -0
  53. package/dist/graphql/index.js.map +1 -0
  54. package/dist/index-4fJKLFK2.d.ts +63 -0
  55. package/dist/index-DI0DRPNv.d.cts +63 -0
  56. package/dist/index.cjs +2506 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.d.cts +525 -0
  59. package/dist/index.d.ts +525 -0
  60. package/dist/index.js +2334 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/mongodb/index.cjs +17 -0
  63. package/dist/mongodb/index.cjs.map +1 -0
  64. package/dist/mongodb/index.d.cts +49 -0
  65. package/dist/mongodb/index.d.ts +49 -0
  66. package/dist/mongodb/index.js +4 -0
  67. package/dist/mongodb/index.js.map +1 -0
  68. package/dist/rest/index.cjs +17 -0
  69. package/dist/rest/index.cjs.map +1 -0
  70. package/dist/rest/index.d.cts +28 -0
  71. package/dist/rest/index.d.ts +28 -0
  72. package/dist/rest/index.js +4 -0
  73. package/dist/rest/index.js.map +1 -0
  74. package/dist/trpc/index.cjs +45 -0
  75. package/dist/trpc/index.cjs.map +1 -0
  76. package/dist/trpc/index.d.cts +130 -0
  77. package/dist/trpc/index.d.ts +130 -0
  78. package/dist/trpc/index.js +4 -0
  79. package/dist/trpc/index.js.map +1 -0
  80. package/dist/types-BGM5MV_K.d.cts +589 -0
  81. package/dist/types-BGM5MV_K.d.ts +589 -0
  82. package/dist/ws/index.cjs +24 -0
  83. package/dist/ws/index.cjs.map +1 -0
  84. package/dist/ws/index.d.cts +88 -0
  85. package/dist/ws/index.d.ts +88 -0
  86. package/dist/ws/index.js +3 -0
  87. package/dist/ws/index.js.map +1 -0
  88. package/package.json +120 -0
@@ -0,0 +1,428 @@
1
+ 'use strict';
2
+
3
+ var ws = require('ws');
4
+
5
+ // src/api/ws/pubsub.ts
6
+ var PubSub = class {
7
+ channels = /* @__PURE__ */ new Map();
8
+ maxListeners;
9
+ constructor(maxListeners = 100) {
10
+ this.maxListeners = maxListeners;
11
+ }
12
+ subscribe(channel, handler) {
13
+ if (!this.channels.has(channel)) {
14
+ this.channels.set(channel, /* @__PURE__ */ new Set());
15
+ }
16
+ const handlers = this.channels.get(channel);
17
+ if (handlers.size >= this.maxListeners) {
18
+ throw new Error(`Max listeners (${this.maxListeners}) reached for channel "${channel}"`);
19
+ }
20
+ handlers.add(handler);
21
+ return () => {
22
+ handlers.delete(handler);
23
+ if (handlers.size === 0) {
24
+ this.channels.delete(channel);
25
+ }
26
+ };
27
+ }
28
+ publish(channel, data) {
29
+ const handlers = this.channels.get(channel);
30
+ if (handlers) {
31
+ for (const handler of handlers) {
32
+ try {
33
+ const result = handler(data);
34
+ if (result instanceof Promise) {
35
+ result.catch((err) => {
36
+ console.error(`[PubSub] Error in handler for channel "${channel}":`, err);
37
+ });
38
+ }
39
+ } catch (err) {
40
+ console.error(`[PubSub] Error in handler for channel "${channel}":`, err);
41
+ }
42
+ }
43
+ }
44
+ }
45
+ hasSubscribers(channel) {
46
+ return this.channels.has(channel) && this.channels.get(channel).size > 0;
47
+ }
48
+ getSubscriberCount(channel) {
49
+ return this.channels.get(channel)?.size || 0;
50
+ }
51
+ getChannels() {
52
+ return Array.from(this.channels.keys());
53
+ }
54
+ clear() {
55
+ this.channels.clear();
56
+ }
57
+ };
58
+ var KyroPubSub = class extends PubSub {
59
+ registry;
60
+ constructor(registry, maxListeners = 100) {
61
+ super(maxListeners);
62
+ this.registry = registry;
63
+ }
64
+ // Publish collection-level events
65
+ publishCollectionEvent(collection, event) {
66
+ this.publish(`collection:${collection}`, event);
67
+ this.publish("events:collection", event);
68
+ if (event.tenantID) {
69
+ this.publish(`tenant:${event.tenantID}:collection:${collection}`, event);
70
+ this.publish(`tenant:${event.tenantID}:events`, event);
71
+ }
72
+ this.publish(`collection:${collection}:${event.type}`, event);
73
+ }
74
+ // Subscribe to a collection
75
+ subscribeToCollection(collection, handler) {
76
+ return this.subscribe(`collection:${collection}`, handler);
77
+ }
78
+ // Subscribe to a specific event type on a collection
79
+ subscribeToCollectionEvent(collection, eventType, handler) {
80
+ return this.subscribe(`collection:${collection}:${eventType}`, handler);
81
+ }
82
+ // Subscribe to tenant-scoped events
83
+ subscribeToTenant(tenantID, handler) {
84
+ return this.subscribe(`tenant:${tenantID}:events`, handler);
85
+ }
86
+ // Subscribe to tenant + collection events
87
+ subscribeToTenantCollection(tenantID, collection, handler) {
88
+ return this.subscribe(`tenant:${tenantID}:collection:${collection}`, handler);
89
+ }
90
+ // Subscribe to all collection events
91
+ subscribeToAllCollections(handler) {
92
+ return this.subscribe("events:collection", handler);
93
+ }
94
+ // Create hooks for afterChange/afterDelete
95
+ createAfterChangeHook(collection) {
96
+ return async (args) => {
97
+ this.publishCollectionEvent(collection, {
98
+ type: args.operation === "create" ? "create" : "update",
99
+ collection,
100
+ doc: args.doc,
101
+ originalDoc: args.originalDoc,
102
+ id: args.id || args.doc?.id,
103
+ tenantID: args.tenantID,
104
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
105
+ user: args.user
106
+ });
107
+ };
108
+ }
109
+ createAfterDeleteHook(collection) {
110
+ return async (args) => {
111
+ this.publishCollectionEvent(collection, {
112
+ type: "delete",
113
+ collection,
114
+ doc: args.doc,
115
+ originalDoc: args.originalDoc,
116
+ id: args.id || args.doc?.id,
117
+ tenantID: args.tenantID,
118
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
119
+ user: args.user
120
+ });
121
+ };
122
+ }
123
+ // Auto-register hooks for all collections
124
+ autoRegisterHooks() {
125
+ const collections = this.registry.getCollections();
126
+ for (const collection of collections) {
127
+ const config = this.registry.getCollection(collection.slug);
128
+ if (config) {
129
+ if (!config.hooks) config.hooks = {};
130
+ if (!config.hooks.afterChange) config.hooks.afterChange = [];
131
+ if (!config.hooks.afterDelete) config.hooks.afterDelete = [];
132
+ config.hooks.afterChange.push(this.createAfterChangeHook(collection.slug));
133
+ config.hooks.afterDelete.push(this.createAfterDeleteHook(collection.slug));
134
+ }
135
+ }
136
+ }
137
+ };
138
+ var KyroWSServer = class {
139
+ wss;
140
+ clients = /* @__PURE__ */ new Map();
141
+ pubsub;
142
+ options;
143
+ pingTimer;
144
+ constructor(options) {
145
+ this.options = options;
146
+ this.pubsub = options.pubsub;
147
+ this.wss = new ws.WebSocketServer({
148
+ port: options.port || 8080
149
+ });
150
+ this.setupServer();
151
+ this.startPingInterval();
152
+ }
153
+ setupServer() {
154
+ this.wss.on("connection", (ws, req) => {
155
+ const clientId = this.generateClientId();
156
+ if (this.options.maxConnections && this.clients.size >= this.options.maxConnections) {
157
+ ws.close(1013, "Server at capacity");
158
+ return;
159
+ }
160
+ const client = {
161
+ id: clientId,
162
+ ws,
163
+ subscriptions: /* @__PURE__ */ new Map(),
164
+ authenticated: false,
165
+ connectedAt: /* @__PURE__ */ new Date(),
166
+ lastActivity: /* @__PURE__ */ new Date()
167
+ };
168
+ this.clients.set(clientId, client);
169
+ console.log(`[WS] Client connected: ${clientId} (total: ${this.clients.size})`);
170
+ this.sendToClient(client, {
171
+ type: "connected",
172
+ clientId,
173
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
174
+ });
175
+ ws.on("message", (data) => {
176
+ this.handleMessage(client, data);
177
+ });
178
+ ws.on("error", (error) => {
179
+ console.error(`[WS] Client error ${clientId}:`, error);
180
+ });
181
+ ws.on("close", () => {
182
+ this.handleDisconnect(client);
183
+ });
184
+ ws.on("pong", () => {
185
+ client.lastActivity = /* @__PURE__ */ new Date();
186
+ });
187
+ });
188
+ this.wss.on("error", (error) => {
189
+ console.error("[WS] Server error:", error);
190
+ });
191
+ }
192
+ handleMessage(client, data) {
193
+ client.lastActivity = /* @__PURE__ */ new Date();
194
+ let message;
195
+ try {
196
+ message = JSON.parse(data.toString());
197
+ } catch {
198
+ this.sendToClient(client, {
199
+ type: "error",
200
+ error: "Invalid JSON"
201
+ });
202
+ return;
203
+ }
204
+ switch (message.type) {
205
+ case "authenticate":
206
+ this.handleAuthenticate(client, message);
207
+ break;
208
+ case "subscribe":
209
+ this.handleSubscribe(client, message);
210
+ break;
211
+ case "unsubscribe":
212
+ this.handleUnsubscribe(client, message);
213
+ break;
214
+ case "unsubscribeAll":
215
+ this.handleUnsubscribeAll(client);
216
+ break;
217
+ case "list":
218
+ this.handleList(client);
219
+ break;
220
+ case "ping":
221
+ this.sendToClient(client, { type: "pong", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
222
+ break;
223
+ default:
224
+ this.sendToClient(client, {
225
+ type: "error",
226
+ error: `Unknown message type: ${message.type}`
227
+ });
228
+ }
229
+ }
230
+ async handleAuthenticate(client, message) {
231
+ if (!this.options.requireAuth) {
232
+ client.authenticated = true;
233
+ this.sendToClient(client, {
234
+ type: "authenticated",
235
+ success: true
236
+ });
237
+ return;
238
+ }
239
+ if (!this.options.verifyToken) {
240
+ client.authenticated = true;
241
+ this.sendToClient(client, {
242
+ type: "authenticated",
243
+ success: true
244
+ });
245
+ return;
246
+ }
247
+ try {
248
+ const user = await this.options.verifyToken(message.token);
249
+ client.authenticated = true;
250
+ client.user = user;
251
+ client.tenantID = user.tenantID;
252
+ this.sendToClient(client, {
253
+ type: "authenticated",
254
+ success: true,
255
+ user: { id: user.id, email: user.email }
256
+ });
257
+ } catch (error) {
258
+ this.sendToClient(client, {
259
+ type: "authenticated",
260
+ success: false,
261
+ error: error.message
262
+ });
263
+ }
264
+ }
265
+ handleSubscribe(client, message) {
266
+ if (this.options.requireAuth && !client.authenticated) {
267
+ this.sendToClient(client, {
268
+ type: "error",
269
+ error: "Not authenticated"
270
+ });
271
+ return;
272
+ }
273
+ const channel = message.channel;
274
+ if (!channel) {
275
+ this.sendToClient(client, {
276
+ type: "error",
277
+ error: "Channel is required"
278
+ });
279
+ return;
280
+ }
281
+ if (client.subscriptions.has(channel)) {
282
+ this.sendToClient(client, {
283
+ type: "subscribed",
284
+ channel,
285
+ success: true,
286
+ message: "Already subscribed"
287
+ });
288
+ return;
289
+ }
290
+ const unsubscribe = this.pubsub.subscribe(channel, (data) => {
291
+ this.sendToClient(client, {
292
+ type: "event",
293
+ channel,
294
+ data,
295
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
296
+ });
297
+ });
298
+ client.subscriptions.set(channel, { channel, unsubscribe });
299
+ this.sendToClient(client, {
300
+ type: "subscribed",
301
+ channel,
302
+ success: true
303
+ });
304
+ }
305
+ handleUnsubscribe(client, message) {
306
+ const channel = message.channel;
307
+ if (!channel) {
308
+ this.sendToClient(client, {
309
+ type: "error",
310
+ error: "Channel is required"
311
+ });
312
+ return;
313
+ }
314
+ const subscription = client.subscriptions.get(channel);
315
+ if (subscription) {
316
+ subscription.unsubscribe();
317
+ client.subscriptions.delete(channel);
318
+ this.sendToClient(client, {
319
+ type: "unsubscribed",
320
+ channel,
321
+ success: true
322
+ });
323
+ } else {
324
+ this.sendToClient(client, {
325
+ type: "unsubscribed",
326
+ channel,
327
+ success: false,
328
+ message: "Not subscribed"
329
+ });
330
+ }
331
+ }
332
+ handleUnsubscribeAll(client) {
333
+ for (const [, subscription] of client.subscriptions) {
334
+ subscription.unsubscribe();
335
+ }
336
+ client.subscriptions.clear();
337
+ this.sendToClient(client, {
338
+ type: "unsubscribedAll",
339
+ success: true
340
+ });
341
+ }
342
+ handleList(client) {
343
+ const channels = this.pubsub.getChannels();
344
+ this.sendToClient(client, {
345
+ type: "channels",
346
+ channels,
347
+ count: channels.length
348
+ });
349
+ }
350
+ handleDisconnect(client) {
351
+ for (const [, subscription] of client.subscriptions) {
352
+ subscription.unsubscribe();
353
+ }
354
+ this.clients.delete(client.id);
355
+ console.log(`[WS] Client disconnected: ${client.id} (total: ${this.clients.size})`);
356
+ }
357
+ sendToClient(client, data) {
358
+ if (client.ws.readyState === ws.WebSocket.OPEN) {
359
+ client.ws.send(JSON.stringify(data));
360
+ }
361
+ }
362
+ generateClientId() {
363
+ return `ws_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
364
+ }
365
+ startPingInterval() {
366
+ if (!this.options.pingInterval) return;
367
+ this.pingTimer = setInterval(() => {
368
+ for (const [id, client] of this.clients) {
369
+ if (client.ws.readyState === ws.WebSocket.OPEN) {
370
+ const timeSinceLastActivity = Date.now() - client.lastActivity.getTime();
371
+ if (timeSinceLastActivity > this.options.pingInterval * 3) {
372
+ console.log(`[WS] Client ${id} timed out`);
373
+ client.ws.terminate();
374
+ this.handleDisconnect(client);
375
+ continue;
376
+ }
377
+ client.ws.ping();
378
+ }
379
+ }
380
+ }, this.options.pingInterval);
381
+ }
382
+ // ============================================================================
383
+ // Public API
384
+ // ============================================================================
385
+ broadcast(channel, data) {
386
+ this.pubsub.publish(channel, data);
387
+ }
388
+ getConnectedClients() {
389
+ return Array.from(this.clients.values());
390
+ }
391
+ getClientCount() {
392
+ return this.clients.size;
393
+ }
394
+ getSubscriptionCount() {
395
+ let count = 0;
396
+ for (const client of this.clients.values()) {
397
+ count += client.subscriptions.size;
398
+ }
399
+ return count;
400
+ }
401
+ async close() {
402
+ if (this.pingTimer) {
403
+ clearInterval(this.pingTimer);
404
+ }
405
+ for (const client of this.clients.values()) {
406
+ client.ws.close(1001, "Server shutting down");
407
+ }
408
+ return new Promise((resolve) => {
409
+ this.wss.close(() => {
410
+ console.log("[WS] Server closed");
411
+ resolve();
412
+ });
413
+ });
414
+ }
415
+ getServer() {
416
+ return this.wss;
417
+ }
418
+ };
419
+ function createWSServer(options) {
420
+ return new KyroWSServer(options);
421
+ }
422
+
423
+ exports.KyroPubSub = KyroPubSub;
424
+ exports.KyroWSServer = KyroWSServer;
425
+ exports.PubSub = PubSub;
426
+ exports.createWSServer = createWSServer;
427
+ //# sourceMappingURL=chunk-DVD5P72E.cjs.map
428
+ //# sourceMappingURL=chunk-DVD5P72E.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/ws/pubsub.ts","../src/api/ws/server.ts"],"names":["WebSocketServer","WebSocket"],"mappings":"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","file":"chunk-DVD5P72E.cjs","sourcesContent":["// ============================================================================\n// Pub/Sub Event Emitter\n// ============================================================================\n\nexport type EventHandler = (data: any) => void | Promise<void>;\n\nexport class PubSub {\n private channels: Map<string, Set<EventHandler>> = new Map();\n private maxListeners: number;\n\n constructor(maxListeners = 100) {\n this.maxListeners = maxListeners;\n }\n\n subscribe(channel: string, handler: EventHandler): () => void {\n if (!this.channels.has(channel)) {\n this.channels.set(channel, new Set());\n }\n\n const handlers = this.channels.get(channel)!;\n if (handlers.size >= this.maxListeners) {\n throw new Error(`Max listeners (${this.maxListeners}) reached for channel \"${channel}\"`);\n }\n\n handlers.add(handler);\n\n // Return unsubscribe function\n return () => {\n handlers.delete(handler);\n if (handlers.size === 0) {\n this.channels.delete(channel);\n }\n };\n }\n\n publish(channel: string, data: any): void {\n const handlers = this.channels.get(channel);\n if (handlers) {\n for (const handler of handlers) {\n try {\n const result = handler(data);\n if (result instanceof Promise) {\n result.catch((err) => {\n console.error(`[PubSub] Error in handler for channel \"${channel}\":`, err);\n });\n }\n } catch (err) {\n console.error(`[PubSub] Error in handler for channel \"${channel}\":`, err);\n }\n }\n }\n }\n\n hasSubscribers(channel: string): boolean {\n return this.channels.has(channel) && this.channels.get(channel)!.size > 0;\n }\n\n getSubscriberCount(channel: string): number {\n return this.channels.get(channel)?.size || 0;\n }\n\n getChannels(): string[] {\n return Array.from(this.channels.keys());\n }\n\n clear(): void {\n this.channels.clear();\n }\n}\n\n// ============================================================================\n// Kyro-specific Event Types\n// ============================================================================\n\nexport interface KyroEvent {\n type: 'create' | 'update' | 'delete';\n collection: string;\n doc?: any;\n originalDoc?: any;\n id?: string;\n tenantID?: string;\n timestamp: string;\n user?: any;\n}\n\n// ============================================================================\n// Kyro Pub/Sub with Hook Integration\n// ============================================================================\n\nexport class KyroPubSub extends PubSub {\n private registry: any;\n\n constructor(registry: any, maxListeners = 100) {\n super(maxListeners);\n this.registry = registry;\n }\n\n // Publish collection-level events\n publishCollectionEvent(collection: string, event: KyroEvent): void {\n // Publish to collection channel\n this.publish(`collection:${collection}`, event);\n\n // Publish to global events channel\n this.publish('events:collection', event);\n\n // Publish to tenant-specific channel if scoped\n if (event.tenantID) {\n this.publish(`tenant:${event.tenantID}:collection:${collection}`, event);\n this.publish(`tenant:${event.tenantID}:events`, event);\n }\n\n // Publish to type-specific channel\n this.publish(`collection:${collection}:${event.type}`, event);\n }\n\n // Subscribe to a collection\n subscribeToCollection(collection: string, handler: EventHandler): () => void {\n return this.subscribe(`collection:${collection}`, handler);\n }\n\n // Subscribe to a specific event type on a collection\n subscribeToCollectionEvent(\n collection: string,\n eventType: 'create' | 'update' | 'delete',\n handler: EventHandler\n ): () => void {\n return this.subscribe(`collection:${collection}:${eventType}`, handler);\n }\n\n // Subscribe to tenant-scoped events\n subscribeToTenant(tenantID: string, handler: EventHandler): () => void {\n return this.subscribe(`tenant:${tenantID}:events`, handler);\n }\n\n // Subscribe to tenant + collection events\n subscribeToTenantCollection(\n tenantID: string,\n collection: string,\n handler: EventHandler\n ): () => void {\n return this.subscribe(`tenant:${tenantID}:collection:${collection}`, handler);\n }\n\n // Subscribe to all collection events\n subscribeToAllCollections(handler: EventHandler): () => void {\n return this.subscribe('events:collection', handler);\n }\n\n // Create hooks for afterChange/afterDelete\n createAfterChangeHook(collection: string) {\n return async (args: any) => {\n this.publishCollectionEvent(collection, {\n type: args.operation === 'create' ? 'create' : 'update',\n collection,\n doc: args.doc,\n originalDoc: args.originalDoc,\n id: args.id || args.doc?.id,\n tenantID: args.tenantID,\n timestamp: new Date().toISOString(),\n user: args.user,\n });\n };\n }\n\n createAfterDeleteHook(collection: string) {\n return async (args: any) => {\n this.publishCollectionEvent(collection, {\n type: 'delete',\n collection,\n doc: args.doc,\n originalDoc: args.originalDoc,\n id: args.id || args.doc?.id,\n tenantID: args.tenantID,\n timestamp: new Date().toISOString(),\n user: args.user,\n });\n };\n }\n\n // Auto-register hooks for all collections\n autoRegisterHooks(): void {\n const collections = this.registry.getCollections();\n for (const collection of collections) {\n const config = this.registry.getCollection(collection.slug);\n if (config) {\n if (!config.hooks) config.hooks = {};\n if (!config.hooks.afterChange) config.hooks.afterChange = [];\n if (!config.hooks.afterDelete) config.hooks.afterDelete = [];\n\n config.hooks.afterChange.push(this.createAfterChangeHook(collection.slug));\n config.hooks.afterDelete.push(this.createAfterDeleteHook(collection.slug));\n }\n }\n }\n}\n","import { WebSocketServer, WebSocket } from 'ws';\nimport type { KyroPubSub, KyroEvent } from './pubsub.js';\n\n// ============================================================================\n// WebSocket Server\n// ============================================================================\n\nexport interface WSServerOptions {\n port?: number;\n pubsub: KyroPubSub;\n maxConnections?: number;\n pingInterval?: number;\n requireAuth?: boolean;\n verifyToken?: (token: string) => Promise<any>;\n}\n\nexport interface WSSubscription {\n channel: string;\n unsubscribe: () => void;\n}\n\nexport interface WSClient {\n id: string;\n ws: WebSocket;\n subscriptions: Map<string, WSSubscription>;\n authenticated: boolean;\n user?: any;\n tenantID?: string;\n connectedAt: Date;\n lastActivity: Date;\n}\n\nexport class KyroWSServer {\n private wss: WebSocketServer;\n private clients: Map<string, WSClient> = new Map();\n private pubsub: KyroPubSub;\n private options: WSServerOptions;\n private pingTimer?: NodeJS.Timer;\n\n constructor(options: WSServerOptions) {\n this.options = options;\n this.pubsub = options.pubsub;\n\n this.wss = new WebSocketServer({\n port: options.port || 8080,\n });\n\n this.setupServer();\n this.startPingInterval();\n }\n\n private setupServer(): void {\n this.wss.on('connection', (ws: WebSocket, req: any) => {\n const clientId = this.generateClientId();\n\n if (this.options.maxConnections && this.clients.size >= this.options.maxConnections) {\n ws.close(1013, 'Server at capacity');\n return;\n }\n\n const client: WSClient = {\n id: clientId,\n ws,\n subscriptions: new Map(),\n authenticated: false,\n connectedAt: new Date(),\n lastActivity: new Date(),\n };\n\n this.clients.set(clientId, client);\n console.log(`[WS] Client connected: ${clientId} (total: ${this.clients.size})`);\n\n // Send welcome message\n this.sendToClient(client, {\n type: 'connected',\n clientId,\n timestamp: new Date().toISOString(),\n });\n\n // Handle messages\n ws.on('message', (data: Buffer) => {\n this.handleMessage(client, data);\n });\n\n // Handle errors\n ws.on('error', (error: Error) => {\n console.error(`[WS] Client error ${clientId}:`, error);\n });\n\n // Handle close\n ws.on('close', () => {\n this.handleDisconnect(client);\n });\n\n // Handle pong\n ws.on('pong', () => {\n client.lastActivity = new Date();\n });\n });\n\n this.wss.on('error', (error: Error) => {\n console.error('[WS] Server error:', error);\n });\n }\n\n private handleMessage(client: WSClient, data: Buffer): void {\n client.lastActivity = new Date();\n\n let message: any;\n try {\n message = JSON.parse(data.toString());\n } catch {\n this.sendToClient(client, {\n type: 'error',\n error: 'Invalid JSON',\n });\n return;\n }\n\n switch (message.type) {\n case 'authenticate':\n this.handleAuthenticate(client, message);\n break;\n case 'subscribe':\n this.handleSubscribe(client, message);\n break;\n case 'unsubscribe':\n this.handleUnsubscribe(client, message);\n break;\n case 'unsubscribeAll':\n this.handleUnsubscribeAll(client);\n break;\n case 'list':\n this.handleList(client);\n break;\n case 'ping':\n this.sendToClient(client, { type: 'pong', timestamp: new Date().toISOString() });\n break;\n default:\n this.sendToClient(client, {\n type: 'error',\n error: `Unknown message type: ${message.type}`,\n });\n }\n }\n\n private async handleAuthenticate(client: WSClient, message: any): Promise<void> {\n if (!this.options.requireAuth) {\n client.authenticated = true;\n this.sendToClient(client, {\n type: 'authenticated',\n success: true,\n });\n return;\n }\n\n if (!this.options.verifyToken) {\n client.authenticated = true;\n this.sendToClient(client, {\n type: 'authenticated',\n success: true,\n });\n return;\n }\n\n try {\n const user = await this.options.verifyToken(message.token);\n client.authenticated = true;\n client.user = user;\n client.tenantID = user.tenantID;\n this.sendToClient(client, {\n type: 'authenticated',\n success: true,\n user: { id: user.id, email: user.email },\n });\n } catch (error: any) {\n this.sendToClient(client, {\n type: 'authenticated',\n success: false,\n error: error.message,\n });\n }\n }\n\n private handleSubscribe(client: WSClient, message: any): void {\n if (this.options.requireAuth && !client.authenticated) {\n this.sendToClient(client, {\n type: 'error',\n error: 'Not authenticated',\n });\n return;\n }\n\n const channel = message.channel;\n if (!channel) {\n this.sendToClient(client, {\n type: 'error',\n error: 'Channel is required',\n });\n return;\n }\n\n // Check if already subscribed\n if (client.subscriptions.has(channel)) {\n this.sendToClient(client, {\n type: 'subscribed',\n channel,\n success: true,\n message: 'Already subscribed',\n });\n return;\n }\n\n // Subscribe to channel\n const unsubscribe = this.pubsub.subscribe(channel, (data: any) => {\n this.sendToClient(client, {\n type: 'event',\n channel,\n data,\n timestamp: new Date().toISOString(),\n });\n });\n\n client.subscriptions.set(channel, { channel, unsubscribe });\n\n this.sendToClient(client, {\n type: 'subscribed',\n channel,\n success: true,\n });\n }\n\n private handleUnsubscribe(client: WSClient, message: any): void {\n const channel = message.channel;\n if (!channel) {\n this.sendToClient(client, {\n type: 'error',\n error: 'Channel is required',\n });\n return;\n }\n\n const subscription = client.subscriptions.get(channel);\n if (subscription) {\n subscription.unsubscribe();\n client.subscriptions.delete(channel);\n this.sendToClient(client, {\n type: 'unsubscribed',\n channel,\n success: true,\n });\n } else {\n this.sendToClient(client, {\n type: 'unsubscribed',\n channel,\n success: false,\n message: 'Not subscribed',\n });\n }\n }\n\n private handleUnsubscribeAll(client: WSClient): void {\n for (const [, subscription] of client.subscriptions) {\n subscription.unsubscribe();\n }\n client.subscriptions.clear();\n\n this.sendToClient(client, {\n type: 'unsubscribedAll',\n success: true,\n });\n }\n\n private handleList(client: WSClient): void {\n const channels = this.pubsub.getChannels();\n this.sendToClient(client, {\n type: 'channels',\n channels,\n count: channels.length,\n });\n }\n\n private handleDisconnect(client: WSClient): void {\n // Unsubscribe from all channels\n for (const [, subscription] of client.subscriptions) {\n subscription.unsubscribe();\n }\n\n this.clients.delete(client.id);\n console.log(`[WS] Client disconnected: ${client.id} (total: ${this.clients.size})`);\n }\n\n private sendToClient(client: WSClient, data: any): void {\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.send(JSON.stringify(data));\n }\n }\n\n private generateClientId(): string {\n return `ws_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n }\n\n private startPingInterval(): void {\n if (!this.options.pingInterval) return;\n\n this.pingTimer = setInterval(() => {\n for (const [id, client] of this.clients) {\n if (client.ws.readyState === WebSocket.OPEN) {\n // Check if client responded to last ping\n const timeSinceLastActivity = Date.now() - client.lastActivity.getTime();\n if (timeSinceLastActivity > (this.options.pingInterval! * 3)) {\n console.log(`[WS] Client ${id} timed out`);\n client.ws.terminate();\n this.handleDisconnect(client);\n continue;\n }\n client.ws.ping();\n }\n }\n }, this.options.pingInterval);\n }\n\n // ============================================================================\n // Public API\n // ============================================================================\n\n broadcast(channel: string, data: any): void {\n this.pubsub.publish(channel, data);\n }\n\n getConnectedClients(): WSClient[] {\n return Array.from(this.clients.values());\n }\n\n getClientCount(): number {\n return this.clients.size;\n }\n\n getSubscriptionCount(): number {\n let count = 0;\n for (const client of this.clients.values()) {\n count += client.subscriptions.size;\n }\n return count;\n }\n\n async close(): Promise<void> {\n if (this.pingTimer) {\n clearInterval(this.pingTimer as any);\n }\n\n // Close all client connections\n for (const client of this.clients.values()) {\n client.ws.close(1001, 'Server shutting down');\n }\n\n // Close server\n return new Promise((resolve) => {\n this.wss.close(() => {\n console.log('[WS] Server closed');\n resolve();\n });\n });\n }\n\n getServer(): WebSocketServer {\n return this.wss;\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nexport function createWSServer(options: WSServerOptions): KyroWSServer {\n return new KyroWSServer(options);\n}\n"]}