@fitzzero/quickdraw-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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shared/types.ts","../../src/server/BaseService.ts","../../src/server/ServiceRegistry.ts","../../src/server/createServer.ts","../../src/server/auth/jwt.ts","../../src/server/auth/oauth.ts","../../src/server/auth/discord.ts","../../src/server/auth/google.ts"],"names":["result","SocketIOServer"],"mappings":"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","file":"index.js","sourcesContent":["import type { z } from \"zod\";\n\n// ============================================================================\n// Access Control Types\n// ============================================================================\n\nexport type AccessLevel = \"Public\" | \"Read\" | \"Moderate\" | \"Admin\";\n\nexport type ACE = {\n userId: string;\n level: AccessLevel;\n};\n\nexport type ACL = ACE[];\n\n// ============================================================================\n// Service Response Types\n// ============================================================================\n\nexport type ServiceResponse<T = unknown> =\n | { success: true; data: T }\n | { success: false; error: string; code?: number };\n\n// ============================================================================\n// Service Method Definition Types\n// ============================================================================\n\n/**\n * Defines the shape of a service method including its payload and response types.\n * Used to create a type-safe contract between server and client.\n */\nexport interface ServiceMethodDefinition<\n TPayload = unknown,\n TResponse = unknown,\n> {\n name: string;\n access: AccessLevel;\n handler: (\n payload: TPayload,\n context: ServiceMethodContext\n ) => Promise<TResponse>;\n schema?: z.ZodType<TPayload>;\n resolveEntryId?: (payload: TPayload) => string | null;\n}\n\n/**\n * Context provided to service method handlers\n */\nexport interface ServiceMethodContext {\n userId: string | undefined;\n socketId: string;\n serviceAccess: Record<string, AccessLevel>;\n}\n\n/**\n * Type helper for defining service method maps.\n * Each service should define its methods using this structure.\n *\n * @example\n * ```typescript\n * type ChatServiceMethods = ServiceMethodMap<{\n * createChat: {\n * payload: { title: string };\n * response: { id: string };\n * };\n * updateTitle: {\n * payload: { id: string; title: string };\n * response: { id: string; title: string };\n * };\n * }>;\n * ```\n */\nexport type ServiceMethodMap<\n T extends Record<string, { payload: unknown; response: unknown }>,\n> = T;\n\n// ============================================================================\n// Admin Method Types (Generic shapes for all services)\n// ============================================================================\n\nexport type AdminListPayload = {\n page?: number;\n pageSize?: number;\n sort?: {\n field?: string;\n direction?: \"asc\" | \"desc\";\n };\n filter?: {\n id?: string;\n ids?: string[];\n createdAfter?: string;\n createdBefore?: string;\n updatedAfter?: string;\n updatedBefore?: string;\n } & Record<string, unknown>;\n};\n\nexport type AdminListResponse<T> = {\n rows: T[];\n page: number;\n pageSize: number;\n total: number;\n};\n\nexport type AdminGetPayload = { id: string };\n\nexport type AdminCreatePayload<TInsert> = { data: Partial<TInsert> };\n\nexport type AdminUpdatePayload<TInsert> = {\n id: string;\n data: Partial<TInsert>;\n};\n\nexport type AdminDeletePayload = { id: string };\nexport type AdminDeleteResponse = { id: string; deleted: true };\n\nexport type AdminSetEntryACLPayload = {\n id: string;\n acl: ACL;\n};\n\nexport type AdminGetSubscribersPayload = { id: string };\nexport type AdminGetSubscribersResponse = {\n id: string;\n subscribers: Array<{ socketId: string; userId?: string }>;\n};\n\nexport type AdminReemitPayload = { id: string };\nexport type AdminReemitResponse = { emitted: boolean };\n\nexport type AdminUnsubscribeAllPayload = { id: string };\nexport type AdminUnsubscribeAllResponse = { id: string; unsubscribed: number };\n\n// ============================================================================\n// Subscription Types\n// ============================================================================\n\nexport type SubscribePayload = {\n entryId: string;\n requiredLevel?: AccessLevel;\n};\n\nexport type UnsubscribePayload = {\n entryId: string;\n};\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Extracts payload type from a service method definition\n */\nexport type ExtractPayload<T> = T extends { payload: infer P } ? P : never;\n\n/**\n * Extracts response type from a service method definition\n */\nexport type ExtractResponse<T> = T extends { response: infer R } ? R : never;\n\n/**\n * Logger interface compatible with Winston and other loggers\n */\nexport interface Logger {\n info(message: string, meta?: Record<string, unknown>): void;\n warn(message: string, meta?: Record<string, unknown>): void;\n error(message: string, meta?: Record<string, unknown>): void;\n debug(message: string, meta?: Record<string, unknown>): void;\n child(options: Record<string, unknown>): Logger;\n}\n\n/**\n * Default console logger implementation\n */\nexport const consoleLogger: Logger = {\n info: (message, meta) => console.log(`[INFO] ${message}`, meta ?? \"\"),\n warn: (message, meta) => console.warn(`[WARN] ${message}`, meta ?? \"\"),\n error: (message, meta) => console.error(`[ERROR] ${message}`, meta ?? \"\"),\n debug: (message, meta) => console.debug(`[DEBUG] ${message}`, meta ?? \"\"),\n child: () => consoleLogger,\n};\n","import type { z } from \"zod\";\nimport type {\n AccessLevel,\n ServiceMethodDefinition,\n ServiceMethodContext,\n Logger,\n ACL,\n} from \"../shared/types\";\nimport { consoleLogger } from \"../shared/types\";\nimport type {\n QuickdrawSocket,\n BaseServiceOptions,\n InstallAdminMethodsOptions,\n PrismaDelegate,\n} from \"./types\";\n\n/**\n * Base class for all quickdraw services.\n *\n * Provides:\n * - Typed CRUD operations with auto-emit to subscribers\n * - Real-time subscription management\n * - ACL-based access control (service-level and entry-level)\n * - Public method definition with type inference\n * - Admin method scaffolding\n *\n * @typeParam TEntity - The entity type (e.g., Prisma model type)\n * @typeParam TCreateInput - The create input type\n * @typeParam TUpdateInput - The update input type\n * @typeParam TServiceMethods - Service method definitions map\n *\n * @example\n * ```typescript\n * class ChatService extends BaseService<\n * Chat,\n * Prisma.ChatCreateInput,\n * Prisma.ChatUpdateInput,\n * ChatServiceMethods\n * > {\n * constructor(prisma: PrismaClient) {\n * super({\n * serviceName: 'chatService',\n * hasEntryACL: true,\n * });\n * this.setDelegate(prisma.chat);\n * }\n * }\n * ```\n */\nexport abstract class BaseService<\n TEntity extends { id: string },\n TCreateInput extends Record<string, unknown>,\n TUpdateInput extends Record<string, unknown>,\n TServiceMethods extends Record<\n string,\n { payload: unknown; response: unknown }\n > = Record<string, { payload: unknown; response: unknown }>,\n> {\n public readonly serviceName: string;\n protected readonly hasEntryACL: boolean;\n protected readonly defaultACL: ACL;\n protected readonly logger: Logger;\n\n // Subscription tracking: entryId -> Set of sockets\n protected readonly subscribers: Map<string, Set<QuickdrawSocket>> = new Map();\n\n // Prisma delegate for DB operations\n protected delegate:\n | PrismaDelegate<TEntity, TCreateInput, TUpdateInput>\n | undefined;\n\n // Collection of public methods for registry discovery\n private readonly publicMethods: Map<\n string,\n ServiceMethodDefinition<unknown, unknown>\n > = new Map();\n\n constructor(options: BaseServiceOptions) {\n this.serviceName = options.serviceName;\n this.hasEntryACL = options.hasEntryACL ?? false;\n this.defaultACL = options.defaultACL ?? [];\n this.logger = options.logger?.child({ service: this.serviceName }) ??\n consoleLogger.child({ service: this.serviceName });\n }\n\n /**\n * Set the Prisma delegate for this service.\n * Must be called in the constructor of derived classes.\n */\n protected setDelegate(\n delegate: PrismaDelegate<TEntity, TCreateInput, TUpdateInput>\n ): void {\n this.delegate = delegate;\n }\n\n /**\n * Get the delegate, throwing if not set.\n */\n protected getDelegate(): PrismaDelegate<TEntity, TCreateInput, TUpdateInput> {\n if (!this.delegate) {\n throw new Error(\n `Delegate not set for service ${this.serviceName}. Call setDelegate() in constructor.`\n );\n }\n return this.delegate;\n }\n\n // ===========================================================================\n // Subscription Management\n // ===========================================================================\n\n /**\n * Subscribe a socket to an entity's updates.\n * Returns the current entity data if access is granted, null otherwise.\n */\n public async subscribe(\n entryId: string,\n socket: QuickdrawSocket,\n requiredLevel: AccessLevel = \"Read\"\n ): Promise<TEntity | null> {\n if (!socket.userId) {\n return null;\n }\n\n // Check access\n const allowed = await this.checkSubscriptionAccess(\n socket.userId,\n entryId,\n requiredLevel,\n socket\n );\n\n if (!allowed) {\n return null;\n }\n\n // Add to subscribers\n if (!this.subscribers.has(entryId)) {\n this.subscribers.set(entryId, new Set());\n }\n this.subscribers.get(entryId)!.add(socket);\n\n this.logger.debug(`User ${socket.userId} subscribed to ${entryId}`);\n\n // Return current entity data\n const entity = await this.findById(entryId);\n return entity;\n }\n\n /**\n * Unsubscribe a socket from an entity's updates.\n */\n public unsubscribe(entryId: string, socket: QuickdrawSocket): void {\n const subs = this.subscribers.get(entryId);\n if (subs) {\n subs.delete(socket);\n if (subs.size === 0) {\n this.subscribers.delete(entryId);\n }\n }\n }\n\n /**\n * Remove a socket from all subscriptions (called on disconnect).\n */\n public unsubscribeSocket(socket: QuickdrawSocket): void {\n for (const [entryId, sockets] of this.subscribers.entries()) {\n if (sockets.has(socket)) {\n sockets.delete(socket);\n if (sockets.size === 0) {\n this.subscribers.delete(entryId);\n }\n }\n }\n }\n\n /**\n * Emit an update to all subscribers of an entity.\n */\n protected emitUpdate(entryId: string, data: Partial<TEntity>): void {\n const eventName = `${this.serviceName}:update:${entryId}`;\n const subs = this.subscribers.get(entryId);\n\n if (subs) {\n for (const socket of subs) {\n socket.emit(eventName, data);\n }\n }\n }\n\n // ===========================================================================\n // Access Control\n // ===========================================================================\n\n /**\n * Check if a user has access to subscribe to an entity.\n * Override in derived classes for custom logic.\n */\n protected async checkSubscriptionAccess(\n userId: string,\n entryId: string,\n requiredLevel: AccessLevel,\n socket: QuickdrawSocket\n ): Promise<boolean> {\n // First check service-level access\n if (this.hasServiceAccess(socket, requiredLevel)) {\n return true;\n }\n\n // Then check via checkAccess (which derived classes can override)\n if (this.checkAccess(userId, entryId, requiredLevel, socket)) {\n return true;\n }\n\n // Finally check entry-level ACL if enabled\n if (this.hasEntryACL) {\n return await this.checkEntryACL(userId, entryId, requiredLevel);\n }\n\n return false;\n }\n\n /**\n * Check if a socket has service-level access.\n */\n protected hasServiceAccess(\n socket: QuickdrawSocket,\n requiredLevel: AccessLevel\n ): boolean {\n const userLevel = socket.serviceAccess?.[this.serviceName];\n if (!userLevel) return false;\n return this.isLevelSufficient(userLevel, requiredLevel);\n }\n\n /**\n * Check if a user has access to an entity.\n * Override in derived classes for custom logic (e.g., self-access).\n */\n protected checkAccess(\n _userId: string,\n _entryId: string,\n _requiredLevel: AccessLevel,\n _socket: QuickdrawSocket\n ): boolean {\n // Default: deny (override in derived classes)\n return false;\n }\n\n /**\n * Check entry-level ACL stored on the entity.\n */\n protected async checkEntryACL(\n userId: string,\n entryId: string,\n requiredLevel: AccessLevel\n ): Promise<boolean> {\n try {\n const entity = await this.getDelegate().findUnique({\n where: { id: entryId } as { id: string },\n select: { acl: true } as Record<string, boolean>,\n });\n\n const acl = (entity as unknown as { acl?: ACL })?.acl;\n if (!acl || !Array.isArray(acl)) return false;\n\n const ace = acl.find((a) => a.userId === userId);\n if (!ace) return false;\n\n return this.isLevelSufficient(ace.level, requiredLevel);\n } catch {\n return false;\n }\n }\n\n /**\n * Compare access levels.\n */\n protected isLevelSufficient(\n userLevel: AccessLevel,\n requiredLevel: AccessLevel\n ): boolean {\n const order: Record<AccessLevel, number> = {\n Public: 0,\n Read: 1,\n Moderate: 2,\n Admin: 3,\n };\n return (order[userLevel] ?? 0) >= (order[requiredLevel] ?? 0);\n }\n\n /**\n * Ensure access for a public method.\n * Throws if access is denied.\n */\n public async ensureAccessForMethod(\n requiredLevel: AccessLevel,\n socket: QuickdrawSocket,\n entryId?: string\n ): Promise<void> {\n if (requiredLevel === \"Public\") {\n return;\n }\n\n if (!socket.userId) {\n throw new Error(\"Authentication required\");\n }\n\n // Service-level access is always sufficient\n if (this.hasServiceAccess(socket, requiredLevel)) {\n return;\n }\n\n // For entry-scoped methods, check entry access\n if (entryId) {\n if (this.checkAccess(socket.userId, entryId, requiredLevel, socket)) {\n return;\n }\n if (\n this.hasEntryACL &&\n (await this.checkEntryACL(socket.userId, entryId, requiredLevel))\n ) {\n return;\n }\n throw new Error(\"Insufficient permissions\");\n }\n\n // Non-entry-scoped Read methods are allowed for authenticated users\n if (requiredLevel === \"Read\") {\n return;\n }\n\n throw new Error(\"Insufficient permissions\");\n }\n\n // ===========================================================================\n // CRUD Operations\n // ===========================================================================\n\n /**\n * Find an entity by ID.\n */\n protected async findById(id: string): Promise<TEntity | null> {\n return await this.getDelegate().findUnique({\n where: { id } as { id: string },\n });\n }\n\n /**\n * Create an entity and emit to subscribers.\n */\n protected async create(data: TCreateInput): Promise<TEntity> {\n const entity = await this.getDelegate().create({ data });\n this.emitUpdate(entity.id, entity);\n this.logger.info(`Created entity ${entity.id}`);\n return entity;\n }\n\n /**\n * Update an entity and emit to subscribers.\n */\n protected async update(\n id: string,\n data: TUpdateInput\n ): Promise<TEntity | null> {\n try {\n const entity = await this.getDelegate().update({\n where: { id } as { id: string },\n data,\n });\n this.emitUpdate(id, entity);\n this.logger.info(`Updated entity ${id}`);\n return entity;\n } catch {\n return null;\n }\n }\n\n /**\n * Delete an entity and emit deletion event to subscribers.\n */\n protected async delete(id: string): Promise<boolean> {\n try {\n await this.getDelegate().delete({\n where: { id } as { id: string },\n });\n this.emitUpdate(id, { id, deleted: true } as unknown as Partial<TEntity>);\n this.logger.info(`Deleted entity ${id}`);\n return true;\n } catch {\n return false;\n }\n }\n\n // ===========================================================================\n // Public Method Definition\n // ===========================================================================\n\n /**\n * Define a public method that will be exposed via Socket.io.\n *\n * @typeParam K - Method name from the service methods map\n */\n protected defineMethod<K extends keyof TServiceMethods & string>(\n name: K,\n access: AccessLevel,\n handler: (\n payload: TServiceMethods[K][\"payload\"],\n context: ServiceMethodContext\n ) => Promise<TServiceMethods[K][\"response\"]>,\n options?: {\n schema?: z.ZodType<TServiceMethods[K][\"payload\"]>;\n resolveEntryId?: (payload: TServiceMethods[K][\"payload\"]) => string | null;\n }\n ): ServiceMethodDefinition<\n TServiceMethods[K][\"payload\"],\n TServiceMethods[K][\"response\"]\n > {\n const definition: ServiceMethodDefinition<\n TServiceMethods[K][\"payload\"],\n TServiceMethods[K][\"response\"]\n > = {\n name,\n access,\n handler: handler as (\n payload: TServiceMethods[K][\"payload\"],\n context: ServiceMethodContext\n ) => Promise<TServiceMethods[K][\"response\"]>,\n schema: options?.schema,\n resolveEntryId: options?.resolveEntryId,\n };\n\n this.publicMethods.set(\n name,\n definition as ServiceMethodDefinition<unknown, unknown>\n );\n return definition;\n }\n\n /**\n * Get all public methods for registry discovery.\n */\n public getPublicMethods(): ServiceMethodDefinition<unknown, unknown>[] {\n return Array.from(this.publicMethods.values());\n }\n\n // ===========================================================================\n // Admin Methods (Scaffolding)\n // ===========================================================================\n\n /**\n * Install standard admin CRUD methods.\n * Call this in derived class constructor to expose admin endpoints.\n */\n protected installAdminMethods(_options: InstallAdminMethodsOptions): void {\n // Implementation will be added in base-service-rewrite todo\n // This is a placeholder to establish the API\n this.logger.debug(\"Admin methods installation placeholder\");\n }\n\n // ===========================================================================\n // Utility Methods\n // ===========================================================================\n\n /**\n * Fields that should never be exposed or editable via admin methods.\n */\n protected getDefaultDeniedFields(): string[] {\n return [\"id\", \"createdAt\", \"updatedAt\", \"acl\", \"serviceAccess\"];\n }\n}\n","import type { Server as SocketIOServer } from \"socket.io\";\nimport type {\n ServiceResponse,\n ServiceMethodDefinition,\n Logger,\n} from \"../shared/types\";\nimport { consoleLogger } from \"../shared/types\";\nimport type {\n QuickdrawSocket,\n BaseServiceInstance,\n ServiceRegistryInstance,\n} from \"./types\";\n\n/**\n * Central registry for auto-discovering and registering service methods as Socket.io events.\n *\n * Features:\n * - Auto-discovers public methods from registered services\n * - Wires methods to Socket.io events with standardized naming\n * - Handles subscription lifecycle\n * - Provides consistent error handling and logging\n *\n * @example\n * ```typescript\n * const registry = new ServiceRegistry(io, { logger });\n * registry.registerService('chatService', chatService);\n * registry.registerService('userService', userService);\n * ```\n */\nexport class ServiceRegistry implements ServiceRegistryInstance {\n private readonly io: SocketIOServer;\n private readonly services: Map<string, BaseServiceInstance> = new Map();\n private readonly logger: Logger;\n\n constructor(io: SocketIOServer, options?: { logger?: Logger }) {\n this.io = io;\n this.logger = options?.logger?.child({ service: \"ServiceRegistry\" }) ??\n consoleLogger.child({ service: \"ServiceRegistry\" });\n }\n\n /**\n * Register a service and auto-discover its public methods.\n */\n public registerService(\n serviceName: string,\n service: BaseServiceInstance\n ): void {\n this.services.set(serviceName, service);\n this.logger.info(`Registered service: ${serviceName}`);\n\n // Auto-discover and wire public methods\n this.discoverServiceMethods(serviceName, service);\n }\n\n /**\n * Discover and register all public methods from a service.\n */\n private discoverServiceMethods(\n serviceName: string,\n service: BaseServiceInstance\n ): void {\n const methods = service.getPublicMethods();\n\n for (const method of methods) {\n const eventName = `${serviceName}:${method.name}`;\n this.logger.info(`Registering socket event: ${eventName}`);\n\n // Register on connection\n this.io.on(\"connection\", (socket) => {\n this.registerMethodListener(\n socket as QuickdrawSocket,\n eventName,\n method,\n service\n );\n });\n }\n\n // Register subscription handlers\n this.io.on(\"connection\", (socket) => {\n this.registerSubscriptionListener(\n socket as QuickdrawSocket,\n `${serviceName}:subscribe`,\n service\n );\n this.registerUnsubscriptionListener(\n socket as QuickdrawSocket,\n `${serviceName}:unsubscribe`,\n service\n );\n });\n }\n\n /**\n * Register a method as a socket event listener.\n */\n private registerMethodListener(\n socket: QuickdrawSocket,\n eventName: string,\n method: ServiceMethodDefinition<unknown, unknown>,\n service: BaseServiceInstance\n ): void {\n socket.on(\n eventName,\n async (\n payload: unknown,\n callback?: (response: ServiceResponse<unknown>) => void\n ) => {\n const startedAt = Date.now();\n const [serviceName, methodName] = eventName.split(\":\");\n const userIdShort = socket.userId?.slice(0, 8) ?? \"anon\";\n\n try {\n // Authentication check\n if (!socket.userId && method.access !== \"Public\") {\n const errorResponse: ServiceResponse<unknown> = {\n success: false,\n error: \"Authentication required\",\n code: 401,\n };\n callback?.(errorResponse);\n return;\n }\n\n // Validate payload with Zod schema if provided\n let validatedPayload = payload;\n if (method.schema) {\n const result = method.schema.safeParse(payload);\n if (!result.success) {\n const errorResponse: ServiceResponse<unknown> = {\n success: false,\n error: `Validation error: ${result.error.message}`,\n code: 400,\n };\n callback?.(errorResponse);\n return;\n }\n validatedPayload = result.data;\n }\n\n // Resolve entry ID for access check\n let entryId: string | undefined;\n if (method.resolveEntryId) {\n entryId = method.resolveEntryId(validatedPayload) ?? undefined;\n } else if (\n validatedPayload &&\n typeof validatedPayload === \"object\" &&\n \"id\" in validatedPayload\n ) {\n const idValue = (validatedPayload as Record<string, unknown>).id;\n if (typeof idValue === \"string\") {\n entryId = idValue;\n }\n }\n\n // Check access\n await service.ensureAccessForMethod(method.access, socket, entryId);\n\n // Log start\n this.logger.info(\n `User ${userIdShort} ${serviceName}.${methodName} -> start`,\n {\n category: \"request_processing\",\n serviceName,\n methodName,\n userId: socket.userId,\n socketId: socket.id,\n }\n );\n\n // Execute handler\n const result = await method.handler(validatedPayload, {\n userId: socket.userId,\n socketId: socket.id,\n serviceAccess: socket.serviceAccess ?? {},\n });\n\n const durationMs = Date.now() - startedAt;\n this.logger.info(\n `User ${userIdShort} ${serviceName}.${methodName} -> success`,\n {\n category: \"request_processing\",\n outcome: \"success\",\n durationMs,\n serviceName,\n methodName,\n userId: socket.userId,\n }\n );\n\n const successResponse: ServiceResponse<unknown> = {\n success: true,\n data: result,\n };\n callback?.(successResponse);\n } catch (error) {\n const durationMs = Date.now() - startedAt;\n this.logger.error(\n `User ${userIdShort} ${serviceName}.${methodName} -> fail`,\n {\n category: \"request_processing\",\n outcome: \"fail\",\n durationMs,\n error: error instanceof Error ? error.message : \"Unknown error\",\n }\n );\n\n const errorResponse: ServiceResponse<unknown> = {\n success: false,\n error: error instanceof Error ? error.message : \"Internal error\",\n code: 500,\n };\n callback?.(errorResponse);\n }\n }\n );\n }\n\n /**\n * Register subscription listener for a service.\n */\n private registerSubscriptionListener(\n socket: QuickdrawSocket,\n eventName: string,\n service: BaseServiceInstance\n ): void {\n socket.on(\n eventName,\n async (\n payload: { entryId: string; requiredLevel?: string },\n callback?: (response: ServiceResponse<unknown>) => void\n ) => {\n try {\n if (!socket.userId) {\n callback?.({\n success: false,\n error: \"Authentication required\",\n code: 401,\n });\n return;\n }\n\n const data = await service.subscribe(\n payload.entryId,\n socket,\n (payload.requiredLevel as \"Read\" | \"Moderate\" | \"Admin\") ?? \"Read\"\n );\n\n if (data === null) {\n callback?.({\n success: false,\n error: \"Access denied or entry not found\",\n code: 403,\n });\n return;\n }\n\n callback?.({ success: true, data });\n } catch (error) {\n this.logger.error(`Error in subscription ${eventName}:`, {\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n callback?.({\n success: false,\n error: error instanceof Error ? error.message : \"Subscription failed\",\n });\n }\n }\n );\n }\n\n /**\n * Register unsubscription listener for a service.\n */\n private registerUnsubscriptionListener(\n socket: QuickdrawSocket,\n eventName: string,\n service: BaseServiceInstance\n ): void {\n socket.on(\n eventName,\n (\n payload: { entryId: string },\n callback?: (\n response: ServiceResponse<{ unsubscribed: true; entryId: string }>\n ) => void\n ) => {\n try {\n service.unsubscribe(payload.entryId, socket);\n callback?.({\n success: true,\n data: { unsubscribed: true, entryId: payload.entryId },\n });\n } catch (error) {\n this.logger.error(`Error in unsubscription ${eventName}:`, {\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n callback?.({\n success: false,\n error: error instanceof Error ? error.message : \"Unsubscription failed\",\n });\n }\n }\n );\n }\n\n /**\n * Get list of registered service names.\n */\n public getServices(): string[] {\n return Array.from(this.services.keys());\n }\n\n /**\n * Get all service instances for lifecycle management.\n */\n public getServiceInstances(): BaseServiceInstance[] {\n return Array.from(this.services.values());\n }\n}\n","import express from \"express\";\nimport { createServer } from \"http\";\nimport { Server as SocketIOServer } from \"socket.io\";\nimport { consoleLogger } from \"../shared/types\";\nimport type {\n QuickdrawSocket,\n QuickdrawServerOptions,\n QuickdrawServerResult,\n} from \"./types\";\nimport { ServiceRegistry } from \"./ServiceRegistry\";\n\n/**\n * Create a fully configured quickdraw server with one function call.\n *\n * @example\n * ```typescript\n * import { createQuickdrawServer } from '@quickdraw/core/server';\n * import { ChatService, UserService } from './services';\n *\n * const { io, httpServer, registry } = createQuickdrawServer({\n * port: 4000,\n * cors: { origin: 'http://localhost:3000' },\n * services: {\n * chatService: new ChatService(prisma),\n * userService: new UserService(prisma),\n * },\n * auth: {\n * authenticate: async (socket, auth) => {\n * // Verify JWT and return userId\n * const payload = await verifyJWT(auth.token);\n * return payload.userId;\n * },\n * },\n * });\n * ```\n */\nexport function createQuickdrawServer(\n options: QuickdrawServerOptions\n): QuickdrawServerResult {\n const logger = options.logger ?? consoleLogger;\n const serverLogger = logger.child({ service: \"QuickdrawServer\" });\n\n // Create Express app with basic middleware\n const app = express();\n app.use(express.json());\n\n // Health check endpoint\n app.get(\"/health\", (_req, res) => {\n res.json({ status: \"ok\", timestamp: new Date().toISOString() });\n });\n\n // Create HTTP server\n const httpServer = createServer(app);\n\n // Create Socket.io server\n const io = new SocketIOServer(httpServer, {\n cors: {\n origin: options.cors?.origin ?? \"*\",\n methods: options.cors?.methods ?? [\"GET\", \"POST\"],\n credentials: options.cors?.credentials ?? true,\n },\n });\n\n // Create service registry\n const registry = new ServiceRegistry(io, { logger });\n\n // Apply authentication middleware\n io.use(async (socket, next) => {\n const quickdrawSocket = socket as QuickdrawSocket;\n\n try {\n if (options.auth?.authenticate) {\n const auth = socket.handshake.auth as Record<string, unknown>;\n const userId = await options.auth.authenticate(quickdrawSocket, auth);\n quickdrawSocket.userId = userId;\n\n // TODO: Load service access from user record\n // For now, default to empty service access\n quickdrawSocket.serviceAccess = {};\n }\n next();\n } catch (error) {\n serverLogger.error(\"Authentication failed\", {\n error: error instanceof Error ? error.message : \"Unknown error\",\n socketId: socket.id,\n });\n next(new Error(\"Authentication failed\"));\n }\n });\n\n // Register services\n for (const [serviceName, service] of Object.entries(options.services)) {\n registry.registerService(serviceName, service);\n }\n\n // Handle connection lifecycle\n io.on(\"connection\", (socket) => {\n const quickdrawSocket = socket as QuickdrawSocket;\n serverLogger.info(\"Socket connected\", {\n socketId: quickdrawSocket.id,\n userId: quickdrawSocket.userId,\n });\n\n quickdrawSocket.on(\"disconnect\", () => {\n serverLogger.info(\"Socket disconnected\", {\n socketId: quickdrawSocket.id,\n userId: quickdrawSocket.userId,\n });\n\n // Cleanup subscriptions across all services\n for (const service of registry.getServiceInstances()) {\n try {\n service.unsubscribeSocket(quickdrawSocket);\n } catch {\n // Ignore cleanup errors\n }\n }\n });\n });\n\n // Start listening\n httpServer.listen(options.port, \"0.0.0.0\", () => {\n serverLogger.info(`Server listening on port ${options.port}`);\n serverLogger.info(\n `Registered services: ${registry.getServices().join(\", \")}`\n );\n });\n\n return { io, httpServer, registry };\n}\n","import * as jose from \"jose\";\n\nexport interface JWTPayload {\n userId: string;\n email?: string;\n exp?: number;\n iat?: number;\n}\n\nconst DEFAULT_EXPIRATION = \"7d\";\n\n/**\n * Create a JWT token for authentication.\n *\n * @param payload - The payload to encode in the JWT\n * @param secret - The secret key for signing\n * @param expiresIn - Expiration time (default: 7 days)\n */\nexport async function createJWT(\n payload: Omit<JWTPayload, \"exp\" | \"iat\">,\n secret: string,\n expiresIn: string = DEFAULT_EXPIRATION\n): Promise<string> {\n const secretKey = new TextEncoder().encode(secret);\n\n const jwt = await new jose.SignJWT(payload as jose.JWTPayload)\n .setProtectedHeader({ alg: \"HS256\" })\n .setIssuedAt()\n .setExpirationTime(expiresIn)\n .sign(secretKey);\n\n return jwt;\n}\n\n/**\n * Verify and decode a JWT token.\n *\n * @param token - The JWT token to verify\n * @param secret - The secret key for verification\n * @returns The decoded payload, or null if invalid\n */\nexport async function verifyJWT(\n token: string,\n secret: string\n): Promise<JWTPayload | null> {\n try {\n const secretKey = new TextEncoder().encode(secret);\n const { payload } = await jose.jwtVerify(token, secretKey);\n\n return {\n userId: payload.userId as string,\n email: payload.email as string | undefined,\n exp: payload.exp,\n iat: payload.iat,\n };\n } catch {\n return null;\n }\n}\n","/**\n * Generic OAuth provider interface.\n */\nexport interface OAuthProvider<TUser = unknown> {\n name: string;\n authorizationUrl: string;\n tokenUrl: string;\n userInfoUrl: string;\n scopes: string[];\n\n /**\n * Parse user info response into a standardized format.\n */\n parseUserInfo: (data: unknown) => TUser;\n}\n\n/**\n * OAuth configuration for a provider.\n */\nexport interface OAuthConfig {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n}\n\n/**\n * OAuth token response.\n */\nexport interface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in?: number;\n refresh_token?: string;\n scope?: string;\n}\n\n/**\n * Create an OAuth authorization URL.\n *\n * @param provider - The OAuth provider\n * @param config - OAuth configuration\n * @param state - Optional state parameter for CSRF protection\n */\nexport function createOAuthURL(\n provider: OAuthProvider,\n config: OAuthConfig,\n state?: string\n): string {\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n response_type: \"code\",\n scope: provider.scopes.join(\" \"),\n });\n\n if (state) {\n params.set(\"state\", state);\n }\n\n return `${provider.authorizationUrl}?${params.toString()}`;\n}\n\n/**\n * Exchange an OAuth authorization code for tokens and user info.\n *\n * @param provider - The OAuth provider\n * @param config - OAuth configuration\n * @param code - The authorization code from the callback\n */\nexport async function exchangeOAuthCode<TUser>(\n provider: OAuthProvider<TUser>,\n config: OAuthConfig,\n code: string\n): Promise<{ tokens: OAuthTokenResponse; user: TUser }> {\n // Exchange code for tokens\n const tokenResponse = await fetch(provider.tokenUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: new URLSearchParams({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n code,\n grant_type: \"authorization_code\",\n redirect_uri: config.redirectUri,\n }),\n });\n\n if (!tokenResponse.ok) {\n const error = await tokenResponse.text();\n throw new Error(`Token exchange failed: ${error}`);\n }\n\n const tokens = (await tokenResponse.json()) as OAuthTokenResponse;\n\n // Fetch user info\n const userResponse = await fetch(provider.userInfoUrl, {\n headers: {\n Authorization: `Bearer ${tokens.access_token}`,\n Accept: \"application/json\",\n },\n });\n\n if (!userResponse.ok) {\n const error = await userResponse.text();\n throw new Error(`User info fetch failed: ${error}`);\n }\n\n const userData = await userResponse.json();\n const user = provider.parseUserInfo(userData);\n\n return { tokens, user };\n}\n","import type { OAuthProvider } from \"./oauth\";\n\n/**\n * Discord user information.\n */\nexport interface DiscordUser {\n id: string;\n username: string;\n discriminator: string;\n email: string | null;\n avatar: string | null;\n verified: boolean;\n}\n\n/**\n * Discord OAuth provider configuration.\n */\nexport const discordProvider: OAuthProvider<DiscordUser> = {\n name: \"discord\",\n authorizationUrl: \"https://discord.com/api/oauth2/authorize\",\n tokenUrl: \"https://discord.com/api/oauth2/token\",\n userInfoUrl: \"https://discord.com/api/users/@me\",\n scopes: [\"identify\", \"email\"],\n\n parseUserInfo: (data: unknown): DiscordUser => {\n const d = data as Record<string, unknown>;\n return {\n id: String(d.id),\n username: String(d.username),\n discriminator: String(d.discriminator ?? \"0\"),\n email: d.email ? String(d.email) : null,\n avatar: d.avatar ? String(d.avatar) : null,\n verified: Boolean(d.verified),\n };\n },\n};\n\n/**\n * Get Discord avatar URL.\n */\nexport function getDiscordAvatarUrl(user: DiscordUser): string {\n if (user.avatar) {\n return `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png`;\n }\n // Default avatar based on discriminator or user ID\n const index =\n user.discriminator !== \"0\"\n ? parseInt(user.discriminator, 10) % 5\n : (BigInt(user.id) >> BigInt(22)) % BigInt(6);\n return `https://cdn.discordapp.com/embed/avatars/${index}.png`;\n}\n","import type { OAuthProvider } from \"./oauth\";\n\n/**\n * Google user information.\n */\nexport interface GoogleUser {\n id: string;\n email: string;\n name: string;\n picture: string | null;\n verified_email: boolean;\n}\n\n/**\n * Google OAuth provider configuration.\n */\nexport const googleProvider: OAuthProvider<GoogleUser> = {\n name: \"google\",\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n userInfoUrl: \"https://www.googleapis.com/oauth2/v2/userinfo\",\n scopes: [\"openid\", \"email\", \"profile\"],\n\n parseUserInfo: (data: unknown): GoogleUser => {\n const d = data as Record<string, unknown>;\n return {\n id: String(d.id),\n email: String(d.email),\n name: String(d.name),\n picture: d.picture ? String(d.picture) : null,\n verified_email: Boolean(d.verified_email),\n };\n },\n};\n"]}
@@ -0,0 +1,70 @@
1
+ import { Socket } from 'socket.io-client';
2
+ import { B as BaseServiceInstance, Q as QuickdrawServerResult } from '../types-OhRxDBID.js';
3
+ import 'socket.io';
4
+ import 'http';
5
+ import '../shared/index.js';
6
+ import 'zod';
7
+
8
+ /**
9
+ * Options for creating a test server.
10
+ */
11
+ interface CreateTestServerOptions {
12
+ services: Record<string, BaseServiceInstance>;
13
+ seedDb?: () => Promise<void>;
14
+ }
15
+ /**
16
+ * Test server instance with helper methods.
17
+ */
18
+ interface TestServer {
19
+ port: number;
20
+ result: QuickdrawServerResult;
21
+ stop: () => Promise<void>;
22
+ connectAs: (userId: string) => Promise<TestClient>;
23
+ }
24
+ /**
25
+ * Test client instance with helper methods.
26
+ */
27
+ interface TestClient {
28
+ socket: Socket;
29
+ emit: <TPayload, TResponse>(event: string, payload: TPayload) => Promise<TResponse>;
30
+ close: () => void;
31
+ }
32
+ /**
33
+ * Get an available port for testing.
34
+ */
35
+ declare function getAvailablePort(): number;
36
+ /**
37
+ * Create a test server with dev authentication.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const server = await createTestServer({
42
+ * services: {
43
+ * chatService: new ChatService(testPrisma),
44
+ * },
45
+ * seedDb: async () => {
46
+ * await testPrisma.user.create({ ... });
47
+ * },
48
+ * });
49
+ *
50
+ * const client = await server.connectAs('user-id-123');
51
+ * const result = await client.emit('chatService:createChat', { title: 'Test' });
52
+ *
53
+ * await server.stop();
54
+ * ```
55
+ */
56
+ declare function createTestServer(options: CreateTestServerOptions): Promise<TestServer>;
57
+ /**
58
+ * Connect to a test server as a specific user.
59
+ */
60
+ declare function connectAsUser(port: number, userId: string): Promise<TestClient>;
61
+ /**
62
+ * Emit an event and wait for acknowledgment.
63
+ */
64
+ declare function emitWithAck<TPayload, TResponse>(socket: Socket, event: string, payload: TPayload, timeoutMs?: number): Promise<TResponse>;
65
+ /**
66
+ * Wait for a specific socket event.
67
+ */
68
+ declare function waitForEvent<T>(socket: Socket, event: string, timeoutMs?: number): Promise<T>;
69
+
70
+ export { type CreateTestServerOptions, type TestClient, type TestServer, connectAsUser, createTestServer, emitWithAck, getAvailablePort, waitForEvent };
@@ -0,0 +1,399 @@
1
+ import { io } from 'socket.io-client';
2
+ import express from 'express';
3
+ import { createServer } from 'http';
4
+ import { Server } from 'socket.io';
5
+
6
+ // src/server/testing.ts
7
+
8
+ // src/shared/types.ts
9
+ var consoleLogger = {
10
+ info: (message, meta) => console.log(`[INFO] ${message}`, meta ?? ""),
11
+ warn: (message, meta) => console.warn(`[WARN] ${message}`, meta ?? ""),
12
+ error: (message, meta) => console.error(`[ERROR] ${message}`, meta ?? ""),
13
+ debug: (message, meta) => console.debug(`[DEBUG] ${message}`, meta ?? ""),
14
+ child: () => consoleLogger
15
+ };
16
+
17
+ // src/server/ServiceRegistry.ts
18
+ var ServiceRegistry = class {
19
+ io;
20
+ services = /* @__PURE__ */ new Map();
21
+ logger;
22
+ constructor(io, options) {
23
+ this.io = io;
24
+ this.logger = options?.logger?.child({ service: "ServiceRegistry" }) ?? consoleLogger.child({ service: "ServiceRegistry" });
25
+ }
26
+ /**
27
+ * Register a service and auto-discover its public methods.
28
+ */
29
+ registerService(serviceName, service) {
30
+ this.services.set(serviceName, service);
31
+ this.logger.info(`Registered service: ${serviceName}`);
32
+ this.discoverServiceMethods(serviceName, service);
33
+ }
34
+ /**
35
+ * Discover and register all public methods from a service.
36
+ */
37
+ discoverServiceMethods(serviceName, service) {
38
+ const methods = service.getPublicMethods();
39
+ for (const method of methods) {
40
+ const eventName = `${serviceName}:${method.name}`;
41
+ this.logger.info(`Registering socket event: ${eventName}`);
42
+ this.io.on("connection", (socket) => {
43
+ this.registerMethodListener(
44
+ socket,
45
+ eventName,
46
+ method,
47
+ service
48
+ );
49
+ });
50
+ }
51
+ this.io.on("connection", (socket) => {
52
+ this.registerSubscriptionListener(
53
+ socket,
54
+ `${serviceName}:subscribe`,
55
+ service
56
+ );
57
+ this.registerUnsubscriptionListener(
58
+ socket,
59
+ `${serviceName}:unsubscribe`,
60
+ service
61
+ );
62
+ });
63
+ }
64
+ /**
65
+ * Register a method as a socket event listener.
66
+ */
67
+ registerMethodListener(socket, eventName, method, service) {
68
+ socket.on(
69
+ eventName,
70
+ async (payload, callback) => {
71
+ const startedAt = Date.now();
72
+ const [serviceName, methodName] = eventName.split(":");
73
+ const userIdShort = socket.userId?.slice(0, 8) ?? "anon";
74
+ try {
75
+ if (!socket.userId && method.access !== "Public") {
76
+ const errorResponse = {
77
+ success: false,
78
+ error: "Authentication required",
79
+ code: 401
80
+ };
81
+ callback?.(errorResponse);
82
+ return;
83
+ }
84
+ let validatedPayload = payload;
85
+ if (method.schema) {
86
+ const result2 = method.schema.safeParse(payload);
87
+ if (!result2.success) {
88
+ const errorResponse = {
89
+ success: false,
90
+ error: `Validation error: ${result2.error.message}`,
91
+ code: 400
92
+ };
93
+ callback?.(errorResponse);
94
+ return;
95
+ }
96
+ validatedPayload = result2.data;
97
+ }
98
+ let entryId;
99
+ if (method.resolveEntryId) {
100
+ entryId = method.resolveEntryId(validatedPayload) ?? void 0;
101
+ } else if (validatedPayload && typeof validatedPayload === "object" && "id" in validatedPayload) {
102
+ const idValue = validatedPayload.id;
103
+ if (typeof idValue === "string") {
104
+ entryId = idValue;
105
+ }
106
+ }
107
+ await service.ensureAccessForMethod(method.access, socket, entryId);
108
+ this.logger.info(
109
+ `User ${userIdShort} ${serviceName}.${methodName} -> start`,
110
+ {
111
+ category: "request_processing",
112
+ serviceName,
113
+ methodName,
114
+ userId: socket.userId,
115
+ socketId: socket.id
116
+ }
117
+ );
118
+ const result = await method.handler(validatedPayload, {
119
+ userId: socket.userId,
120
+ socketId: socket.id,
121
+ serviceAccess: socket.serviceAccess ?? {}
122
+ });
123
+ const durationMs = Date.now() - startedAt;
124
+ this.logger.info(
125
+ `User ${userIdShort} ${serviceName}.${methodName} -> success`,
126
+ {
127
+ category: "request_processing",
128
+ outcome: "success",
129
+ durationMs,
130
+ serviceName,
131
+ methodName,
132
+ userId: socket.userId
133
+ }
134
+ );
135
+ const successResponse = {
136
+ success: true,
137
+ data: result
138
+ };
139
+ callback?.(successResponse);
140
+ } catch (error) {
141
+ const durationMs = Date.now() - startedAt;
142
+ this.logger.error(
143
+ `User ${userIdShort} ${serviceName}.${methodName} -> fail`,
144
+ {
145
+ category: "request_processing",
146
+ outcome: "fail",
147
+ durationMs,
148
+ error: error instanceof Error ? error.message : "Unknown error"
149
+ }
150
+ );
151
+ const errorResponse = {
152
+ success: false,
153
+ error: error instanceof Error ? error.message : "Internal error",
154
+ code: 500
155
+ };
156
+ callback?.(errorResponse);
157
+ }
158
+ }
159
+ );
160
+ }
161
+ /**
162
+ * Register subscription listener for a service.
163
+ */
164
+ registerSubscriptionListener(socket, eventName, service) {
165
+ socket.on(
166
+ eventName,
167
+ async (payload, callback) => {
168
+ try {
169
+ if (!socket.userId) {
170
+ callback?.({
171
+ success: false,
172
+ error: "Authentication required",
173
+ code: 401
174
+ });
175
+ return;
176
+ }
177
+ const data = await service.subscribe(
178
+ payload.entryId,
179
+ socket,
180
+ payload.requiredLevel ?? "Read"
181
+ );
182
+ if (data === null) {
183
+ callback?.({
184
+ success: false,
185
+ error: "Access denied or entry not found",
186
+ code: 403
187
+ });
188
+ return;
189
+ }
190
+ callback?.({ success: true, data });
191
+ } catch (error) {
192
+ this.logger.error(`Error in subscription ${eventName}:`, {
193
+ error: error instanceof Error ? error.message : "Unknown error"
194
+ });
195
+ callback?.({
196
+ success: false,
197
+ error: error instanceof Error ? error.message : "Subscription failed"
198
+ });
199
+ }
200
+ }
201
+ );
202
+ }
203
+ /**
204
+ * Register unsubscription listener for a service.
205
+ */
206
+ registerUnsubscriptionListener(socket, eventName, service) {
207
+ socket.on(
208
+ eventName,
209
+ (payload, callback) => {
210
+ try {
211
+ service.unsubscribe(payload.entryId, socket);
212
+ callback?.({
213
+ success: true,
214
+ data: { unsubscribed: true, entryId: payload.entryId }
215
+ });
216
+ } catch (error) {
217
+ this.logger.error(`Error in unsubscription ${eventName}:`, {
218
+ error: error instanceof Error ? error.message : "Unknown error"
219
+ });
220
+ callback?.({
221
+ success: false,
222
+ error: error instanceof Error ? error.message : "Unsubscription failed"
223
+ });
224
+ }
225
+ }
226
+ );
227
+ }
228
+ /**
229
+ * Get list of registered service names.
230
+ */
231
+ getServices() {
232
+ return Array.from(this.services.keys());
233
+ }
234
+ /**
235
+ * Get all service instances for lifecycle management.
236
+ */
237
+ getServiceInstances() {
238
+ return Array.from(this.services.values());
239
+ }
240
+ };
241
+
242
+ // src/server/createServer.ts
243
+ function createQuickdrawServer(options) {
244
+ const logger = options.logger ?? consoleLogger;
245
+ const serverLogger = logger.child({ service: "QuickdrawServer" });
246
+ const app = express();
247
+ app.use(express.json());
248
+ app.get("/health", (_req, res) => {
249
+ res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
250
+ });
251
+ const httpServer = createServer(app);
252
+ const io = new Server(httpServer, {
253
+ cors: {
254
+ origin: options.cors?.origin ?? "*",
255
+ methods: options.cors?.methods ?? ["GET", "POST"],
256
+ credentials: options.cors?.credentials ?? true
257
+ }
258
+ });
259
+ const registry = new ServiceRegistry(io, { logger });
260
+ io.use(async (socket, next) => {
261
+ const quickdrawSocket = socket;
262
+ try {
263
+ if (options.auth?.authenticate) {
264
+ const auth = socket.handshake.auth;
265
+ const userId = await options.auth.authenticate(quickdrawSocket, auth);
266
+ quickdrawSocket.userId = userId;
267
+ quickdrawSocket.serviceAccess = {};
268
+ }
269
+ next();
270
+ } catch (error) {
271
+ serverLogger.error("Authentication failed", {
272
+ error: error instanceof Error ? error.message : "Unknown error",
273
+ socketId: socket.id
274
+ });
275
+ next(new Error("Authentication failed"));
276
+ }
277
+ });
278
+ for (const [serviceName, service] of Object.entries(options.services)) {
279
+ registry.registerService(serviceName, service);
280
+ }
281
+ io.on("connection", (socket) => {
282
+ const quickdrawSocket = socket;
283
+ serverLogger.info("Socket connected", {
284
+ socketId: quickdrawSocket.id,
285
+ userId: quickdrawSocket.userId
286
+ });
287
+ quickdrawSocket.on("disconnect", () => {
288
+ serverLogger.info("Socket disconnected", {
289
+ socketId: quickdrawSocket.id,
290
+ userId: quickdrawSocket.userId
291
+ });
292
+ for (const service of registry.getServiceInstances()) {
293
+ try {
294
+ service.unsubscribeSocket(quickdrawSocket);
295
+ } catch {
296
+ }
297
+ }
298
+ });
299
+ });
300
+ httpServer.listen(options.port, "0.0.0.0", () => {
301
+ serverLogger.info(`Server listening on port ${options.port}`);
302
+ serverLogger.info(
303
+ `Registered services: ${registry.getServices().join(", ")}`
304
+ );
305
+ });
306
+ return { io, httpServer, registry };
307
+ }
308
+
309
+ // src/server/testing.ts
310
+ var nextPort = 1e4;
311
+ function getAvailablePort() {
312
+ return nextPort++;
313
+ }
314
+ async function createTestServer(options) {
315
+ const port = getAvailablePort();
316
+ const result = createQuickdrawServer({
317
+ port,
318
+ services: options.services,
319
+ auth: {
320
+ // Dev mode: accept userId directly from auth
321
+ authenticate: async (_socket, auth) => {
322
+ return auth.userId;
323
+ }
324
+ }
325
+ });
326
+ await new Promise((resolve) => {
327
+ result.httpServer.once("listening", resolve);
328
+ });
329
+ if (options.seedDb) {
330
+ await options.seedDb();
331
+ }
332
+ return {
333
+ port,
334
+ result,
335
+ stop: () => new Promise((resolve) => {
336
+ result.io.close();
337
+ result.httpServer.close(() => resolve());
338
+ }),
339
+ connectAs: (userId) => connectAsUser(port, userId)
340
+ };
341
+ }
342
+ async function connectAsUser(port, userId) {
343
+ const socket = io(`http://localhost:${port}`, {
344
+ auth: { userId },
345
+ transports: ["websocket"],
346
+ autoConnect: true
347
+ });
348
+ await new Promise((resolve, reject) => {
349
+ const timeout = setTimeout(() => {
350
+ reject(new Error("Connection timeout"));
351
+ }, 5e3);
352
+ socket.on("connect", () => {
353
+ clearTimeout(timeout);
354
+ resolve();
355
+ });
356
+ socket.on("connect_error", (err) => {
357
+ clearTimeout(timeout);
358
+ reject(err);
359
+ });
360
+ });
361
+ return {
362
+ socket,
363
+ emit: (event, payload) => emitWithAck(socket, event, payload),
364
+ close: () => socket.close()
365
+ };
366
+ }
367
+ function emitWithAck(socket, event, payload, timeoutMs = 5e3) {
368
+ return new Promise((resolve, reject) => {
369
+ const timeout = setTimeout(() => {
370
+ reject(new Error(`Timeout waiting for ${event}`));
371
+ }, timeoutMs);
372
+ socket.emit(event, payload, (response) => {
373
+ clearTimeout(timeout);
374
+ if (response.success) {
375
+ resolve(response.data);
376
+ } else {
377
+ reject(new Error(response.error));
378
+ }
379
+ });
380
+ });
381
+ }
382
+ function waitForEvent(socket, event, timeoutMs = 5e3) {
383
+ return new Promise((resolve, reject) => {
384
+ const timeout = setTimeout(() => {
385
+ socket.off(event, handler);
386
+ reject(new Error(`Timeout waiting for event ${event}`));
387
+ }, timeoutMs);
388
+ const handler = (data) => {
389
+ clearTimeout(timeout);
390
+ socket.off(event, handler);
391
+ resolve(data);
392
+ };
393
+ socket.on(event, handler);
394
+ });
395
+ }
396
+
397
+ export { connectAsUser, createTestServer, emitWithAck, getAvailablePort, waitForEvent };
398
+ //# sourceMappingURL=testing.js.map
399
+ //# sourceMappingURL=testing.js.map