@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.
- package/README.md +241 -0
- package/dist/base-CQkFzqQl.d.ts +62 -0
- package/dist/base-DlhVlwnN.d.cts +62 -0
- package/dist/chunk-3Q3FS5J4.cjs +273 -0
- package/dist/chunk-3Q3FS5J4.cjs.map +1 -0
- package/dist/chunk-3TPQ2BU6.js +423 -0
- package/dist/chunk-3TPQ2BU6.js.map +1 -0
- package/dist/chunk-3VZCX4DF.cjs +384 -0
- package/dist/chunk-3VZCX4DF.cjs.map +1 -0
- package/dist/chunk-BXMWDUED.js +115 -0
- package/dist/chunk-BXMWDUED.js.map +1 -0
- package/dist/chunk-DIC236EW.js +290 -0
- package/dist/chunk-DIC236EW.js.map +1 -0
- package/dist/chunk-DKSMFC3L.js +268 -0
- package/dist/chunk-DKSMFC3L.js.map +1 -0
- package/dist/chunk-DVD5P72E.cjs +428 -0
- package/dist/chunk-DVD5P72E.cjs.map +1 -0
- package/dist/chunk-HT6VE4NW.cjs +293 -0
- package/dist/chunk-HT6VE4NW.cjs.map +1 -0
- package/dist/chunk-K7QF2QCM.cjs +311 -0
- package/dist/chunk-K7QF2QCM.cjs.map +1 -0
- package/dist/chunk-OG3KX56O.js +308 -0
- package/dist/chunk-OG3KX56O.js.map +1 -0
- package/dist/chunk-R3XIBBAW.cjs +34 -0
- package/dist/chunk-R3XIBBAW.cjs.map +1 -0
- package/dist/chunk-RLTG4YZM.cjs +117 -0
- package/dist/chunk-RLTG4YZM.cjs.map +1 -0
- package/dist/chunk-SDMNUYVU.js +30 -0
- package/dist/chunk-SDMNUYVU.js.map +1 -0
- package/dist/chunk-UEG7KMKC.cjs +228 -0
- package/dist/chunk-UEG7KMKC.cjs.map +1 -0
- package/dist/chunk-UEYC46RL.js +374 -0
- package/dist/chunk-UEYC46RL.js.map +1 -0
- package/dist/chunk-YPAFJ7EV.js +225 -0
- package/dist/chunk-YPAFJ7EV.js.map +1 -0
- package/dist/cli/index.cjs +306 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +303 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/drizzle/index.cjs +25 -0
- package/dist/drizzle/index.cjs.map +1 -0
- package/dist/drizzle/index.d.cts +49 -0
- package/dist/drizzle/index.d.ts +49 -0
- package/dist/drizzle/index.js +4 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/graphql/index.cjs +16 -0
- package/dist/graphql/index.cjs.map +1 -0
- package/dist/graphql/index.d.cts +20 -0
- package/dist/graphql/index.d.ts +20 -0
- package/dist/graphql/index.js +3 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/index-4fJKLFK2.d.ts +63 -0
- package/dist/index-DI0DRPNv.d.cts +63 -0
- package/dist/index.cjs +2506 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +525 -0
- package/dist/index.d.ts +525 -0
- package/dist/index.js +2334 -0
- package/dist/index.js.map +1 -0
- package/dist/mongodb/index.cjs +17 -0
- package/dist/mongodb/index.cjs.map +1 -0
- package/dist/mongodb/index.d.cts +49 -0
- package/dist/mongodb/index.d.ts +49 -0
- package/dist/mongodb/index.js +4 -0
- package/dist/mongodb/index.js.map +1 -0
- package/dist/rest/index.cjs +17 -0
- package/dist/rest/index.cjs.map +1 -0
- package/dist/rest/index.d.cts +28 -0
- package/dist/rest/index.d.ts +28 -0
- package/dist/rest/index.js +4 -0
- package/dist/rest/index.js.map +1 -0
- package/dist/trpc/index.cjs +45 -0
- package/dist/trpc/index.cjs.map +1 -0
- package/dist/trpc/index.d.cts +130 -0
- package/dist/trpc/index.d.ts +130 -0
- package/dist/trpc/index.js +4 -0
- package/dist/trpc/index.js.map +1 -0
- package/dist/types-BGM5MV_K.d.cts +589 -0
- package/dist/types-BGM5MV_K.d.ts +589 -0
- package/dist/ws/index.cjs +24 -0
- package/dist/ws/index.cjs.map +1 -0
- package/dist/ws/index.d.cts +88 -0
- package/dist/ws/index.d.ts +88 -0
- package/dist/ws/index.js +3 -0
- package/dist/ws/index.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/database/drizzle/adapter.ts"],"names":["AbstractBaseAdapter"],"mappings":"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","file":"chunk-3Q3FS5J4.cjs","sourcesContent":["import { AbstractBaseAdapter } from '../base.js';\nimport type {\n CollectionConfig,\n GlobalConfig,\n FindArgs,\n FindByIDArgs,\n CreateArgs,\n UpdateArgs,\n DeleteArgs,\n FindResult,\n} from '../../registry/types.js';\nimport type { Field, RelationshipField } from '../../fields/types.js';\n\n// ============================================================================\n// Drizzle Schema Generator\n// ============================================================================\n\nexport function fieldToDrizzleType(field: Field, dialect: 'postgres' | 'mysql' | 'sqlite' = 'postgres'): string {\n switch (field.type) {\n case 'text':\n case 'email':\n case 'password':\n case 'textarea':\n case 'color':\n case 'code':\n case 'markdown':\n return dialect === 'sqlite' ? 'text' : 'varchar';\n case 'number':\n return field.integer ? 'integer' : 'decimal';\n case 'checkbox':\n return 'boolean';\n case 'date':\n return 'timestamp';\n case 'select':\n case 'radio':\n return dialect === 'sqlite' ? 'text' : 'varchar';\n case 'richtext':\n case 'json':\n case 'array':\n case 'group':\n case 'blocks':\n case 'row':\n case 'collapsible':\n case 'tabs':\n return 'jsonb';\n case 'relationship':\n return dialect === 'sqlite' ? 'text' : 'varchar';\n case 'upload':\n return dialect === 'sqlite' ? 'text' : 'varchar';\n default:\n return 'jsonb';\n }\n}\n\nexport function collectionToDrizzleSchema(\n collection: CollectionConfig,\n dialect: 'postgres' | 'mysql' | 'sqlite' = 'postgres'\n): string {\n const tableName = collection.slug.replace(/-/g, '_');\n const lines: string[] = [];\n \n lines.push(`export const ${tableName} = ${dialect === 'mysql' ? 'mysqlTable' : 'pgTable'}('${tableName}', {`);\n \n // Add id field\n lines.push(` id: ${dialect === 'mysql' ? 'varchar' : 'uuid'}('${dialect === 'mysql' ? 'id' : 'id'}').${dialect === 'mysql' ? \"primaryKey().default(sql`UUID()`)\" : \"primaryKey().defaultRandom()\"},`);\n \n // Process fields\n for (const field of collection.fields) {\n if (field.name === 'id') continue;\n \n const dbType = fieldToDrizzleType(field, dialect);\n const isRequired = field.required;\n \n let fieldDef = ` ${field.name}: ${dialect === 'mysql' ? 'mysql' : 'pg'}.${dbType}('${field.name}')`;\n \n // Add constraints\n if (field.unique) fieldDef += '.unique()';\n if (!isRequired) fieldDef += '.nullable()';\n \n // Add default value\n if (field.defaultValue !== undefined) {\n if (typeof field.defaultValue === 'string') {\n fieldDef += `.default('${field.defaultValue}')`;\n } else if (typeof field.defaultValue === 'boolean') {\n fieldDef += `.default(${field.defaultValue})`;\n } else {\n fieldDef += `.default(sql\\`${JSON.stringify(field.defaultValue)}\\`)`;\n }\n }\n \n fieldDef += ',';\n lines.push(fieldDef);\n }\n \n // Add timestamps\n if (collection.timestamps) {\n lines.push(` createdAt: ${dialect === 'mysql' ? 'mysql' : 'pg'}.timestamp('created_at').defaultNow(),`);\n lines.push(` updatedAt: ${dialect === 'mysql' ? 'mysql' : 'pg'}.timestamp('updated_at').defaultNow(),`);\n }\n \n // Add tenantID\n if (collection.tenantScoped) {\n lines.push(` tenantId: ${dialect === 'mysql' ? 'mysql' : 'pg'}.varchar('tenant_id'),`);\n }\n \n lines.push('});');\n \n return lines.join('\\n');\n}\n\n// ============================================================================\n// Drizzle Adapter\n// ============================================================================\n\nexport class DrizzleAdapter extends AbstractBaseAdapter {\n private client: any;\n private schema: any;\n private dialect: 'postgres' | 'mysql' | 'sqlite';\n \n constructor(options: {\n type: 'postgres' | 'mysql' | 'sqlite';\n client: any;\n schema?: any;\n }) {\n super();\n this.client = options.client;\n this.schema = options.schema || {};\n this.dialect = options.type;\n }\n\n async connect(): Promise<void> {\n this.connected = true;\n console.log(`[DrizzleAdapter] Connected to ${this.dialect}`);\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n console.log(`[DrizzleAdapter] Disconnected from ${this.dialect}`);\n }\n\n async find<T>(args: FindArgs): Promise<FindResult<T>> {\n const { collection: slug, where = {}, sort, limit = 10, page = 1, tenantID, select } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n // Build query\n const filters = this.buildWhereClause(where, config, tenantID);\n const sortOption = this.parseSort(sort);\n\n // Get total count\n const totalDocs = await this.count({ collection: slug, where, tenantID });\n\n // Execute query\n const offset = (page - 1) * limit;\n \n let docs: T[] = [];\n try {\n const results = await this.client\n .select()\n .from(table)\n .where(filters)\n .orderBy(sortOption.direction === 'asc' ? table[sortOption.field] : undefined)\n .limit(limit)\n .offset(offset);\n\n docs = results.map((doc: any) => this.processResult(doc, config));\n } catch (error) {\n console.error(`[DrizzleAdapter] Query error:`, error);\n docs = [];\n }\n\n return {\n docs,\n ...this.calculatePagination(page, limit, totalDocs),\n };\n }\n\n async findByID<T>(args: FindByIDArgs): Promise<T | null> {\n const { collection: slug, id, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n let query = this.client\n .select()\n .from(table)\n .where(table.id.equals(id));\n\n if (tenantID) {\n query = query.where(table.tenantId.equals(tenantID));\n }\n\n const results = await query.limit(1);\n if (results.length === 0) return null;\n\n return this.processResult(results[0], config) as T;\n }\n\n async create<T>(args: CreateArgs): Promise<T> {\n const { collection: slug, data, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n const insertData = this.prepareData(data, config);\n if (tenantID) {\n insertData.tenantId = tenantID;\n }\n\n const result = await this.client\n .insert(table)\n .values(insertData)\n .returning();\n\n return this.processResult(result[0], config) as T;\n }\n\n async update<T>(args: UpdateArgs): Promise<T> {\n const { collection: slug, id, data, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n const updateData = this.prepareData(data, config);\n if (tenantID) {\n updateData.tenantId = tenantID;\n }\n\n const result = await this.client\n .update(table)\n .set(updateData)\n .where(table.id.equals(id))\n .returning();\n\n return this.processResult(result[0], config) as T;\n }\n\n async delete<T>(args: DeleteArgs): Promise<T> {\n const { collection: slug, id, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n let query = this.client\n .delete(table)\n .where(table.id.equals(id))\n .returning();\n\n if (tenantID) {\n query = query.where(table.tenantId.equals(tenantID));\n }\n\n const result = await query;\n if (result.length === 0) {\n throw new Error(`Document not found: ${slug}/${id}`);\n }\n\n return this.processResult(result[0], config) as T;\n }\n\n async count(args: { collection: string; where?: Record<string, any>; tenantID?: string }): Promise<number> {\n const { collection: slug, where = {}, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n const filters = this.buildWhereClause(where, config, tenantID);\n\n try {\n const result = await this.client\n .select({ count: `count(*)` })\n .from(table)\n .where(filters);\n\n return parseInt(result[0]?.count || '0');\n } catch {\n return 0;\n }\n }\n\n async findOne(args: { collection: string; where: Record<string, any>; tenantID?: string }): Promise<any> {\n const { collection: slug, where = {}, tenantID } = args;\n const config = this.getCollection(slug);\n const table = this.getTable(slug);\n\n const filters = this.buildWhereClause(where, config, tenantID);\n\n const results = await this.client\n .select()\n .from(table)\n .where(filters)\n .limit(1);\n\n if (results.length === 0) return null;\n\n return this.processResult(results[0], config);\n }\n\n async findVersions(args: FindArgs): Promise<FindResult<any>> {\n // Versions are stored in a separate table\n const { collection: slug, where = {}, sort, limit = 10, page = 1 } = args;\n \n // Placeholder implementation\n return {\n docs: [],\n ...this.calculatePagination(page, limit, 0),\n };\n }\n\n async findVersionByID(args: FindByIDArgs): Promise<any> {\n return null;\n }\n\n async createVersion(args: CreateArgs): Promise<any> {\n return args.data;\n }\n\n async deleteVersions(args: { collection: string; where: Record<string, any> }): Promise<void> {\n // Placeholder\n }\n\n // ========================================================================\n // Helper Methods\n // ========================================================================\n\n private getTable(slug: string): any {\n const tableName = this.getTableName(slug);\n const table = this.schema[tableName];\n if (!table) {\n throw new Error(`Table \"${tableName}\" not found in schema`);\n }\n return table;\n }\n\n private buildWhereClause(\n where: Record<string, any>,\n config: CollectionConfig,\n tenantID?: string\n ): any {\n // Simplified where clause builder\n const conditions: any[] = [];\n\n // Apply tenant filter\n if (tenantID && config.tenantScoped) {\n conditions.push({ tenantId: tenantID });\n }\n\n // Process where conditions\n for (const [key, value] of Object.entries(where)) {\n if (key === 'AND' && Array.isArray(value)) {\n // AND conditions\n for (const subCondition of value) {\n conditions.push(...Object.entries(subCondition).map(([k, v]) => ({ [k]: v })));\n }\n } else if (key === 'OR' && Array.isArray(value)) {\n // OR conditions - simplified\n conditions.push(...value.flatMap((v: any) => \n Object.entries(v).map(([k, val]) => ({ [k]: val }))\n ));\n } else if (typeof value === 'object' && value !== null) {\n // Operator-based conditions\n if (value.equals !== undefined) conditions.push({ [key]: value.equals });\n if (value.not_equals !== undefined) conditions.push({ [key]: { not: value.not_equals } });\n if (value.in) conditions.push({ [key]: { in: value.in } });\n if (value.like) conditions.push({ [key]: { like: value.like } });\n if (value.greater_than !== undefined) conditions.push({ [key]: { gt: value.greater_than } });\n if (value.greater_than_equal !== undefined) conditions.push({ [key]: { gte: value.greater_than_equal } });\n if (value.less_than !== undefined) conditions.push({ [key]: { lt: value.less_than } });\n if (value.less_than_equal !== undefined) conditions.push({ [key]: { lte: value.less_than_equal } });\n } else {\n // Direct equality\n conditions.push({ [key]: value });\n }\n }\n\n return conditions.length > 0 ? conditions : undefined;\n }\n\n private processResult(data: any, config: CollectionConfig): any {\n if (!data) return null;\n\n const result = { ...data };\n\n // Convert id field\n if (data.id) {\n result.id = String(data.id);\n }\n\n // Parse JSON fields\n for (const field of config.fields) {\n if (field.type === 'json' || field.type === 'richtext' || field.type === 'array' || field.type === 'group' || field.type === 'blocks') {\n if (result[field.name] && typeof result[field.name] === 'string') {\n try {\n result[field.name] = JSON.parse(result[field.name]);\n } catch {\n // Keep original value\n }\n }\n }\n }\n\n // Convert timestamps to ISO strings\n if (result.createdAt) {\n result.createdAt = new Date(result.createdAt).toISOString();\n }\n if (result.updatedAt) {\n result.updatedAt = new Date(result.updatedAt).toISOString();\n }\n\n return result;\n }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\nexport function createDrizzleAdapter(options: {\n type: 'postgres' | 'mysql' | 'sqlite';\n client: any;\n schema?: any;\n}): DrizzleAdapter {\n return new DrizzleAdapter(options);\n}\n"]}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
+
|
|
3
|
+
// src/api/ws/pubsub.ts
|
|
4
|
+
var PubSub = class {
|
|
5
|
+
channels = /* @__PURE__ */ new Map();
|
|
6
|
+
maxListeners;
|
|
7
|
+
constructor(maxListeners = 100) {
|
|
8
|
+
this.maxListeners = maxListeners;
|
|
9
|
+
}
|
|
10
|
+
subscribe(channel, handler) {
|
|
11
|
+
if (!this.channels.has(channel)) {
|
|
12
|
+
this.channels.set(channel, /* @__PURE__ */ new Set());
|
|
13
|
+
}
|
|
14
|
+
const handlers = this.channels.get(channel);
|
|
15
|
+
if (handlers.size >= this.maxListeners) {
|
|
16
|
+
throw new Error(`Max listeners (${this.maxListeners}) reached for channel "${channel}"`);
|
|
17
|
+
}
|
|
18
|
+
handlers.add(handler);
|
|
19
|
+
return () => {
|
|
20
|
+
handlers.delete(handler);
|
|
21
|
+
if (handlers.size === 0) {
|
|
22
|
+
this.channels.delete(channel);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
publish(channel, data) {
|
|
27
|
+
const handlers = this.channels.get(channel);
|
|
28
|
+
if (handlers) {
|
|
29
|
+
for (const handler of handlers) {
|
|
30
|
+
try {
|
|
31
|
+
const result = handler(data);
|
|
32
|
+
if (result instanceof Promise) {
|
|
33
|
+
result.catch((err) => {
|
|
34
|
+
console.error(`[PubSub] Error in handler for channel "${channel}":`, err);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error(`[PubSub] Error in handler for channel "${channel}":`, err);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
hasSubscribers(channel) {
|
|
44
|
+
return this.channels.has(channel) && this.channels.get(channel).size > 0;
|
|
45
|
+
}
|
|
46
|
+
getSubscriberCount(channel) {
|
|
47
|
+
return this.channels.get(channel)?.size || 0;
|
|
48
|
+
}
|
|
49
|
+
getChannels() {
|
|
50
|
+
return Array.from(this.channels.keys());
|
|
51
|
+
}
|
|
52
|
+
clear() {
|
|
53
|
+
this.channels.clear();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var KyroPubSub = class extends PubSub {
|
|
57
|
+
registry;
|
|
58
|
+
constructor(registry, maxListeners = 100) {
|
|
59
|
+
super(maxListeners);
|
|
60
|
+
this.registry = registry;
|
|
61
|
+
}
|
|
62
|
+
// Publish collection-level events
|
|
63
|
+
publishCollectionEvent(collection, event) {
|
|
64
|
+
this.publish(`collection:${collection}`, event);
|
|
65
|
+
this.publish("events:collection", event);
|
|
66
|
+
if (event.tenantID) {
|
|
67
|
+
this.publish(`tenant:${event.tenantID}:collection:${collection}`, event);
|
|
68
|
+
this.publish(`tenant:${event.tenantID}:events`, event);
|
|
69
|
+
}
|
|
70
|
+
this.publish(`collection:${collection}:${event.type}`, event);
|
|
71
|
+
}
|
|
72
|
+
// Subscribe to a collection
|
|
73
|
+
subscribeToCollection(collection, handler) {
|
|
74
|
+
return this.subscribe(`collection:${collection}`, handler);
|
|
75
|
+
}
|
|
76
|
+
// Subscribe to a specific event type on a collection
|
|
77
|
+
subscribeToCollectionEvent(collection, eventType, handler) {
|
|
78
|
+
return this.subscribe(`collection:${collection}:${eventType}`, handler);
|
|
79
|
+
}
|
|
80
|
+
// Subscribe to tenant-scoped events
|
|
81
|
+
subscribeToTenant(tenantID, handler) {
|
|
82
|
+
return this.subscribe(`tenant:${tenantID}:events`, handler);
|
|
83
|
+
}
|
|
84
|
+
// Subscribe to tenant + collection events
|
|
85
|
+
subscribeToTenantCollection(tenantID, collection, handler) {
|
|
86
|
+
return this.subscribe(`tenant:${tenantID}:collection:${collection}`, handler);
|
|
87
|
+
}
|
|
88
|
+
// Subscribe to all collection events
|
|
89
|
+
subscribeToAllCollections(handler) {
|
|
90
|
+
return this.subscribe("events:collection", handler);
|
|
91
|
+
}
|
|
92
|
+
// Create hooks for afterChange/afterDelete
|
|
93
|
+
createAfterChangeHook(collection) {
|
|
94
|
+
return async (args) => {
|
|
95
|
+
this.publishCollectionEvent(collection, {
|
|
96
|
+
type: args.operation === "create" ? "create" : "update",
|
|
97
|
+
collection,
|
|
98
|
+
doc: args.doc,
|
|
99
|
+
originalDoc: args.originalDoc,
|
|
100
|
+
id: args.id || args.doc?.id,
|
|
101
|
+
tenantID: args.tenantID,
|
|
102
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
103
|
+
user: args.user
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
createAfterDeleteHook(collection) {
|
|
108
|
+
return async (args) => {
|
|
109
|
+
this.publishCollectionEvent(collection, {
|
|
110
|
+
type: "delete",
|
|
111
|
+
collection,
|
|
112
|
+
doc: args.doc,
|
|
113
|
+
originalDoc: args.originalDoc,
|
|
114
|
+
id: args.id || args.doc?.id,
|
|
115
|
+
tenantID: args.tenantID,
|
|
116
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
117
|
+
user: args.user
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Auto-register hooks for all collections
|
|
122
|
+
autoRegisterHooks() {
|
|
123
|
+
const collections = this.registry.getCollections();
|
|
124
|
+
for (const collection of collections) {
|
|
125
|
+
const config = this.registry.getCollection(collection.slug);
|
|
126
|
+
if (config) {
|
|
127
|
+
if (!config.hooks) config.hooks = {};
|
|
128
|
+
if (!config.hooks.afterChange) config.hooks.afterChange = [];
|
|
129
|
+
if (!config.hooks.afterDelete) config.hooks.afterDelete = [];
|
|
130
|
+
config.hooks.afterChange.push(this.createAfterChangeHook(collection.slug));
|
|
131
|
+
config.hooks.afterDelete.push(this.createAfterDeleteHook(collection.slug));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var KyroWSServer = class {
|
|
137
|
+
wss;
|
|
138
|
+
clients = /* @__PURE__ */ new Map();
|
|
139
|
+
pubsub;
|
|
140
|
+
options;
|
|
141
|
+
pingTimer;
|
|
142
|
+
constructor(options) {
|
|
143
|
+
this.options = options;
|
|
144
|
+
this.pubsub = options.pubsub;
|
|
145
|
+
this.wss = new WebSocketServer({
|
|
146
|
+
port: options.port || 8080
|
|
147
|
+
});
|
|
148
|
+
this.setupServer();
|
|
149
|
+
this.startPingInterval();
|
|
150
|
+
}
|
|
151
|
+
setupServer() {
|
|
152
|
+
this.wss.on("connection", (ws, req) => {
|
|
153
|
+
const clientId = this.generateClientId();
|
|
154
|
+
if (this.options.maxConnections && this.clients.size >= this.options.maxConnections) {
|
|
155
|
+
ws.close(1013, "Server at capacity");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const client = {
|
|
159
|
+
id: clientId,
|
|
160
|
+
ws,
|
|
161
|
+
subscriptions: /* @__PURE__ */ new Map(),
|
|
162
|
+
authenticated: false,
|
|
163
|
+
connectedAt: /* @__PURE__ */ new Date(),
|
|
164
|
+
lastActivity: /* @__PURE__ */ new Date()
|
|
165
|
+
};
|
|
166
|
+
this.clients.set(clientId, client);
|
|
167
|
+
console.log(`[WS] Client connected: ${clientId} (total: ${this.clients.size})`);
|
|
168
|
+
this.sendToClient(client, {
|
|
169
|
+
type: "connected",
|
|
170
|
+
clientId,
|
|
171
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
172
|
+
});
|
|
173
|
+
ws.on("message", (data) => {
|
|
174
|
+
this.handleMessage(client, data);
|
|
175
|
+
});
|
|
176
|
+
ws.on("error", (error) => {
|
|
177
|
+
console.error(`[WS] Client error ${clientId}:`, error);
|
|
178
|
+
});
|
|
179
|
+
ws.on("close", () => {
|
|
180
|
+
this.handleDisconnect(client);
|
|
181
|
+
});
|
|
182
|
+
ws.on("pong", () => {
|
|
183
|
+
client.lastActivity = /* @__PURE__ */ new Date();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
this.wss.on("error", (error) => {
|
|
187
|
+
console.error("[WS] Server error:", error);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
handleMessage(client, data) {
|
|
191
|
+
client.lastActivity = /* @__PURE__ */ new Date();
|
|
192
|
+
let message;
|
|
193
|
+
try {
|
|
194
|
+
message = JSON.parse(data.toString());
|
|
195
|
+
} catch {
|
|
196
|
+
this.sendToClient(client, {
|
|
197
|
+
type: "error",
|
|
198
|
+
error: "Invalid JSON"
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
switch (message.type) {
|
|
203
|
+
case "authenticate":
|
|
204
|
+
this.handleAuthenticate(client, message);
|
|
205
|
+
break;
|
|
206
|
+
case "subscribe":
|
|
207
|
+
this.handleSubscribe(client, message);
|
|
208
|
+
break;
|
|
209
|
+
case "unsubscribe":
|
|
210
|
+
this.handleUnsubscribe(client, message);
|
|
211
|
+
break;
|
|
212
|
+
case "unsubscribeAll":
|
|
213
|
+
this.handleUnsubscribeAll(client);
|
|
214
|
+
break;
|
|
215
|
+
case "list":
|
|
216
|
+
this.handleList(client);
|
|
217
|
+
break;
|
|
218
|
+
case "ping":
|
|
219
|
+
this.sendToClient(client, { type: "pong", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
220
|
+
break;
|
|
221
|
+
default:
|
|
222
|
+
this.sendToClient(client, {
|
|
223
|
+
type: "error",
|
|
224
|
+
error: `Unknown message type: ${message.type}`
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async handleAuthenticate(client, message) {
|
|
229
|
+
if (!this.options.requireAuth) {
|
|
230
|
+
client.authenticated = true;
|
|
231
|
+
this.sendToClient(client, {
|
|
232
|
+
type: "authenticated",
|
|
233
|
+
success: true
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!this.options.verifyToken) {
|
|
238
|
+
client.authenticated = true;
|
|
239
|
+
this.sendToClient(client, {
|
|
240
|
+
type: "authenticated",
|
|
241
|
+
success: true
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const user = await this.options.verifyToken(message.token);
|
|
247
|
+
client.authenticated = true;
|
|
248
|
+
client.user = user;
|
|
249
|
+
client.tenantID = user.tenantID;
|
|
250
|
+
this.sendToClient(client, {
|
|
251
|
+
type: "authenticated",
|
|
252
|
+
success: true,
|
|
253
|
+
user: { id: user.id, email: user.email }
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
this.sendToClient(client, {
|
|
257
|
+
type: "authenticated",
|
|
258
|
+
success: false,
|
|
259
|
+
error: error.message
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
handleSubscribe(client, message) {
|
|
264
|
+
if (this.options.requireAuth && !client.authenticated) {
|
|
265
|
+
this.sendToClient(client, {
|
|
266
|
+
type: "error",
|
|
267
|
+
error: "Not authenticated"
|
|
268
|
+
});
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const channel = message.channel;
|
|
272
|
+
if (!channel) {
|
|
273
|
+
this.sendToClient(client, {
|
|
274
|
+
type: "error",
|
|
275
|
+
error: "Channel is required"
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (client.subscriptions.has(channel)) {
|
|
280
|
+
this.sendToClient(client, {
|
|
281
|
+
type: "subscribed",
|
|
282
|
+
channel,
|
|
283
|
+
success: true,
|
|
284
|
+
message: "Already subscribed"
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const unsubscribe = this.pubsub.subscribe(channel, (data) => {
|
|
289
|
+
this.sendToClient(client, {
|
|
290
|
+
type: "event",
|
|
291
|
+
channel,
|
|
292
|
+
data,
|
|
293
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
client.subscriptions.set(channel, { channel, unsubscribe });
|
|
297
|
+
this.sendToClient(client, {
|
|
298
|
+
type: "subscribed",
|
|
299
|
+
channel,
|
|
300
|
+
success: true
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
handleUnsubscribe(client, message) {
|
|
304
|
+
const channel = message.channel;
|
|
305
|
+
if (!channel) {
|
|
306
|
+
this.sendToClient(client, {
|
|
307
|
+
type: "error",
|
|
308
|
+
error: "Channel is required"
|
|
309
|
+
});
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const subscription = client.subscriptions.get(channel);
|
|
313
|
+
if (subscription) {
|
|
314
|
+
subscription.unsubscribe();
|
|
315
|
+
client.subscriptions.delete(channel);
|
|
316
|
+
this.sendToClient(client, {
|
|
317
|
+
type: "unsubscribed",
|
|
318
|
+
channel,
|
|
319
|
+
success: true
|
|
320
|
+
});
|
|
321
|
+
} else {
|
|
322
|
+
this.sendToClient(client, {
|
|
323
|
+
type: "unsubscribed",
|
|
324
|
+
channel,
|
|
325
|
+
success: false,
|
|
326
|
+
message: "Not subscribed"
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
handleUnsubscribeAll(client) {
|
|
331
|
+
for (const [, subscription] of client.subscriptions) {
|
|
332
|
+
subscription.unsubscribe();
|
|
333
|
+
}
|
|
334
|
+
client.subscriptions.clear();
|
|
335
|
+
this.sendToClient(client, {
|
|
336
|
+
type: "unsubscribedAll",
|
|
337
|
+
success: true
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
handleList(client) {
|
|
341
|
+
const channels = this.pubsub.getChannels();
|
|
342
|
+
this.sendToClient(client, {
|
|
343
|
+
type: "channels",
|
|
344
|
+
channels,
|
|
345
|
+
count: channels.length
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
handleDisconnect(client) {
|
|
349
|
+
for (const [, subscription] of client.subscriptions) {
|
|
350
|
+
subscription.unsubscribe();
|
|
351
|
+
}
|
|
352
|
+
this.clients.delete(client.id);
|
|
353
|
+
console.log(`[WS] Client disconnected: ${client.id} (total: ${this.clients.size})`);
|
|
354
|
+
}
|
|
355
|
+
sendToClient(client, data) {
|
|
356
|
+
if (client.ws.readyState === WebSocket.OPEN) {
|
|
357
|
+
client.ws.send(JSON.stringify(data));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
generateClientId() {
|
|
361
|
+
return `ws_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
362
|
+
}
|
|
363
|
+
startPingInterval() {
|
|
364
|
+
if (!this.options.pingInterval) return;
|
|
365
|
+
this.pingTimer = setInterval(() => {
|
|
366
|
+
for (const [id, client] of this.clients) {
|
|
367
|
+
if (client.ws.readyState === WebSocket.OPEN) {
|
|
368
|
+
const timeSinceLastActivity = Date.now() - client.lastActivity.getTime();
|
|
369
|
+
if (timeSinceLastActivity > this.options.pingInterval * 3) {
|
|
370
|
+
console.log(`[WS] Client ${id} timed out`);
|
|
371
|
+
client.ws.terminate();
|
|
372
|
+
this.handleDisconnect(client);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
client.ws.ping();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}, this.options.pingInterval);
|
|
379
|
+
}
|
|
380
|
+
// ============================================================================
|
|
381
|
+
// Public API
|
|
382
|
+
// ============================================================================
|
|
383
|
+
broadcast(channel, data) {
|
|
384
|
+
this.pubsub.publish(channel, data);
|
|
385
|
+
}
|
|
386
|
+
getConnectedClients() {
|
|
387
|
+
return Array.from(this.clients.values());
|
|
388
|
+
}
|
|
389
|
+
getClientCount() {
|
|
390
|
+
return this.clients.size;
|
|
391
|
+
}
|
|
392
|
+
getSubscriptionCount() {
|
|
393
|
+
let count = 0;
|
|
394
|
+
for (const client of this.clients.values()) {
|
|
395
|
+
count += client.subscriptions.size;
|
|
396
|
+
}
|
|
397
|
+
return count;
|
|
398
|
+
}
|
|
399
|
+
async close() {
|
|
400
|
+
if (this.pingTimer) {
|
|
401
|
+
clearInterval(this.pingTimer);
|
|
402
|
+
}
|
|
403
|
+
for (const client of this.clients.values()) {
|
|
404
|
+
client.ws.close(1001, "Server shutting down");
|
|
405
|
+
}
|
|
406
|
+
return new Promise((resolve) => {
|
|
407
|
+
this.wss.close(() => {
|
|
408
|
+
console.log("[WS] Server closed");
|
|
409
|
+
resolve();
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
getServer() {
|
|
414
|
+
return this.wss;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
function createWSServer(options) {
|
|
418
|
+
return new KyroWSServer(options);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export { KyroPubSub, KyroWSServer, PubSub, createWSServer };
|
|
422
|
+
//# sourceMappingURL=chunk-3TPQ2BU6.js.map
|
|
423
|
+
//# sourceMappingURL=chunk-3TPQ2BU6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api/ws/pubsub.ts","../src/api/ws/server.ts"],"names":[],"mappings":"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","file":"chunk-3TPQ2BU6.js","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"]}
|