@trigger.dev/core 0.0.0-prerelease-20240603154820 → 0.0.0-prerelease-20240723165848

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.
Files changed (187) hide show
  1. package/dist/api-Pl9fxB8v.d.mts +13879 -0
  2. package/dist/api-sNoooMbT.d.ts +13879 -0
  3. package/dist/{catalog-dRKTgwQ7.d.ts → catalog-H7yFiZ60.d.mts} +52 -52
  4. package/dist/{catalog-XTlJQaMn.d.mts → catalog-h79CG5Wy.d.ts} +52 -52
  5. package/dist/{manager-JkbddlcO.d.mts → common-CLW82lkt.d.mts} +280 -16
  6. package/dist/{manager-JkbddlcO.d.ts → common-CLW82lkt.d.ts} +280 -16
  7. package/dist/{eventFilterMatches-2kHImluE.d.mts → eventFilter-66NaBAMi.d.mts} +1 -3
  8. package/dist/{eventFilterMatches-2kHImluE.d.ts → eventFilter-66NaBAMi.d.ts} +1 -3
  9. package/dist/eventFilterMatches.d.mts +6 -0
  10. package/dist/eventFilterMatches.d.ts +6 -0
  11. package/dist/eventFilterMatches.js +165 -0
  12. package/dist/eventFilterMatches.js.map +1 -0
  13. package/dist/eventFilterMatches.mjs +163 -0
  14. package/dist/eventFilterMatches.mjs.map +1 -0
  15. package/dist/index.d.mts +14 -16716
  16. package/dist/index.d.ts +14 -16716
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +1 -1
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/json-DBPEJQRe.d.mts +16 -0
  22. package/dist/json-DBPEJQRe.d.ts +16 -0
  23. package/dist/manager-KvCabW1a.d.mts +18 -0
  24. package/dist/manager-OBA35PzR.d.ts +18 -0
  25. package/dist/{messages-6_-q72KG.d.mts → messages-JvHJ83wv.d.mts} +2978 -291
  26. package/dist/{messages-6_-q72KG.d.ts → messages-JvHJ83wv.d.ts} +2978 -291
  27. package/dist/replacements.d.mts +22 -0
  28. package/dist/replacements.d.ts +22 -0
  29. package/dist/replacements.js +33 -0
  30. package/dist/replacements.js.map +1 -0
  31. package/dist/replacements.mjs +28 -0
  32. package/dist/replacements.mjs.map +1 -0
  33. package/dist/requestFilter-HNZQEpQb.d.ts +180 -0
  34. package/dist/requestFilter-b5W2_1oP.d.mts +180 -0
  35. package/dist/requestFilterMatches.d.mts +13 -0
  36. package/dist/requestFilterMatches.d.ts +13 -0
  37. package/dist/requestFilterMatches.js +238 -0
  38. package/dist/requestFilterMatches.js.map +1 -0
  39. package/dist/requestFilterMatches.mjs +235 -0
  40. package/dist/requestFilterMatches.mjs.map +1 -0
  41. package/dist/retry.d.mts +10 -0
  42. package/dist/retry.d.ts +10 -0
  43. package/dist/retry.js +100 -0
  44. package/dist/retry.js.map +1 -0
  45. package/dist/retry.mjs +97 -0
  46. package/dist/retry.mjs.map +1 -0
  47. package/dist/schemas/index.d.mts +2611 -0
  48. package/dist/schemas/index.d.ts +2611 -0
  49. package/dist/schemas/index.js +1630 -0
  50. package/dist/schemas/index.js.map +1 -0
  51. package/dist/schemas/index.mjs +1463 -0
  52. package/dist/schemas/index.mjs.map +1 -0
  53. package/dist/{schemas-r4ZP9S-F.d.mts → schemas-C9ssfehv.d.mts} +270 -33
  54. package/dist/{schemas-r4ZP9S-F.d.ts → schemas-C9ssfehv.d.ts} +270 -33
  55. package/dist/taskLogger-CzADe4je.d.ts +33 -0
  56. package/dist/taskLogger-r_AFTX45.d.mts +33 -0
  57. package/dist/tracer-N0p2Fuuv.d.mts +23 -0
  58. package/dist/tracer-N0p2Fuuv.d.ts +23 -0
  59. package/dist/types.d.mts +11 -0
  60. package/dist/types.d.ts +11 -0
  61. package/dist/types.js +4 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/types.mjs +3 -0
  64. package/dist/types.mjs.map +1 -0
  65. package/dist/utils.d.mts +7 -0
  66. package/dist/utils.d.ts +7 -0
  67. package/dist/utils.js +33 -0
  68. package/dist/utils.js.map +1 -0
  69. package/dist/utils.mjs +30 -0
  70. package/dist/utils.mjs.map +1 -0
  71. package/dist/v3/dev/index.d.mts +2 -1
  72. package/dist/v3/dev/index.d.ts +2 -1
  73. package/dist/v3/dev/index.js.map +1 -1
  74. package/dist/v3/dev/index.mjs.map +1 -1
  75. package/dist/v3/errors.d.mts +39 -0
  76. package/dist/v3/errors.d.ts +39 -0
  77. package/dist/v3/errors.js +204 -0
  78. package/dist/v3/errors.js.map +1 -0
  79. package/dist/v3/errors.mjs +195 -0
  80. package/dist/v3/errors.mjs.map +1 -0
  81. package/dist/v3/index.d.mts +172 -4737
  82. package/dist/v3/index.d.ts +172 -4737
  83. package/dist/v3/index.js +871 -620
  84. package/dist/v3/index.js.map +1 -1
  85. package/dist/v3/index.mjs +856 -620
  86. package/dist/v3/index.mjs.map +1 -1
  87. package/dist/v3/logger-api.d.mts +24 -0
  88. package/dist/v3/logger-api.d.ts +24 -0
  89. package/dist/v3/logger-api.js +118 -0
  90. package/dist/v3/logger-api.js.map +1 -0
  91. package/dist/v3/logger-api.mjs +116 -0
  92. package/dist/v3/logger-api.mjs.map +1 -0
  93. package/dist/v3/otel/index.js +36 -12
  94. package/dist/v3/otel/index.js.map +1 -1
  95. package/dist/v3/otel/index.mjs +36 -12
  96. package/dist/v3/otel/index.mjs.map +1 -1
  97. package/dist/v3/prod/index.d.mts +4 -3
  98. package/dist/v3/prod/index.d.ts +4 -3
  99. package/dist/v3/prod/index.js +7 -131
  100. package/dist/v3/prod/index.js.map +1 -1
  101. package/dist/v3/prod/index.mjs +7 -131
  102. package/dist/v3/prod/index.mjs.map +1 -1
  103. package/dist/v3/schemas/index.d.mts +4807 -0
  104. package/dist/v3/schemas/index.d.ts +4807 -0
  105. package/dist/v3/schemas/index.js +2065 -0
  106. package/dist/v3/schemas/index.js.map +1 -0
  107. package/dist/v3/schemas/index.mjs +1924 -0
  108. package/dist/v3/schemas/index.mjs.map +1 -0
  109. package/dist/v3/semanticInternalAttributes.d.mts +56 -0
  110. package/dist/v3/semanticInternalAttributes.d.ts +56 -0
  111. package/dist/v3/semanticInternalAttributes.js +61 -0
  112. package/dist/v3/semanticInternalAttributes.js.map +1 -0
  113. package/dist/v3/semanticInternalAttributes.mjs +59 -0
  114. package/dist/v3/semanticInternalAttributes.mjs.map +1 -0
  115. package/dist/v3/utils/durations.d.mts +15 -0
  116. package/dist/v3/utils/durations.d.ts +15 -0
  117. package/dist/v3/utils/durations.js +93 -0
  118. package/dist/v3/utils/durations.js.map +1 -0
  119. package/dist/v3/utils/durations.mjs +82 -0
  120. package/dist/v3/utils/durations.mjs.map +1 -0
  121. package/dist/v3/utils/flattenAttributes.d.mts +8 -0
  122. package/dist/v3/utils/flattenAttributes.d.ts +8 -0
  123. package/dist/v3/utils/flattenAttributes.js +131 -0
  124. package/dist/v3/utils/flattenAttributes.js.map +1 -0
  125. package/dist/v3/utils/flattenAttributes.mjs +126 -0
  126. package/dist/v3/utils/flattenAttributes.mjs.map +1 -0
  127. package/dist/v3/utils/ioSerialization.d.mts +21 -0
  128. package/dist/v3/utils/ioSerialization.d.ts +21 -0
  129. package/dist/v3/utils/ioSerialization.js +2403 -0
  130. package/dist/v3/utils/ioSerialization.js.map +1 -0
  131. package/dist/v3/utils/ioSerialization.mjs +2394 -0
  132. package/dist/v3/utils/ioSerialization.mjs.map +1 -0
  133. package/dist/v3/utils/omit.d.mts +3 -0
  134. package/dist/v3/utils/omit.d.ts +3 -0
  135. package/dist/v3/utils/omit.js +20 -0
  136. package/dist/v3/utils/omit.js.map +1 -0
  137. package/dist/v3/utils/omit.mjs +18 -0
  138. package/dist/v3/utils/omit.mjs.map +1 -0
  139. package/dist/v3/utils/retries.d.mts +46 -0
  140. package/dist/v3/utils/retries.d.ts +46 -0
  141. package/dist/v3/utils/retries.js +118 -0
  142. package/dist/v3/utils/retries.js.map +1 -0
  143. package/dist/v3/utils/retries.mjs +113 -0
  144. package/dist/v3/utils/retries.mjs.map +1 -0
  145. package/dist/v3/utils/timers.d.mts +6 -0
  146. package/dist/v3/utils/timers.d.ts +6 -0
  147. package/dist/v3/utils/timers.js +31 -0
  148. package/dist/v3/utils/timers.js.map +1 -0
  149. package/dist/v3/utils/timers.mjs +28 -0
  150. package/dist/v3/utils/timers.mjs.map +1 -0
  151. package/dist/v3/workers/index.d.mts +56 -8
  152. package/dist/v3/workers/index.d.ts +56 -8
  153. package/dist/v3/workers/index.js +755 -279
  154. package/dist/v3/workers/index.js.map +1 -1
  155. package/dist/v3/workers/index.mjs +753 -280
  156. package/dist/v3/workers/index.mjs.map +1 -1
  157. package/dist/v3/zodIpc.js.map +1 -1
  158. package/dist/v3/zodIpc.mjs.map +1 -1
  159. package/dist/v3/zodMessageHandler.d.mts +16 -3
  160. package/dist/v3/zodMessageHandler.d.ts +16 -3
  161. package/dist/v3/zodMessageHandler.js +77 -23
  162. package/dist/v3/zodMessageHandler.js.map +1 -1
  163. package/dist/v3/zodMessageHandler.mjs +77 -23
  164. package/dist/v3/zodMessageHandler.mjs.map +1 -1
  165. package/dist/v3/zodNamespace.js +59 -28
  166. package/dist/v3/zodNamespace.js.map +1 -1
  167. package/dist/v3/zodNamespace.mjs +60 -29
  168. package/dist/v3/zodNamespace.mjs.map +1 -1
  169. package/dist/v3/zodSocket.d.mts +8 -3
  170. package/dist/v3/zodSocket.d.ts +8 -3
  171. package/dist/v3/zodSocket.js +56 -25
  172. package/dist/v3/zodSocket.js.map +1 -1
  173. package/dist/v3/zodSocket.mjs +57 -26
  174. package/dist/v3/zodSocket.mjs.map +1 -1
  175. package/dist/v3/zodfetch.d.mts +15 -58
  176. package/dist/v3/zodfetch.d.ts +15 -58
  177. package/dist/v3/zodfetch.js +246 -156
  178. package/dist/v3/zodfetch.js.map +1 -1
  179. package/dist/v3/zodfetch.mjs +244 -149
  180. package/dist/v3/zodfetch.mjs.map +1 -1
  181. package/dist/versions.d.mts +11 -0
  182. package/dist/versions.d.ts +11 -0
  183. package/dist/versions.js +31 -0
  184. package/dist/versions.js.map +1 -0
  185. package/dist/versions.mjs +27 -0
  186. package/dist/versions.mjs.map +1 -0
  187. package/package.json +154 -10
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/v3/zodIpc.ts","../../src/v3/zodMessageHandler.ts"],"names":["randomUUID","z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","messageSchema","ZodIpcMessageHandler","options","schema","handlers","sender","handleMessage","parsedMessage","parseMessage","handler","ack","safeParse","success","JSON","stringify","data","parsedPayload","Packet","discriminatedUnion","sessionId","optional","any","id","number","ZodIpcConnection","opts","Map","listenSchema","send","bind","sendWithAck","connect","emitSchema","timeoutInMs","currentId","Promise","resolve","reject","defaultTimeoutInMs","timeout","setTimeout","reason","set","clearTimeout","process","on","packet","parsedPacket","get","result"],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport {\n GetSocketCallbackSchema,\n GetSocketMessageSchema,\n GetSocketMessagesWithCallback,\n GetSocketMessagesWithoutCallback,\n MessagesFromSocketCatalog,\n SocketMessageHasCallback,\n ZodSocketMessageCatalogSchema,\n} from \"./zodSocket\";\nimport { z } from \"zod\";\nimport { ZodSchemaParsedError } from \"./zodMessageHandler\";\n\ninterface ZodIpcMessageSender<TEmitCatalog extends ZodSocketMessageCatalogSchema> {\n send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void>;\n\n sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>>;\n}\n\ntype ZodIpcMessageHandlers<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = Partial<{\n [K in keyof TListenCatalog]: (\n payload: z.infer<GetSocketMessageSchema<TListenCatalog, K>>,\n sender: ZodIpcMessageSender<TEmitCatalog>\n ) => Promise<\n SocketMessageHasCallback<TListenCatalog, K> extends true\n ? z.input<GetSocketCallbackSchema<TListenCatalog, K>>\n : void\n >;\n}>;\n\nconst messageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\ntype ZodIpcMessageHandlerOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = {\n schema: TListenCatalog;\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n sender: ZodIpcMessageSender<TEmitCatalog>;\n};\n\nclass ZodIpcMessageHandler<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #schema: TListenCatalog;\n #handlers: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog> | undefined;\n #sender: ZodIpcMessageSender<TEmitCatalog>;\n\n constructor(options: ZodIpcMessageHandlerOptions<TListenCatalog, TEmitCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.handlers;\n this.#sender = options.sender;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n // console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload, this.#sender);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessagesFromSocketCatalog<TListenCatalog> {\n const parsedMessage = messageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n}\n\nconst Packet = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"CONNECT\"),\n sessionId: z.string().optional(),\n }),\n z.object({\n type: z.literal(\"ACK\"),\n message: z.any(),\n id: z.number(),\n }),\n z.object({\n type: z.literal(\"EVENT\"),\n message: z.any(),\n id: z.number().optional(),\n }),\n]);\n\ntype Packet = z.infer<typeof Packet>;\n\ninterface ZodIpcConnectionOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n listenSchema: TListenCatalog;\n emitSchema: TEmitCatalog;\n process: {\n send?: (message: any) => any;\n on?: (event: \"message\", listener: (message: any) => void) => void;\n };\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n}\n\nexport class ZodIpcConnection<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #sessionId?: string;\n #messageCounter: number = 0;\n\n #handler: ZodIpcMessageHandler<TListenCatalog, TEmitCatalog>;\n\n #acks: Map<\n number,\n {\n resolve: (value: unknown) => void;\n reject: (reason?: any) => void;\n timeout: NodeJS.Timeout;\n }\n > = new Map();\n\n constructor(private opts: ZodIpcConnectionOptions<TListenCatalog, TEmitCatalog>) {\n this.#handler = new ZodIpcMessageHandler({\n schema: opts.listenSchema,\n handlers: opts.handlers,\n sender: {\n send: this.send.bind(this),\n sendWithAck: this.sendWithAck.bind(this),\n },\n });\n\n this.#registerHandlers();\n // this.connect();\n }\n\n async #registerHandlers() {\n if (!this.opts.process.on) {\n return;\n }\n\n this.opts.process.on(\"message\", async (message) => {\n this.#handlePacket(message);\n });\n }\n\n async connect() {\n this.#sendPacket({ type: \"CONNECT\" });\n }\n\n async #handlePacket(packet: Packet): Promise<void> {\n const parsedPacket = Packet.safeParse(packet);\n\n if (!parsedPacket.success) {\n // console.error(\"dropping invalid packet\", packet);\n return;\n }\n\n // console.log(\"<-\", packet);\n\n switch (parsedPacket.data.type) {\n case \"ACK\": {\n // Check our list of ACKs and resolve with the message\n const ack = this.#acks.get(parsedPacket.data.id);\n\n if (!ack) {\n return;\n }\n\n clearTimeout(ack.timeout);\n ack.resolve(parsedPacket.data.message);\n\n break;\n }\n case \"CONNECT\": {\n if (!parsedPacket.data.sessionId) {\n // This is a client trying to connect, so we generate and send back a session ID\n const id = randomUUID();\n\n await this.#sendPacket({ type: \"CONNECT\", sessionId: id });\n\n return;\n }\n\n // This is a server replying to our connect message\n if (this.#sessionId) {\n // We're already connected\n return;\n }\n\n this.#sessionId = parsedPacket.data.sessionId;\n\n break;\n }\n case \"EVENT\": {\n const result = await this.#handler.handleMessage(parsedPacket.data.message);\n\n if (typeof parsedPacket.data.id === \"undefined\") {\n return;\n }\n\n // There's an ID so we should ACK\n await this.#sendPacket({\n type: \"ACK\",\n id: parsedPacket.data.id,\n message: result,\n });\n\n break;\n }\n default: {\n break;\n }\n }\n }\n\n async #sendPacket(packet: Packet) {\n // console.log(\"->\", packet);\n await this.opts.process.send?.(packet);\n }\n\n async send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void> {\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n });\n }\n\n public async sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>,\n timeoutInMs?: number\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>> {\n const currentId = this.#messageCounter++;\n\n return new Promise(async (resolve, reject) => {\n const defaultTimeoutInMs = 2000;\n\n // Timeout if the ACK takes too long to get back to us\n const timeout = setTimeout(() => {\n reject(\n JSON.stringify({\n reason: \"sendWithAck() timeout\",\n timeoutInMs: timeoutInMs ?? defaultTimeoutInMs,\n type,\n payload,\n })\n );\n }, timeoutInMs ?? defaultTimeoutInMs);\n\n this.#acks.set(currentId, { resolve, reject, timeout });\n\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n clearTimeout(timeout);\n return reject(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n clearTimeout(timeout);\n return reject(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n id: currentId,\n });\n });\n }\n}\n","import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessageFromCatalog<TMessageCatalog> {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n callback(ack);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sender({ type, payload, version: \"v1\" });\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}
1
+ {"version":3,"sources":["../../src/v3/zodIpc.ts","../../src/v3/zodMessageHandler.ts"],"names":["randomUUID","z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","messageSchema","ZodIpcMessageHandler","options","schema","handlers","sender","handleMessage","parsedMessage","parseMessage","handler","ack","safeParse","success","JSON","stringify","data","parsedPayload","Packet","discriminatedUnion","sessionId","optional","any","id","number","ZodIpcConnection","opts","Map","listenSchema","send","bind","sendWithAck","connect","emitSchema","timeoutInMs","currentId","Promise","resolve","reject","defaultTimeoutInMs","timeout","setTimeout","reason","set","clearTimeout","process","on","packet","parsedPacket","get","result"],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport {\n GetSocketCallbackSchema,\n GetSocketMessageSchema,\n GetSocketMessagesWithCallback,\n GetSocketMessagesWithoutCallback,\n MessagesFromSocketCatalog,\n SocketMessageHasCallback,\n ZodSocketMessageCatalogSchema,\n} from \"./zodSocket\";\nimport { z } from \"zod\";\nimport { ZodSchemaParsedError } from \"./zodMessageHandler\";\nimport { inspect } from \"node:util\";\n\ninterface ZodIpcMessageSender<TEmitCatalog extends ZodSocketMessageCatalogSchema> {\n send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void>;\n\n sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>>;\n}\n\ntype ZodIpcMessageHandlers<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = Partial<{\n [K in keyof TListenCatalog]: (\n payload: z.infer<GetSocketMessageSchema<TListenCatalog, K>>,\n sender: ZodIpcMessageSender<TEmitCatalog>\n ) => Promise<\n SocketMessageHasCallback<TListenCatalog, K> extends true\n ? z.input<GetSocketCallbackSchema<TListenCatalog, K>>\n : void\n >;\n}>;\n\nconst messageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\ntype ZodIpcMessageHandlerOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = {\n schema: TListenCatalog;\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n sender: ZodIpcMessageSender<TEmitCatalog>;\n};\n\nclass ZodIpcMessageHandler<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #schema: TListenCatalog;\n #handlers: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog> | undefined;\n #sender: ZodIpcMessageSender<TEmitCatalog>;\n\n constructor(options: ZodIpcMessageHandlerOptions<TListenCatalog, TEmitCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.handlers;\n this.#sender = options.sender;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n // console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload, this.#sender);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessagesFromSocketCatalog<TListenCatalog> {\n const parsedMessage = messageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n}\n\nconst Packet = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"CONNECT\"),\n sessionId: z.string().optional(),\n }),\n z.object({\n type: z.literal(\"ACK\"),\n message: z.any(),\n id: z.number(),\n }),\n z.object({\n type: z.literal(\"EVENT\"),\n message: z.any(),\n id: z.number().optional(),\n }),\n]);\n\ntype Packet = z.infer<typeof Packet>;\n\ninterface ZodIpcConnectionOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n listenSchema: TListenCatalog;\n emitSchema: TEmitCatalog;\n process: {\n send?: (message: any) => any;\n on?: (event: \"message\", listener: (message: any) => void) => void;\n };\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n}\n\nexport class ZodIpcConnection<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #sessionId?: string;\n #messageCounter: number = 0;\n\n #handler: ZodIpcMessageHandler<TListenCatalog, TEmitCatalog>;\n\n #acks: Map<\n number,\n {\n resolve: (value: unknown) => void;\n reject: (reason?: any) => void;\n timeout: NodeJS.Timeout;\n }\n > = new Map();\n\n constructor(private opts: ZodIpcConnectionOptions<TListenCatalog, TEmitCatalog>) {\n this.#handler = new ZodIpcMessageHandler({\n schema: opts.listenSchema,\n handlers: opts.handlers,\n sender: {\n send: this.send.bind(this),\n sendWithAck: this.sendWithAck.bind(this),\n },\n });\n\n this.#registerHandlers();\n // this.connect();\n }\n\n async #registerHandlers() {\n if (!this.opts.process.on) {\n return;\n }\n\n this.opts.process.on(\"message\", async (message) => {\n this.#handlePacket(message);\n });\n }\n\n async connect() {\n this.#sendPacket({ type: \"CONNECT\" });\n }\n\n async #handlePacket(packet: Packet): Promise<void> {\n const parsedPacket = Packet.safeParse(packet);\n\n if (!parsedPacket.success) {\n return;\n }\n\n switch (parsedPacket.data.type) {\n case \"ACK\": {\n // Check our list of ACKs and resolve with the message\n const ack = this.#acks.get(parsedPacket.data.id);\n\n if (!ack) {\n return;\n }\n\n clearTimeout(ack.timeout);\n ack.resolve(parsedPacket.data.message);\n\n break;\n }\n case \"CONNECT\": {\n if (!parsedPacket.data.sessionId) {\n // This is a client trying to connect, so we generate and send back a session ID\n const id = randomUUID();\n\n await this.#sendPacket({ type: \"CONNECT\", sessionId: id });\n\n return;\n }\n\n // This is a server replying to our connect message\n if (this.#sessionId) {\n // We're already connected\n return;\n }\n\n this.#sessionId = parsedPacket.data.sessionId;\n\n break;\n }\n case \"EVENT\": {\n const result = await this.#handler.handleMessage(parsedPacket.data.message);\n\n if (typeof parsedPacket.data.id === \"undefined\") {\n return;\n }\n\n // There's an ID so we should ACK\n await this.#sendPacket({\n type: \"ACK\",\n id: parsedPacket.data.id,\n message: result,\n });\n\n break;\n }\n default: {\n break;\n }\n }\n }\n\n async #sendPacket(packet: Packet) {\n await this.opts.process.send?.(packet);\n }\n\n async send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void> {\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n });\n }\n\n public async sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>,\n timeoutInMs?: number\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>> {\n const currentId = this.#messageCounter++;\n\n return new Promise(async (resolve, reject) => {\n const defaultTimeoutInMs = 2000;\n\n // Timeout if the ACK takes too long to get back to us\n const timeout = setTimeout(() => {\n reject(\n JSON.stringify({\n reason: \"sendWithAck() timeout\",\n timeoutInMs: timeoutInMs ?? defaultTimeoutInMs,\n type,\n payload,\n })\n );\n }, timeoutInMs ?? defaultTimeoutInMs);\n\n this.#acks.set(currentId, { resolve, reject, timeout });\n\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n clearTimeout(timeout);\n return reject(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n clearTimeout(timeout);\n return reject(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n id: currentId,\n });\n });\n }\n}\n","import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n logger?: StructuredLogger;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n #logger: StructuredLogger | Console;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n this.#logger = options.logger ?? console;\n }\n\n public async handleMessage(message: unknown): Promise<\n | {\n success: true;\n data: unknown;\n }\n | {\n success: false;\n error: string;\n }\n > {\n const parsedMessage = this.parseMessage(message);\n\n if (!parsedMessage.success) {\n this.#logger.error(parsedMessage.error, { message });\n\n return {\n success: false,\n error: parsedMessage.error,\n };\n }\n\n if (!this.#handlers) {\n this.#logger.error(\"No handlers provided\", { message });\n\n return {\n success: false,\n error: \"No handlers provided\",\n };\n }\n\n const handler = this.#handlers[parsedMessage.data.type];\n\n if (!handler) {\n const error = `No handler for message type: ${String(parsedMessage.data.type)}`;\n\n this.#logger.error(error, { message });\n\n return {\n success: false,\n error,\n };\n }\n\n const ack = await handler(parsedMessage.data.payload);\n\n return {\n success: true,\n data: ack,\n };\n }\n\n public parseMessage(message: unknown):\n | {\n success: true;\n data: MessageFromCatalog<TMessageCatalog>;\n }\n | {\n success: false;\n error: string;\n } {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n return {\n success: false,\n error: `Failed to parse message: ${JSON.stringify(parsedMessage.error)}`,\n };\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n return {\n success: false,\n error: `Unknown message type: ${parsedMessage.data.type}`,\n };\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n return {\n success: false,\n error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`,\n };\n }\n\n return {\n success: true,\n data: {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n },\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack: Awaited<ReturnType<ZodMessageHandler<TMessageCatalog>[\"handleMessage\"]>>;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n if (!ack.success) {\n // We don't know the callback type, so we can't do anything else - not all callbacks may accept a success prop\n log.error(\"Failed to handle message, skipping callback\", { message, error: ack.error });\n return;\n }\n\n callback(ack.data);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n try {\n await this.#sender({ type, payload, version: \"v1\" });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to send message\", error);\n }\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n try {\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to forward message\", error);\n }\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/v3/zodIpc.ts","../../src/v3/zodMessageHandler.ts"],"names":["randomUUID","z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","messageSchema","ZodIpcMessageHandler","options","schema","handlers","sender","handleMessage","parsedMessage","parseMessage","handler","ack","safeParse","success","JSON","stringify","data","parsedPayload","Packet","discriminatedUnion","sessionId","optional","any","id","number","ZodIpcConnection","opts","Map","listenSchema","send","bind","sendWithAck","connect","emitSchema","timeoutInMs","currentId","Promise","resolve","reject","defaultTimeoutInMs","timeout","setTimeout","reason","set","clearTimeout","process","on","packet","parsedPacket","get","result"],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport {\n GetSocketCallbackSchema,\n GetSocketMessageSchema,\n GetSocketMessagesWithCallback,\n GetSocketMessagesWithoutCallback,\n MessagesFromSocketCatalog,\n SocketMessageHasCallback,\n ZodSocketMessageCatalogSchema,\n} from \"./zodSocket\";\nimport { z } from \"zod\";\nimport { ZodSchemaParsedError } from \"./zodMessageHandler\";\n\ninterface ZodIpcMessageSender<TEmitCatalog extends ZodSocketMessageCatalogSchema> {\n send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void>;\n\n sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>>;\n}\n\ntype ZodIpcMessageHandlers<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = Partial<{\n [K in keyof TListenCatalog]: (\n payload: z.infer<GetSocketMessageSchema<TListenCatalog, K>>,\n sender: ZodIpcMessageSender<TEmitCatalog>\n ) => Promise<\n SocketMessageHasCallback<TListenCatalog, K> extends true\n ? z.input<GetSocketCallbackSchema<TListenCatalog, K>>\n : void\n >;\n}>;\n\nconst messageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\ntype ZodIpcMessageHandlerOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = {\n schema: TListenCatalog;\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n sender: ZodIpcMessageSender<TEmitCatalog>;\n};\n\nclass ZodIpcMessageHandler<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #schema: TListenCatalog;\n #handlers: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog> | undefined;\n #sender: ZodIpcMessageSender<TEmitCatalog>;\n\n constructor(options: ZodIpcMessageHandlerOptions<TListenCatalog, TEmitCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.handlers;\n this.#sender = options.sender;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n // console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload, this.#sender);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessagesFromSocketCatalog<TListenCatalog> {\n const parsedMessage = messageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n}\n\nconst Packet = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"CONNECT\"),\n sessionId: z.string().optional(),\n }),\n z.object({\n type: z.literal(\"ACK\"),\n message: z.any(),\n id: z.number(),\n }),\n z.object({\n type: z.literal(\"EVENT\"),\n message: z.any(),\n id: z.number().optional(),\n }),\n]);\n\ntype Packet = z.infer<typeof Packet>;\n\ninterface ZodIpcConnectionOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n listenSchema: TListenCatalog;\n emitSchema: TEmitCatalog;\n process: {\n send?: (message: any) => any;\n on?: (event: \"message\", listener: (message: any) => void) => void;\n };\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n}\n\nexport class ZodIpcConnection<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #sessionId?: string;\n #messageCounter: number = 0;\n\n #handler: ZodIpcMessageHandler<TListenCatalog, TEmitCatalog>;\n\n #acks: Map<\n number,\n {\n resolve: (value: unknown) => void;\n reject: (reason?: any) => void;\n timeout: NodeJS.Timeout;\n }\n > = new Map();\n\n constructor(private opts: ZodIpcConnectionOptions<TListenCatalog, TEmitCatalog>) {\n this.#handler = new ZodIpcMessageHandler({\n schema: opts.listenSchema,\n handlers: opts.handlers,\n sender: {\n send: this.send.bind(this),\n sendWithAck: this.sendWithAck.bind(this),\n },\n });\n\n this.#registerHandlers();\n // this.connect();\n }\n\n async #registerHandlers() {\n if (!this.opts.process.on) {\n return;\n }\n\n this.opts.process.on(\"message\", async (message) => {\n this.#handlePacket(message);\n });\n }\n\n async connect() {\n this.#sendPacket({ type: \"CONNECT\" });\n }\n\n async #handlePacket(packet: Packet): Promise<void> {\n const parsedPacket = Packet.safeParse(packet);\n\n if (!parsedPacket.success) {\n // console.error(\"dropping invalid packet\", packet);\n return;\n }\n\n // console.log(\"<-\", packet);\n\n switch (parsedPacket.data.type) {\n case \"ACK\": {\n // Check our list of ACKs and resolve with the message\n const ack = this.#acks.get(parsedPacket.data.id);\n\n if (!ack) {\n return;\n }\n\n clearTimeout(ack.timeout);\n ack.resolve(parsedPacket.data.message);\n\n break;\n }\n case \"CONNECT\": {\n if (!parsedPacket.data.sessionId) {\n // This is a client trying to connect, so we generate and send back a session ID\n const id = randomUUID();\n\n await this.#sendPacket({ type: \"CONNECT\", sessionId: id });\n\n return;\n }\n\n // This is a server replying to our connect message\n if (this.#sessionId) {\n // We're already connected\n return;\n }\n\n this.#sessionId = parsedPacket.data.sessionId;\n\n break;\n }\n case \"EVENT\": {\n const result = await this.#handler.handleMessage(parsedPacket.data.message);\n\n if (typeof parsedPacket.data.id === \"undefined\") {\n return;\n }\n\n // There's an ID so we should ACK\n await this.#sendPacket({\n type: \"ACK\",\n id: parsedPacket.data.id,\n message: result,\n });\n\n break;\n }\n default: {\n break;\n }\n }\n }\n\n async #sendPacket(packet: Packet) {\n // console.log(\"->\", packet);\n await this.opts.process.send?.(packet);\n }\n\n async send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void> {\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n });\n }\n\n public async sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>,\n timeoutInMs?: number\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>> {\n const currentId = this.#messageCounter++;\n\n return new Promise(async (resolve, reject) => {\n const defaultTimeoutInMs = 2000;\n\n // Timeout if the ACK takes too long to get back to us\n const timeout = setTimeout(() => {\n reject(\n JSON.stringify({\n reason: \"sendWithAck() timeout\",\n timeoutInMs: timeoutInMs ?? defaultTimeoutInMs,\n type,\n payload,\n })\n );\n }, timeoutInMs ?? defaultTimeoutInMs);\n\n this.#acks.set(currentId, { resolve, reject, timeout });\n\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n clearTimeout(timeout);\n return reject(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n clearTimeout(timeout);\n return reject(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n id: currentId,\n });\n });\n }\n}\n","import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessageFromCatalog<TMessageCatalog> {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n callback(ack);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sender({ type, payload, version: \"v1\" });\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}
1
+ {"version":3,"sources":["../../src/v3/zodIpc.ts","../../src/v3/zodMessageHandler.ts"],"names":["randomUUID","z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","messageSchema","ZodIpcMessageHandler","options","schema","handlers","sender","handleMessage","parsedMessage","parseMessage","handler","ack","safeParse","success","JSON","stringify","data","parsedPayload","Packet","discriminatedUnion","sessionId","optional","any","id","number","ZodIpcConnection","opts","Map","listenSchema","send","bind","sendWithAck","connect","emitSchema","timeoutInMs","currentId","Promise","resolve","reject","defaultTimeoutInMs","timeout","setTimeout","reason","set","clearTimeout","process","on","packet","parsedPacket","get","result"],"mappings":"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","sourcesContent":["import { randomUUID } from \"crypto\";\nimport {\n GetSocketCallbackSchema,\n GetSocketMessageSchema,\n GetSocketMessagesWithCallback,\n GetSocketMessagesWithoutCallback,\n MessagesFromSocketCatalog,\n SocketMessageHasCallback,\n ZodSocketMessageCatalogSchema,\n} from \"./zodSocket\";\nimport { z } from \"zod\";\nimport { ZodSchemaParsedError } from \"./zodMessageHandler\";\nimport { inspect } from \"node:util\";\n\ninterface ZodIpcMessageSender<TEmitCatalog extends ZodSocketMessageCatalogSchema> {\n send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void>;\n\n sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>>;\n}\n\ntype ZodIpcMessageHandlers<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = Partial<{\n [K in keyof TListenCatalog]: (\n payload: z.infer<GetSocketMessageSchema<TListenCatalog, K>>,\n sender: ZodIpcMessageSender<TEmitCatalog>\n ) => Promise<\n SocketMessageHasCallback<TListenCatalog, K> extends true\n ? z.input<GetSocketCallbackSchema<TListenCatalog, K>>\n : void\n >;\n}>;\n\nconst messageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\ntype ZodIpcMessageHandlerOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> = {\n schema: TListenCatalog;\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n sender: ZodIpcMessageSender<TEmitCatalog>;\n};\n\nclass ZodIpcMessageHandler<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #schema: TListenCatalog;\n #handlers: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog> | undefined;\n #sender: ZodIpcMessageSender<TEmitCatalog>;\n\n constructor(options: ZodIpcMessageHandlerOptions<TListenCatalog, TEmitCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.handlers;\n this.#sender = options.sender;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n // console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload, this.#sender);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessagesFromSocketCatalog<TListenCatalog> {\n const parsedMessage = messageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n}\n\nconst Packet = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"CONNECT\"),\n sessionId: z.string().optional(),\n }),\n z.object({\n type: z.literal(\"ACK\"),\n message: z.any(),\n id: z.number(),\n }),\n z.object({\n type: z.literal(\"EVENT\"),\n message: z.any(),\n id: z.number().optional(),\n }),\n]);\n\ntype Packet = z.infer<typeof Packet>;\n\ninterface ZodIpcConnectionOptions<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n listenSchema: TListenCatalog;\n emitSchema: TEmitCatalog;\n process: {\n send?: (message: any) => any;\n on?: (event: \"message\", listener: (message: any) => void) => void;\n };\n handlers?: ZodIpcMessageHandlers<TListenCatalog, TEmitCatalog>;\n}\n\nexport class ZodIpcConnection<\n TListenCatalog extends ZodSocketMessageCatalogSchema,\n TEmitCatalog extends ZodSocketMessageCatalogSchema,\n> {\n #sessionId?: string;\n #messageCounter: number = 0;\n\n #handler: ZodIpcMessageHandler<TListenCatalog, TEmitCatalog>;\n\n #acks: Map<\n number,\n {\n resolve: (value: unknown) => void;\n reject: (reason?: any) => void;\n timeout: NodeJS.Timeout;\n }\n > = new Map();\n\n constructor(private opts: ZodIpcConnectionOptions<TListenCatalog, TEmitCatalog>) {\n this.#handler = new ZodIpcMessageHandler({\n schema: opts.listenSchema,\n handlers: opts.handlers,\n sender: {\n send: this.send.bind(this),\n sendWithAck: this.sendWithAck.bind(this),\n },\n });\n\n this.#registerHandlers();\n // this.connect();\n }\n\n async #registerHandlers() {\n if (!this.opts.process.on) {\n return;\n }\n\n this.opts.process.on(\"message\", async (message) => {\n this.#handlePacket(message);\n });\n }\n\n async connect() {\n this.#sendPacket({ type: \"CONNECT\" });\n }\n\n async #handlePacket(packet: Packet): Promise<void> {\n const parsedPacket = Packet.safeParse(packet);\n\n if (!parsedPacket.success) {\n return;\n }\n\n switch (parsedPacket.data.type) {\n case \"ACK\": {\n // Check our list of ACKs and resolve with the message\n const ack = this.#acks.get(parsedPacket.data.id);\n\n if (!ack) {\n return;\n }\n\n clearTimeout(ack.timeout);\n ack.resolve(parsedPacket.data.message);\n\n break;\n }\n case \"CONNECT\": {\n if (!parsedPacket.data.sessionId) {\n // This is a client trying to connect, so we generate and send back a session ID\n const id = randomUUID();\n\n await this.#sendPacket({ type: \"CONNECT\", sessionId: id });\n\n return;\n }\n\n // This is a server replying to our connect message\n if (this.#sessionId) {\n // We're already connected\n return;\n }\n\n this.#sessionId = parsedPacket.data.sessionId;\n\n break;\n }\n case \"EVENT\": {\n const result = await this.#handler.handleMessage(parsedPacket.data.message);\n\n if (typeof parsedPacket.data.id === \"undefined\") {\n return;\n }\n\n // There's an ID so we should ACK\n await this.#sendPacket({\n type: \"ACK\",\n id: parsedPacket.data.id,\n message: result,\n });\n\n break;\n }\n default: {\n break;\n }\n }\n }\n\n async #sendPacket(packet: Packet) {\n await this.opts.process.send?.(packet);\n }\n\n async send<K extends GetSocketMessagesWithoutCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>\n ): Promise<void> {\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n });\n }\n\n public async sendWithAck<K extends GetSocketMessagesWithCallback<TEmitCatalog>>(\n type: K,\n payload: z.input<GetSocketMessageSchema<TEmitCatalog, K>>,\n timeoutInMs?: number\n ): Promise<z.infer<GetSocketCallbackSchema<TEmitCatalog, K>>> {\n const currentId = this.#messageCounter++;\n\n return new Promise(async (resolve, reject) => {\n const defaultTimeoutInMs = 2000;\n\n // Timeout if the ACK takes too long to get back to us\n const timeout = setTimeout(() => {\n reject(\n JSON.stringify({\n reason: \"sendWithAck() timeout\",\n timeoutInMs: timeoutInMs ?? defaultTimeoutInMs,\n type,\n payload,\n })\n );\n }, timeoutInMs ?? defaultTimeoutInMs);\n\n this.#acks.set(currentId, { resolve, reject, timeout });\n\n const schema = this.opts.emitSchema[type][\"message\"];\n\n if (!schema) {\n clearTimeout(timeout);\n return reject(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n clearTimeout(timeout);\n return reject(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sendPacket({\n type: \"EVENT\",\n message: {\n type,\n payload,\n version: \"v1\",\n },\n id: currentId,\n });\n });\n }\n}\n","import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n logger?: StructuredLogger;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n #logger: StructuredLogger | Console;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n this.#logger = options.logger ?? console;\n }\n\n public async handleMessage(message: unknown): Promise<\n | {\n success: true;\n data: unknown;\n }\n | {\n success: false;\n error: string;\n }\n > {\n const parsedMessage = this.parseMessage(message);\n\n if (!parsedMessage.success) {\n this.#logger.error(parsedMessage.error, { message });\n\n return {\n success: false,\n error: parsedMessage.error,\n };\n }\n\n if (!this.#handlers) {\n this.#logger.error(\"No handlers provided\", { message });\n\n return {\n success: false,\n error: \"No handlers provided\",\n };\n }\n\n const handler = this.#handlers[parsedMessage.data.type];\n\n if (!handler) {\n const error = `No handler for message type: ${String(parsedMessage.data.type)}`;\n\n this.#logger.error(error, { message });\n\n return {\n success: false,\n error,\n };\n }\n\n const ack = await handler(parsedMessage.data.payload);\n\n return {\n success: true,\n data: ack,\n };\n }\n\n public parseMessage(message: unknown):\n | {\n success: true;\n data: MessageFromCatalog<TMessageCatalog>;\n }\n | {\n success: false;\n error: string;\n } {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n return {\n success: false,\n error: `Failed to parse message: ${JSON.stringify(parsedMessage.error)}`,\n };\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n return {\n success: false,\n error: `Unknown message type: ${parsedMessage.data.type}`,\n };\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n return {\n success: false,\n error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`,\n };\n }\n\n return {\n success: true,\n data: {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n },\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack: Awaited<ReturnType<ZodMessageHandler<TMessageCatalog>[\"handleMessage\"]>>;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n if (!ack.success) {\n // We don't know the callback type, so we can't do anything else - not all callbacks may accept a success prop\n log.error(\"Failed to handle message, skipping callback\", { message, error: ack.error });\n return;\n }\n\n callback(ack.data);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n try {\n await this.#sender({ type, payload, version: \"v1\" });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to send message\", error);\n }\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n try {\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to forward message\", error);\n }\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}
@@ -16,6 +16,7 @@ type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partia
16
16
  type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {
17
17
  schema: TMessageCatalog;
18
18
  messages?: ZodMessageHandlers<TMessageCatalog>;
19
+ logger?: StructuredLogger;
19
20
  };
20
21
  type MessageFromSchema<K extends keyof TMessageCatalog, TMessageCatalog extends ZodMessageCatalogSchema> = {
21
22
  type: K;
@@ -29,8 +30,8 @@ declare const ZodMessageSchema: z.ZodObject<{
29
30
  type: z.ZodString;
30
31
  payload: z.ZodUnknown;
31
32
  }, "strip", z.ZodTypeAny, {
32
- version: "v1";
33
33
  type: string;
34
+ version: "v1";
34
35
  payload?: unknown;
35
36
  }, {
36
37
  type: string;
@@ -43,8 +44,20 @@ interface EventEmitterLike {
43
44
  declare class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {
44
45
  #private;
45
46
  constructor(options: ZodMessageHandlerOptions<TMessageCatalog>);
46
- handleMessage(message: unknown): Promise<any>;
47
- parseMessage(message: unknown): MessageFromCatalog<TMessageCatalog>;
47
+ handleMessage(message: unknown): Promise<{
48
+ success: true;
49
+ data: unknown;
50
+ } | {
51
+ success: false;
52
+ error: string;
53
+ }>;
54
+ parseMessage(message: unknown): {
55
+ success: true;
56
+ data: MessageFromCatalog<TMessageCatalog>;
57
+ } | {
58
+ success: false;
59
+ error: string;
60
+ };
48
61
  registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger): void;
49
62
  }
50
63
  type ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {
@@ -16,6 +16,7 @@ type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partia
16
16
  type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {
17
17
  schema: TMessageCatalog;
18
18
  messages?: ZodMessageHandlers<TMessageCatalog>;
19
+ logger?: StructuredLogger;
19
20
  };
20
21
  type MessageFromSchema<K extends keyof TMessageCatalog, TMessageCatalog extends ZodMessageCatalogSchema> = {
21
22
  type: K;
@@ -29,8 +30,8 @@ declare const ZodMessageSchema: z.ZodObject<{
29
30
  type: z.ZodString;
30
31
  payload: z.ZodUnknown;
31
32
  }, "strip", z.ZodTypeAny, {
32
- version: "v1";
33
33
  type: string;
34
+ version: "v1";
34
35
  payload?: unknown;
35
36
  }, {
36
37
  type: string;
@@ -43,8 +44,20 @@ interface EventEmitterLike {
43
44
  declare class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {
44
45
  #private;
45
46
  constructor(options: ZodMessageHandlerOptions<TMessageCatalog>);
46
- handleMessage(message: unknown): Promise<any>;
47
- parseMessage(message: unknown): MessageFromCatalog<TMessageCatalog>;
47
+ handleMessage(message: unknown): Promise<{
48
+ success: true;
49
+ data: unknown;
50
+ } | {
51
+ success: false;
52
+ error: string;
53
+ }>;
54
+ parseMessage(message: unknown): {
55
+ success: true;
56
+ data: MessageFromCatalog<TMessageCatalog>;
57
+ } | {
58
+ success: false;
59
+ error: string;
60
+ };
48
61
  registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger): void;
49
62
  }
50
63
  type ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {
@@ -36,43 +36,81 @@ var ZodMessageSchema = zod.z.object({
36
36
  type: zod.z.string(),
37
37
  payload: zod.z.unknown()
38
38
  });
39
- var _schema, _handlers;
39
+ var _schema, _handlers, _logger;
40
40
  var _ZodMessageHandler = class _ZodMessageHandler {
41
41
  constructor(options) {
42
42
  __privateAdd(this, _schema, void 0);
43
43
  __privateAdd(this, _handlers, void 0);
44
+ __privateAdd(this, _logger, void 0);
44
45
  __privateSet(this, _schema, options.schema);
45
46
  __privateSet(this, _handlers, options.messages);
47
+ __privateSet(this, _logger, options.logger ?? console);
46
48
  }
47
49
  async handleMessage(message) {
48
50
  const parsedMessage = this.parseMessage(message);
51
+ if (!parsedMessage.success) {
52
+ __privateGet(this, _logger).error(parsedMessage.error, {
53
+ message
54
+ });
55
+ return {
56
+ success: false,
57
+ error: parsedMessage.error
58
+ };
59
+ }
49
60
  if (!__privateGet(this, _handlers)) {
50
- throw new Error("No handlers provided");
61
+ __privateGet(this, _logger).error("No handlers provided", {
62
+ message
63
+ });
64
+ return {
65
+ success: false,
66
+ error: "No handlers provided"
67
+ };
51
68
  }
52
- const handler = __privateGet(this, _handlers)[parsedMessage.type];
69
+ const handler = __privateGet(this, _handlers)[parsedMessage.data.type];
53
70
  if (!handler) {
54
- console.error(`No handler for message type: ${String(parsedMessage.type)}`);
55
- return;
71
+ const error = `No handler for message type: ${String(parsedMessage.data.type)}`;
72
+ __privateGet(this, _logger).error(error, {
73
+ message
74
+ });
75
+ return {
76
+ success: false,
77
+ error
78
+ };
56
79
  }
57
- const ack = await handler(parsedMessage.payload);
58
- return ack;
80
+ const ack = await handler(parsedMessage.data.payload);
81
+ return {
82
+ success: true,
83
+ data: ack
84
+ };
59
85
  }
60
86
  parseMessage(message) {
61
87
  const parsedMessage = ZodMessageSchema.safeParse(message);
62
88
  if (!parsedMessage.success) {
63
- throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);
89
+ return {
90
+ success: false,
91
+ error: `Failed to parse message: ${JSON.stringify(parsedMessage.error)}`
92
+ };
64
93
  }
65
94
  const schema = __privateGet(this, _schema)[parsedMessage.data.type];
66
95
  if (!schema) {
67
- throw new Error(`Unknown message type: ${parsedMessage.data.type}`);
96
+ return {
97
+ success: false,
98
+ error: `Unknown message type: ${parsedMessage.data.type}`
99
+ };
68
100
  }
69
101
  const parsedPayload = schema.safeParse(parsedMessage.data.payload);
70
102
  if (!parsedPayload.success) {
71
- throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);
103
+ return {
104
+ success: false,
105
+ error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`
106
+ };
72
107
  }
73
108
  return {
74
- type: parsedMessage.data.type,
75
- payload: parsedPayload.data
109
+ success: true,
110
+ data: {
111
+ type: parsedMessage.data.type,
112
+ payload: parsedPayload.data
113
+ }
76
114
  };
77
115
  }
78
116
  registerHandlers(emitter, logger) {
@@ -102,7 +140,14 @@ var _ZodMessageHandler = class _ZodMessageHandler {
102
140
  });
103
141
  }
104
142
  if (callback && typeof callback === "function") {
105
- callback(ack);
143
+ if (!ack.success) {
144
+ log.error("Failed to handle message, skipping callback", {
145
+ message,
146
+ error: ack.error
147
+ });
148
+ return;
149
+ }
150
+ callback(ack.data);
106
151
  }
107
152
  });
108
153
  }
@@ -110,6 +155,7 @@ var _ZodMessageHandler = class _ZodMessageHandler {
110
155
  };
111
156
  _schema = new WeakMap();
112
157
  _handlers = new WeakMap();
158
+ _logger = new WeakMap();
113
159
  __name(_ZodMessageHandler, "ZodMessageHandler");
114
160
  var ZodMessageHandler = _ZodMessageHandler;
115
161
  var _schema2, _sender;
@@ -129,11 +175,15 @@ var _ZodMessageSender = class _ZodMessageSender {
129
175
  if (!parsedPayload.success) {
130
176
  throw new ZodSchemaParsedError(parsedPayload.error, payload);
131
177
  }
132
- await __privateGet(this, _sender).call(this, {
133
- type,
134
- payload,
135
- version: "v1"
136
- });
178
+ try {
179
+ await __privateGet(this, _sender).call(this, {
180
+ type,
181
+ payload,
182
+ version: "v1"
183
+ });
184
+ } catch (error) {
185
+ console.error("[ZodMessageSender] Failed to send message", error);
186
+ }
137
187
  }
138
188
  async forwardMessage(message) {
139
189
  const parsedMessage = ZodMessageSchema.safeParse(message);
@@ -148,11 +198,15 @@ var _ZodMessageSender = class _ZodMessageSender {
148
198
  if (!parsedPayload.success) {
149
199
  throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);
150
200
  }
151
- await __privateGet(this, _sender).call(this, {
152
- type: parsedMessage.data.type,
153
- payload: parsedPayload.data,
154
- version: "v1"
155
- });
201
+ try {
202
+ await __privateGet(this, _sender).call(this, {
203
+ type: parsedMessage.data.type,
204
+ payload: parsedPayload.data,
205
+ version: "v1"
206
+ });
207
+ } catch (error) {
208
+ console.error("[ZodMessageSender] Failed to forward message", error);
209
+ }
156
210
  }
157
211
  };
158
212
  _schema2 = new WeakMap();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/v3/zodMessageHandler.ts"],"names":["z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","ZodMessageHandler","options","schema","messages","handleMessage","parsedMessage","parseMessage","handler","console","String","ack","safeParse","success","JSON","stringify","data","parsedPayload","registerHandlers","emitter","logger","log","info","eventName","Object","keys","on","callback","hasCallback","_schema","ZodMessageSender","sender","send","forwardMessage"],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n }\n\n public async handleMessage(message: unknown) {\n const parsedMessage = this.parseMessage(message);\n\n if (!this.#handlers) {\n throw new Error(\"No handlers provided\");\n }\n\n const handler = this.#handlers[parsedMessage.type];\n\n if (!handler) {\n console.error(`No handler for message type: ${String(parsedMessage.type)}`);\n return;\n }\n\n const ack = await handler(parsedMessage.payload);\n\n return ack;\n }\n\n public parseMessage(message: unknown): MessageFromCatalog<TMessageCatalog> {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n return {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n callback(ack);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n await this.#sender({ type, payload, version: \"v1\" });\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}
1
+ {"version":3,"sources":["../../src/v3/zodMessageHandler.ts"],"names":["z","ZodSchemaParsedError","Error","constructor","error","payload","message","ZodMessageSchema","object","version","literal","default","type","string","unknown","ZodMessageHandler","options","schema","messages","logger","console","handleMessage","parsedMessage","parseMessage","success","handler","data","String","ack","safeParse","JSON","stringify","parsedPayload","registerHandlers","emitter","log","info","eventName","Object","keys","on","callback","hasCallback","_schema","ZodMessageSender","sender","send","forwardMessage"],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { StructuredLogger } from \"./utils/structuredLogger\";\n\nexport class ZodSchemaParsedError extends Error {\n constructor(\n public error: z.ZodError,\n public payload: unknown\n ) {\n super(error.message);\n }\n}\n\nexport type ZodMessageValueSchema<TDiscriminatedUnion extends z.ZodDiscriminatedUnion<any, any>> =\n | z.ZodFirstPartySchemaTypes\n | TDiscriminatedUnion;\n\nexport interface ZodMessageCatalogSchema {\n [key: string]: ZodMessageValueSchema<any>;\n}\n\nexport type ZodMessageHandlers<TCatalogSchema extends ZodMessageCatalogSchema> = Partial<{\n [K in keyof TCatalogSchema]: (payload: z.infer<TCatalogSchema[K]>) => Promise<any>;\n}>;\n\nexport type ZodMessageHandlerOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n messages?: ZodMessageHandlers<TMessageCatalog>;\n logger?: StructuredLogger;\n};\n\nexport type MessageFromSchema<\n K extends keyof TMessageCatalog,\n TMessageCatalog extends ZodMessageCatalogSchema,\n> = {\n type: K;\n payload: z.input<TMessageCatalog[K]>;\n};\n\nexport type MessageFromCatalog<TMessageCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TMessageCatalog]: MessageFromSchema<K, TMessageCatalog>;\n}[keyof TMessageCatalog];\n\nexport const ZodMessageSchema = z.object({\n version: z.literal(\"v1\").default(\"v1\"),\n type: z.string(),\n payload: z.unknown(),\n});\n\nexport interface EventEmitterLike {\n on(eventName: string | symbol, listener: (...args: any[]) => void): this;\n}\n\nexport class ZodMessageHandler<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #handlers: ZodMessageHandlers<TMessageCatalog> | undefined;\n #logger: StructuredLogger | Console;\n\n constructor(options: ZodMessageHandlerOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#handlers = options.messages;\n this.#logger = options.logger ?? console;\n }\n\n public async handleMessage(message: unknown): Promise<\n | {\n success: true;\n data: unknown;\n }\n | {\n success: false;\n error: string;\n }\n > {\n const parsedMessage = this.parseMessage(message);\n\n if (!parsedMessage.success) {\n this.#logger.error(parsedMessage.error, { message });\n\n return {\n success: false,\n error: parsedMessage.error,\n };\n }\n\n if (!this.#handlers) {\n this.#logger.error(\"No handlers provided\", { message });\n\n return {\n success: false,\n error: \"No handlers provided\",\n };\n }\n\n const handler = this.#handlers[parsedMessage.data.type];\n\n if (!handler) {\n const error = `No handler for message type: ${String(parsedMessage.data.type)}`;\n\n this.#logger.error(error, { message });\n\n return {\n success: false,\n error,\n };\n }\n\n const ack = await handler(parsedMessage.data.payload);\n\n return {\n success: true,\n data: ack,\n };\n }\n\n public parseMessage(message: unknown):\n | {\n success: true;\n data: MessageFromCatalog<TMessageCatalog>;\n }\n | {\n success: false;\n error: string;\n } {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n return {\n success: false,\n error: `Failed to parse message: ${JSON.stringify(parsedMessage.error)}`,\n };\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n return {\n success: false,\n error: `Unknown message type: ${parsedMessage.data.type}`,\n };\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n return {\n success: false,\n error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`,\n };\n }\n\n return {\n success: true,\n data: {\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n },\n };\n }\n\n public registerHandlers(emitter: EventEmitterLike, logger?: StructuredLogger) {\n const log = logger ?? console;\n\n if (!this.#handlers) {\n log.info(\"No handlers provided\");\n return;\n }\n\n for (const eventName of Object.keys(this.#schema)) {\n emitter.on(eventName, async (message: any, callback?: any): Promise<void> => {\n log.info(`handling ${eventName}`, {\n payload: message,\n hasCallback: !!callback,\n });\n\n let ack: Awaited<ReturnType<ZodMessageHandler<TMessageCatalog>[\"handleMessage\"]>>;\n\n // FIXME: this only works if the message doesn't have genuine payload prop\n if (\"payload\" in message) {\n ack = await this.handleMessage({ type: eventName, ...message });\n } else {\n // Handle messages not sent by ZodMessageSender\n const { version, ...payload } = message;\n ack = await this.handleMessage({ type: eventName, version, payload });\n }\n\n if (callback && typeof callback === \"function\") {\n if (!ack.success) {\n // We don't know the callback type, so we can't do anything else - not all callbacks may accept a success prop\n log.error(\"Failed to handle message, skipping callback\", { message, error: ack.error });\n return;\n }\n\n callback(ack.data);\n }\n });\n }\n }\n}\n\ntype ZodMessageSenderCallback<TMessageCatalog extends ZodMessageCatalogSchema> = (message: {\n type: keyof TMessageCatalog;\n payload: z.infer<TMessageCatalog[keyof TMessageCatalog]>;\n version: \"v1\";\n}) => Promise<void>;\n\nexport type ZodMessageSenderOptions<TMessageCatalog extends ZodMessageCatalogSchema> = {\n schema: TMessageCatalog;\n sender: ZodMessageSenderCallback<TMessageCatalog>;\n};\n\nexport class ZodMessageSender<TMessageCatalog extends ZodMessageCatalogSchema> {\n #schema: TMessageCatalog;\n #sender: ZodMessageSenderCallback<TMessageCatalog>;\n\n constructor(options: ZodMessageSenderOptions<TMessageCatalog>) {\n this.#schema = options.schema;\n this.#sender = options.sender;\n }\n\n public async send<K extends keyof TMessageCatalog>(\n type: K,\n payload: z.input<TMessageCatalog[K]>\n ) {\n const schema = this.#schema[type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${type as string}`);\n }\n\n const parsedPayload = schema.safeParse(payload);\n\n if (!parsedPayload.success) {\n throw new ZodSchemaParsedError(parsedPayload.error, payload);\n }\n\n try {\n await this.#sender({ type, payload, version: \"v1\" });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to send message\", error);\n }\n }\n\n public async forwardMessage(message: unknown) {\n const parsedMessage = ZodMessageSchema.safeParse(message);\n\n if (!parsedMessage.success) {\n throw new Error(`Failed to parse message: ${JSON.stringify(parsedMessage.error)}`);\n }\n\n const schema = this.#schema[parsedMessage.data.type];\n\n if (!schema) {\n throw new Error(`Unknown message type: ${parsedMessage.data.type}`);\n }\n\n const parsedPayload = schema.safeParse(parsedMessage.data.payload);\n\n if (!parsedPayload.success) {\n throw new Error(`Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`);\n }\n\n try {\n await this.#sender({\n type: parsedMessage.data.type,\n payload: parsedPayload.data,\n version: \"v1\",\n });\n } catch (error) {\n console.error(\"[ZodMessageSender] Failed to forward message\", error);\n }\n }\n}\n\nexport type MessageCatalogToSocketIoEvents<TCatalog extends ZodMessageCatalogSchema> = {\n [K in keyof TCatalog]: (message: z.infer<TCatalog[K]>) => void;\n};\n"]}