{"version":3,"sources":["../../../src/server/sockets.ts"],"names":["EmitTypes","EmitterEvent","defaultTo","config","socket","#setupSocketConnection","stream","data","#connectionCallbacks","#routes","#publish","channels","to","#emit","after","before","channelMap"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/server/sockets.min.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"]}