{"version":3,"sources":["../../../src/server/sockets.ts","/home/runner/work/equipped/equipped/dist/cjs/server/sockets.cjs"],"names":["EmitTypes","to"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/server/sockets.cjs","sourcesContent":["import { match as Match } from 'path-to-regexp'\nimport type { Server } from 'socket.io'\n\nimport type { Entity } from '../dbs/base/core'\nimport { Instance } from '../instance'\nimport type { AuthUser } from '../types'\nimport type { ServerConfig } from './pipes'\nimport { BaseRequestAuthMethod } from './requests-auth-methods'\nimport { StatusCodes, type StatusCodesEnum } from './types'\n\nenum EmitTypes {\n\tcreated = 'created',\n\tupdated = 'updated',\n\tdeleted = 'deleted',\n}\n\nconst EmitterEvent = '__listener_emitter'\ntype EmitData = { channel: string; type: EmitTypes; after: any; before: any }\ntype LeaveRoomParams = { channel: string }\ntype JoinRoomParams = { channel: string; token?: string; query: Record<string, any> }\ntype Callback = (params: { code: StatusCodesEnum; message: string; channel: string }) => void\nexport type OnJoinFn = (\n\tdata: { channel: string; user: AuthUser | null },\n\tparams: Record<string, any>,\n\tquery: Record<string, any>,\n) => Promise<string | null>\nexport type SocketCallbacks = {\n\tonConnect: (userId: string, socketId: string) => Promise<void>\n\tonDisconnect: (userId: string, socketId: string) => Promise<void>\n}\n\nconst defaultTo = '*'\n\nexport class SocketEmitter {\n\treadonly socketInstance: Server\n\t#connectionCallbacks: SocketCallbacks = { onConnect: async () => {}, onDisconnect: async () => {} }\n\t#routes = {} as Record<string, OnJoinFn>\n\t#publish: (data: EmitData) => Promise<void> = async () => {}\n\n\tconstructor(\n\t\tsocket: Server,\n\t\tprivate config: ServerConfig,\n\t) {\n\t\tthis.socketInstance = socket\n\t\tthis.#setupSocketConnection()\n\t\tInstance.on(\n\t\t\t'setup',\n\t\t\t() => {\n\t\t\t\tconst stream = config.eventBus?.createStream(EmitterEvent as never, { fanout: true })\n\t\t\t\tthis.#publish = stream\n\t\t\t\t\t? (stream.publish as unknown as (data: EmitData) => Promise<void>)\n\t\t\t\t\t: async (data: EmitData) => {\n\t\t\t\t\t\t\tsocket.to(data.channel).emit(data.channel, data)\n\t\t\t\t\t\t}\n\t\t\t\tstream?.subscribe(async (data: EmitData) => {\n\t\t\t\t\tsocket.to(data.channel).emit(data.channel, data)\n\t\t\t\t})\n\t\t\t},\n\t\t\t1,\n\t\t)\n\t}\n\n\tasync created<T extends Entity>(channels: string[], data: T, to: string | string[] | null) {\n\t\tawait this.#emit(channels, EmitTypes.created, { after: data.toJSON(), before: null }, to)\n\t}\n\n\tasync updated<T extends Entity>(channels: string[], { after, before }: { after: T; before: T }, to: string | string[] | null) {\n\t\tawait this.#emit(channels, EmitTypes.updated, { after: after.toJSON(), before: before.toJSON() }, to)\n\t}\n\n\tasync deleted<T extends Entity>(channels: string[], data: T, to: string | string[] | null) {\n\t\tawait this.#emit(channels, EmitTypes.deleted, { before: data.toJSON(), after: null }, to)\n\t}\n\n\tasync #emit(channels: string[], type: EmitTypes, { before, after }: { after: any; before: any }, to: string | string[] | null) {\n\t\tconst toArray = Array.isArray(to) ? to : [to ?? defaultTo]\n\t\tconst channelMap = channels.flatMap((c) => toArray.map((to) => `${to}:${c}`))\n\t\tawait Promise.all(channelMap.map(async (channel) => this.#publish({ channel, type, before, after })))\n\t}\n\n\tset connectionCallbacks(callbacks: SocketCallbacks) {\n\t\tthis.#connectionCallbacks = callbacks\n\t\tthis.#setupSocketConnection()\n\t}\n\n\tregister(channel: string, onJoin: OnJoinFn) {\n\t\tthis.#routes[channel] = onJoin\n\t\tthis.#routes[channel + '/:id'] = onJoin\n\t\treturn this\n\t}\n\n\t#getConfig(channel: string) {\n\t\tconst matcher = (key: string) => Match(key)(channel)\n\t\tconst matchedChannel = Object.keys(this.#routes).find(matcher) ?? null\n\t\tif (!matchedChannel) return null\n\t\tconst match = matcher(matchedChannel)\n\t\tif (!match) return null\n\t\treturn {\n\t\t\tconfig: this.#routes[matchedChannel],\n\t\t\tparams: match.params,\n\t\t}\n\t}\n\n\t#setupSocketConnection = () => {\n\t\tthis.socketInstance.removeAllListeners('connection')\n\t\tthis.socketInstance.on('connection', async (socket) => {\n\t\t\tconst socketId = socket.id\n\t\t\tconst user = await BaseRequestAuthMethod.process(this.config.socketsAuthMethods, socket.handshake.headers).catch(() => null)\n\t\t\tsocket.on('leave', async (data: LeaveRoomParams, callback: Callback) => {\n\t\t\t\tif (!data.channel)\n\t\t\t\t\treturn (\n\t\t\t\t\t\ttypeof callback === 'function' &&\n\t\t\t\t\t\tcallback({\n\t\t\t\t\t\t\tcode: StatusCodes.ValidationError,\n\t\t\t\t\t\t\tmessage: 'channel is required',\n\t\t\t\t\t\t\tchannel: '',\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\tsocket.leave(data.channel)\n\t\t\t\treturn (\n\t\t\t\t\ttypeof callback === 'function' &&\n\t\t\t\t\tcallback({\n\t\t\t\t\t\tcode: StatusCodes.Ok,\n\t\t\t\t\t\tmessage: '',\n\t\t\t\t\t\tchannel: data.channel,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t})\n\t\t\tsocket.on('join', async (data: JoinRoomParams, callback: Callback) => {\n\t\t\t\tif (!data.channel)\n\t\t\t\t\treturn (\n\t\t\t\t\t\ttypeof callback === 'function' &&\n\t\t\t\t\t\tcallback({\n\t\t\t\t\t\t\tcode: StatusCodes.ValidationError,\n\t\t\t\t\t\t\tmessage: 'channel is required',\n\t\t\t\t\t\t\tchannel: '',\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\tconst channel = data.channel\n\t\t\t\tconst route = this.#getConfig(channel) ?? null\n\t\t\t\tif (!route)\n\t\t\t\t\treturn (\n\t\t\t\t\t\ttypeof callback === 'function' &&\n\t\t\t\t\t\tcallback({\n\t\t\t\t\t\t\tcode: StatusCodes.BadRequest,\n\t\t\t\t\t\t\tmessage: 'unknown channel',\n\t\t\t\t\t\t\tchannel,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\tconst to = await route.config({ channel, user }, route.params, data.query ?? {})\n\t\t\t\tconst newChannel = `${to ?? defaultTo}:${channel}`\n\t\t\t\tsocket.join(newChannel)\n\t\t\t\treturn (\n\t\t\t\t\ttypeof callback === 'function' &&\n\t\t\t\t\tcallback({\n\t\t\t\t\t\tcode: StatusCodes.Ok,\n\t\t\t\t\t\tmessage: '',\n\t\t\t\t\t\tchannel: newChannel,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t})\n\t\t\tif (user) await this.#connectionCallbacks.onConnect(user.id, socketId)\n\t\t\tsocket.on('disconnect', async () => {\n\t\t\t\tif (user) await this.#connectionCallbacks.onDisconnect(user.id, socketId)\n\t\t\t})\n\t\t})\n\t}\n}\n",null]}