| 88 | >; |
| 89 | |
| 90 | constructor( |
| 91 | opts: ZodNamespaceOptions<TClientMessages, TServerMessages, TServerSideEvents, TSocketData> |
| 92 | ) { |
| 93 | this.#logger = opts.logger ?? new SimpleStructuredLogger(opts.name); |
| 94 | |
| 95 | this.#handler = new ZodSocketMessageHandler({ |
| 96 | schema: opts.clientMessages, |
| 97 | handlers: opts.handlers, |
| 98 | }); |
| 99 | |
| 100 | this.io = opts.io; |
| 101 | |
| 102 | this.namespace = this.io.of(opts.name); |
| 103 | |
| 104 | // FIXME: There's a bug here, this sender should not accept Socket schemas with callbacks |
| 105 | this.sender = new ZodMessageSender({ |
| 106 | schema: opts.serverMessages, |
| 107 | sender: async (message) => { |
| 108 | return new Promise((resolve, reject) => { |
| 109 | try { |
| 110 | // @ts-expect-error |
| 111 | this.namespace.emit(message.type, message.payload); |
| 112 | resolve(); |
| 113 | } catch (err) { |
| 114 | reject(err); |
| 115 | } |
| 116 | }); |
| 117 | }, |
| 118 | }); |
| 119 | |
| 120 | if (opts.preAuth) { |
| 121 | this.namespace.use(async (socket, next) => { |
| 122 | const logger = this.#logger.child({ socketId: socket.id, socketStage: "preAuth" }); |
| 123 | |
| 124 | if (typeof opts.preAuth === "function") { |
| 125 | await opts.preAuth(socket, next, logger); |
| 126 | } |
| 127 | }); |
| 128 | } |
| 129 | |
| 130 | if (opts.authToken) { |
| 131 | this.namespace.use((socket, next) => { |
| 132 | const logger = this.#logger.child({ socketId: socket.id, socketStage: "auth" }); |
| 133 | |
| 134 | const { auth } = socket.handshake; |
| 135 | |
| 136 | if (!("token" in auth)) { |
| 137 | logger.error("no token"); |
| 138 | return socket.disconnect(true); |
| 139 | } |
| 140 | |
| 141 | if (auth.token !== opts.authToken) { |
| 142 | logger.error("invalid token"); |
| 143 | return socket.disconnect(true); |
| 144 | } |
| 145 | |
| 146 | logger.info("success"); |
| 147 | |