@trigger.dev/core 3.0.0-beta.47 → 3.0.0-beta.49
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.
- package/dist/api-Pl9fxB8v.d.mts +13879 -0
- package/dist/api-sNoooMbT.d.ts +13879 -0
- package/dist/{catalog-NxVZnWZh.d.ts → catalog-U7_q4XsM.d.mts} +12 -34
- package/dist/{catalog-N-X0Te3W.d.mts → catalog-bSnBE19I.d.ts} +12 -34
- package/dist/{common-fIyU5pmz.d.mts → common-CLW82lkt.d.mts} +1 -1
- package/dist/{common-fIyU5pmz.d.ts → common-CLW82lkt.d.ts} +1 -1
- package/dist/{eventFilterMatches-2kHImluE.d.mts → eventFilter-66NaBAMi.d.mts} +1 -3
- package/dist/{eventFilterMatches-2kHImluE.d.ts → eventFilter-66NaBAMi.d.ts} +1 -3
- package/dist/eventFilterMatches.d.mts +6 -0
- package/dist/eventFilterMatches.d.ts +6 -0
- package/dist/eventFilterMatches.js +165 -0
- package/dist/eventFilterMatches.js.map +1 -0
- package/dist/eventFilterMatches.mjs +163 -0
- package/dist/eventFilterMatches.mjs.map +1 -0
- package/dist/index.d.mts +14 -16716
- package/dist/index.d.ts +14 -16716
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/json-DBPEJQRe.d.mts +16 -0
- package/dist/json-DBPEJQRe.d.ts +16 -0
- package/dist/{manager-X_HrWQ7_.d.mts → manager-KvCabW1a.d.mts} +1 -1
- package/dist/{manager-2ZQ3_twq.d.ts → manager-OBA35PzR.d.ts} +1 -1
- package/dist/replacements.d.mts +22 -0
- package/dist/replacements.d.ts +22 -0
- package/dist/replacements.js +33 -0
- package/dist/replacements.js.map +1 -0
- package/dist/replacements.mjs +28 -0
- package/dist/replacements.mjs.map +1 -0
- package/dist/requestFilter-HNZQEpQb.d.ts +180 -0
- package/dist/requestFilter-b5W2_1oP.d.mts +180 -0
- package/dist/requestFilterMatches.d.mts +13 -0
- package/dist/requestFilterMatches.d.ts +13 -0
- package/dist/requestFilterMatches.js +238 -0
- package/dist/requestFilterMatches.js.map +1 -0
- package/dist/requestFilterMatches.mjs +235 -0
- package/dist/requestFilterMatches.mjs.map +1 -0
- package/dist/retry.d.mts +10 -0
- package/dist/retry.d.ts +10 -0
- package/dist/retry.js +100 -0
- package/dist/retry.js.map +1 -0
- package/dist/retry.mjs +97 -0
- package/dist/retry.mjs.map +1 -0
- package/dist/schemas/index.d.mts +2611 -0
- package/dist/schemas/index.d.ts +2611 -0
- package/dist/schemas/index.js +1630 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/index.mjs +1463 -0
- package/dist/schemas/index.mjs.map +1 -0
- package/dist/{schemas-Zy7mGFgD.d.mts → schemas-WHkFakb3.d.mts} +4 -1
- package/dist/{schemas-Zy7mGFgD.d.ts → schemas-WHkFakb3.d.ts} +4 -1
- package/dist/taskLogger-CzADe4je.d.ts +33 -0
- package/dist/taskLogger-r_AFTX45.d.mts +33 -0
- package/dist/types.d.mts +11 -0
- package/dist/types.d.ts +11 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +3 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils.d.mts +7 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +33 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +30 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/v3/dev/index.d.mts +2 -2
- package/dist/v3/dev/index.d.ts +2 -2
- package/dist/v3/errors.d.mts +39 -0
- package/dist/v3/errors.d.ts +39 -0
- package/dist/v3/errors.js +204 -0
- package/dist/v3/errors.js.map +1 -0
- package/dist/v3/errors.mjs +195 -0
- package/dist/v3/errors.mjs.map +1 -0
- package/dist/v3/index.d.mts +46 -211
- package/dist/v3/index.d.ts +46 -211
- package/dist/v3/index.js +3 -2
- package/dist/v3/index.js.map +1 -1
- package/dist/v3/index.mjs +3 -2
- package/dist/v3/index.mjs.map +1 -1
- package/dist/v3/logger-api.d.mts +24 -0
- package/dist/v3/logger-api.d.ts +24 -0
- package/dist/v3/logger-api.js +118 -0
- package/dist/v3/logger-api.js.map +1 -0
- package/dist/v3/logger-api.mjs +116 -0
- package/dist/v3/logger-api.mjs.map +1 -0
- package/dist/v3/otel/index.js +1 -1
- package/dist/v3/otel/index.js.map +1 -1
- package/dist/v3/otel/index.mjs +1 -1
- package/dist/v3/otel/index.mjs.map +1 -1
- package/dist/v3/prod/index.d.mts +3 -3
- package/dist/v3/prod/index.d.ts +3 -3
- package/dist/v3/schemas/index.d.mts +110 -110
- package/dist/v3/schemas/index.d.ts +110 -110
- package/dist/v3/schemas/index.js +2 -1
- package/dist/v3/schemas/index.js.map +1 -1
- package/dist/v3/schemas/index.mjs +2 -1
- package/dist/v3/schemas/index.mjs.map +1 -1
- package/dist/v3/semanticInternalAttributes.d.mts +56 -0
- package/dist/v3/semanticInternalAttributes.d.ts +56 -0
- package/dist/v3/semanticInternalAttributes.js +61 -0
- package/dist/v3/semanticInternalAttributes.js.map +1 -0
- package/dist/v3/semanticInternalAttributes.mjs +59 -0
- package/dist/v3/semanticInternalAttributes.mjs.map +1 -0
- package/dist/v3/utils/flattenAttributes.d.mts +8 -0
- package/dist/v3/utils/flattenAttributes.d.ts +8 -0
- package/dist/v3/utils/flattenAttributes.js +131 -0
- package/dist/v3/utils/flattenAttributes.js.map +1 -0
- package/dist/v3/utils/flattenAttributes.mjs +126 -0
- package/dist/v3/utils/flattenAttributes.mjs.map +1 -0
- package/dist/v3/utils/ioSerialization.d.mts +21 -0
- package/dist/v3/utils/ioSerialization.d.ts +21 -0
- package/dist/v3/utils/ioSerialization.js +2348 -0
- package/dist/v3/utils/ioSerialization.js.map +1 -0
- package/dist/v3/utils/ioSerialization.mjs +2339 -0
- package/dist/v3/utils/ioSerialization.mjs.map +1 -0
- package/dist/v3/utils/omit.d.mts +3 -0
- package/dist/v3/utils/omit.d.ts +3 -0
- package/dist/v3/utils/omit.js +20 -0
- package/dist/v3/utils/omit.js.map +1 -0
- package/dist/v3/utils/omit.mjs +18 -0
- package/dist/v3/utils/omit.mjs.map +1 -0
- package/dist/v3/utils/retries.d.mts +46 -0
- package/dist/v3/utils/retries.d.ts +46 -0
- package/dist/v3/utils/retries.js +118 -0
- package/dist/v3/utils/retries.js.map +1 -0
- package/dist/v3/utils/retries.mjs +113 -0
- package/dist/v3/utils/retries.mjs.map +1 -0
- package/dist/v3/workers/index.d.mts +7 -6
- package/dist/v3/workers/index.d.ts +7 -6
- package/dist/v3/workers/index.js +3 -2
- package/dist/v3/workers/index.js.map +1 -1
- package/dist/v3/workers/index.mjs +3 -2
- package/dist/v3/workers/index.mjs.map +1 -1
- package/dist/v3/zodIpc.js.map +1 -1
- package/dist/v3/zodIpc.mjs.map +1 -1
- package/dist/v3/zodMessageHandler.d.mts +16 -3
- package/dist/v3/zodMessageHandler.d.ts +16 -3
- package/dist/v3/zodMessageHandler.js +59 -13
- package/dist/v3/zodMessageHandler.js.map +1 -1
- package/dist/v3/zodMessageHandler.mjs +59 -13
- package/dist/v3/zodMessageHandler.mjs.map +1 -1
- package/dist/v3/zodNamespace.js.map +1 -1
- package/dist/v3/zodNamespace.mjs.map +1 -1
- package/dist/v3/zodfetch.d.mts +1 -1
- package/dist/v3/zodfetch.d.ts +1 -1
- package/dist/versions.d.mts +11 -0
- package/dist/versions.d.ts +11 -0
- package/dist/versions.js +31 -0
- package/dist/versions.js.map +1 -0
- package/dist/versions.mjs +27 -0
- package/dist/versions.mjs.map +1 -0
- package/package.json +137 -17
- package/dist/{messages-Sggr4tid.d.mts → messages-I-h-zZN9.d.mts} +32 -32
- package/dist/{messages-Sggr4tid.d.ts → messages-I-h-zZN9.d.ts} +32 -32
package/dist/v3/zodIpc.js.map
CHANGED
|
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,kBAAkB;AAU3B,SAASC,KAAAA,UAAS;;;ACVlB,SAASA,SAAS;AAGX,IAAMC,wBAAN,MAAMA,8BAA6BC,MAAAA;EACxCC,YACSC,OACAC,SACP;AACA,UAAMD,MAAME,OAAO;iBAHZF;mBACAC;EAGT;AACF;AAP0CH;AAAnC,IAAMD,uBAAN;AAsCA,IAAMM,mBAAmBP,EAAEQ,OAAO;EACvCC,SAAST,EAAEU,QAAQ,IAAA,EAAMC,QAAQ,IAAA;EACjCC,MAAMZ,EAAEa,OAAM;EACdR,SAASL,EAAEc,QAAO;AACpB,CAAA;;;ADLA,IAAMC,gBAAgBf,GAAEQ,OAAO;EAC7BC,SAAST,GAAEU,QAAQ,IAAA,EAAMC,QAAQ,IAAA;EACjCC,MAAMZ,GAAEa,OAAM;EACdR,SAASL,GAAEc,QAAO;AACpB,CAAA;AA5CA;AAuDA,IAAME,wBAAN,WAAMA;EAQJb,YAAYc,SAAoE;AAJhF;AACA;AACA;AAGE,uBAAK,SAAUA,QAAQC;AACvB,uBAAK,WAAYD,QAAQE;AACzB,uBAAK,SAAUF,QAAQG;EACzB;EAEA,MAAaC,cAAcf,SAAkB;AAC3C,UAAMgB,gBAAgB,KAAKC,aAAajB,OAAAA;AAExC,QAAI,CAAC,mBAAK,YAAW;AACnB,YAAM,IAAIJ,MAAM,sBAAA;IAClB;AAEA,UAAMsB,UAAU,mBAAK,WAAUF,cAAcV,IAAI;AAEjD,QAAI,CAACY,SAAS;AAEZ;IACF;AAEA,UAAMC,MAAM,MAAMD,QAAQF,cAAcjB,SAAS,mBAAK,QAAO;AAE7D,WAAOoB;EACT;EAEOF,aAAajB,SAA6D;AAC/E,UAAMgB,gBAAgBP,cAAcW,UAAUpB,OAAAA;AAE9C,QAAI,CAACgB,cAAcK,SAAS;AAC1B,YAAM,IAAIzB,MAAM,4BAA4B0B,KAAKC,UAAUP,cAAclB,KAAK,CAAA,EAAG;IACnF;AAEA,UAAMc,SAAS,mBAAK,SAAQI,cAAcQ,KAAKlB,IAAI,EAAE,SAAA;AAErD,QAAI,CAACM,QAAQ;AACX,YAAM,IAAIhB,MAAM,yBAAyBoB,cAAcQ,KAAKlB,IAAI,EAAE;IACpE;AAEA,UAAMmB,gBAAgBb,OAAOQ,UAAUJ,cAAcQ,KAAKzB,OAAO;AAEjE,QAAI,CAAC0B,cAAcJ,SAAS;AAC1B,YAAM,IAAIzB,MAAM,oCAAoC0B,KAAKC,UAAUE,cAAc3B,KAAK,CAAA,EAAG;IAC3F;AAEA,WAAO;MACLQ,MAAMU,cAAcQ,KAAKlB;MACzBP,SAAS0B,cAAcD;IACzB;EACF;AACF,GArDE,yBACA,2BACA,yBANId,oCAAN;AA2DA,IAAMgB,SAAShC,GAAEiC,mBAAmB,QAAQ;EAC1CjC,GAAEQ,OAAO;IACPI,MAAMZ,GAAEU,QAAQ,SAAA;IAChBwB,WAAWlC,GAAEa,OAAM,EAAGsB,SAAQ;EAChC,CAAA;EACAnC,GAAEQ,OAAO;IACPI,MAAMZ,GAAEU,QAAQ,KAAA;IAChBJ,SAASN,GAAEoC,IAAG;IACdC,IAAIrC,GAAEsC,OAAM;EACd,CAAA;EACAtC,GAAEQ,OAAO;IACPI,MAAMZ,GAAEU,QAAQ,OAAA;IAChBJ,SAASN,GAAEoC,IAAG;IACdC,IAAIrC,GAAEsC,OAAM,EAAGH,SAAQ;EACzB,CAAA;CACD;AAjID;AAkJO,IAAMI,oBAAN,MAAMA,kBAAAA;EAkBXpC,YAAoBqC,MAA6D;AAcjF,uBAAM;AAcN,uBAAM;AA+DN,uBAAM;AAzGN;AACA;AAEA;AAEA;gBASoBA;uBAbpB,iBAA0B;uBAI1B,OAOI,oBAAIC,IAAAA;AAGN,uBAAK,UAAW,IAAIzB,qBAAqB;MACvCE,QAAQsB,KAAKE;MACbvB,UAAUqB,KAAKrB;MACfC,QAAQ;QACNuB,MAAM,KAAKA,KAAKC,KAAK,IAAI;QACzBC,aAAa,KAAKA,YAAYD,KAAK,IAAI;MACzC;IACF,CAAA;AAEA,0BAAK,wCAAL;EAEF;EAYA,MAAME,UAAU;AACd,0BAAK,4BAAL,WAAiB;MAAElC,MAAM;IAAU;EACrC;EAqEA,MAAM+B,KACJ/B,MACAP,SACe;AACf,UAAMa,SAAS,KAAKsB,KAAKO,WAAWnC,IAAAA,EAAM,SAAA;AAE1C,QAAI,CAACM,QAAQ;AACX,YAAM,IAAIhB,MAAM,yBAAyBU,IAAAA,EAAgB;IAC3D;AAEA,UAAMmB,gBAAgBb,OAAOQ,UAAUrB,OAAAA;AAEvC,QAAI,CAAC0B,cAAcJ,SAAS;AAC1B,YAAM,IAAI1B,qBAAqB8B,cAAc3B,OAAOC,OAAAA;IACtD;AAEA,UAAM,sBAAK,4BAAL,WAAiB;MACrBO,MAAM;MACNN,SAAS;QACPM;QACAP;QACAI,SAAS;MACX;IACF;EACF;EAEA,MAAaoC,YACXjC,MACAP,SACA2C,aAC4D;AAC5D,UAAMC,YAAY,uBAAK,iBAAL;AAElB,WAAO,IAAIC,QAAQ,OAAOC,SAASC,WAAW;AAC5C,YAAMC,qBAAqB;AAG3B,YAAMC,UAAUC,WAAW,MAAM;AAC/BH,eACExB,KAAKC,UAAU;UACb2B,QAAQ;UACRR,aAAaA,eAAeK;UAC5BzC;UACAP;QACF,CAAA,CAAA;MAEJ,GAAG2C,eAAeK,kBAAAA;AAElB,yBAAK,OAAMI,IAAIR,WAAW;QAAEE;QAASC;QAAQE;MAAQ,CAAA;AAErD,YAAMpC,SAAS,KAAKsB,KAAKO,WAAWnC,IAAAA,EAAM,SAAA;AAE1C,UAAI,CAACM,QAAQ;AACXwC,qBAAaJ,OAAAA;AACb,eAAOF,OAAO,yBAAyBxC,IAAAA,EAAgB;MACzD;AAEA,YAAMmB,gBAAgBb,OAAOQ,UAAUrB,OAAAA;AAEvC,UAAI,CAAC0B,cAAcJ,SAAS;AAC1B+B,qBAAaJ,OAAAA;AACb,eAAOF,OAAO,oCAAoCxB,KAAKC,UAAUE,cAAc3B,KAAK,CAAA,EAAG;MACzF;AAEA,YAAM,sBAAK,4BAAL,WAAiB;QACrBQ,MAAM;QACNN,SAAS;UACPM;UACAP;UACAI,SAAS;QACX;QACA4B,IAAIY;MACN;IACF,CAAA;EACF;AACF;AAxLE;AACA;AAEA;AAEA;AAuBM;sBAAiB,wCAAG;AACxB,MAAI,CAAC,KAAKT,KAAKmB,QAAQC,IAAI;AACzB;EACF;AAEA,OAAKpB,KAAKmB,QAAQC,GAAG,WAAW,OAAOtD,YAAY;AACjD,0BAAK,gCAAL,WAAmBA;EACrB,CAAA;AACF,GARuB;AAcjB;kBAAa,sCAACuD,QAA+B;AACjD,QAAMC,eAAe9B,OAAON,UAAUmC,MAAAA;AAEtC,MAAI,CAACC,aAAanC,SAAS;AACzB;EACF;AAEA,UAAQmC,aAAahC,KAAKlB,MAAI;IAC5B,KAAK,OAAO;AAEV,YAAMa,MAAM,mBAAK,OAAMsC,IAAID,aAAahC,KAAKO,EAAE;AAE/C,UAAI,CAACZ,KAAK;AACR;MACF;AAEAiC,mBAAajC,IAAI6B,OAAO;AACxB7B,UAAI0B,QAAQW,aAAahC,KAAKxB,OAAO;AAErC;IACF;IACA,KAAK,WAAW;AACd,UAAI,CAACwD,aAAahC,KAAKI,WAAW;AAEhC,cAAMG,KAAKtC,WAAAA;AAEX,cAAM,sBAAK,4BAAL,WAAiB;UAAEa,MAAM;UAAWsB,WAAWG;QAAG;AAExD;MACF;AAGA,UAAI,mBAAK,aAAY;AAEnB;MACF;AAEA,yBAAK,YAAayB,aAAahC,KAAKI;AAEpC;IACF;IACA,KAAK,SAAS;AACZ,YAAM8B,SAAS,MAAM,mBAAK,UAAS3C,cAAcyC,aAAahC,KAAKxB,OAAO;AAE1E,UAAI,OAAOwD,aAAahC,KAAKO,OAAO,aAAa;AAC/C;MACF;AAGA,YAAM,sBAAK,4BAAL,WAAiB;QACrBzB,MAAM;QACNyB,IAAIyB,aAAahC,KAAKO;QACtB/B,SAAS0D;MACX;AAEA;IACF;IACA,SAAS;AACP;IACF;EACF;AACF,GA7DmB;AA+Db;gBAAW,sCAACH,SAAgB;AAChC,QAAM,KAAKrB,KAAKmB,QAAQhB,OAAOkB,OAAAA;AACjC,GAFiB;AA7GNtB;AAAN,IAAMA,mBAAN","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};\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 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
|
+
{"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"]}
|
package/dist/v3/zodIpc.mjs.map
CHANGED
|
@@ -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\";\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};\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 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
|
+
{"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<
|
|
47
|
-
|
|
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<
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`
|
|
106
|
+
};
|
|
72
107
|
}
|
|
73
108
|
return {
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -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 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
|
+
{"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"]}
|
|
@@ -34,43 +34,81 @@ var ZodMessageSchema = z.object({
|
|
|
34
34
|
type: z.string(),
|
|
35
35
|
payload: z.unknown()
|
|
36
36
|
});
|
|
37
|
-
var _schema, _handlers;
|
|
37
|
+
var _schema, _handlers, _logger;
|
|
38
38
|
var _ZodMessageHandler = class _ZodMessageHandler {
|
|
39
39
|
constructor(options) {
|
|
40
40
|
__privateAdd(this, _schema, void 0);
|
|
41
41
|
__privateAdd(this, _handlers, void 0);
|
|
42
|
+
__privateAdd(this, _logger, void 0);
|
|
42
43
|
__privateSet(this, _schema, options.schema);
|
|
43
44
|
__privateSet(this, _handlers, options.messages);
|
|
45
|
+
__privateSet(this, _logger, options.logger ?? console);
|
|
44
46
|
}
|
|
45
47
|
async handleMessage(message) {
|
|
46
48
|
const parsedMessage = this.parseMessage(message);
|
|
49
|
+
if (!parsedMessage.success) {
|
|
50
|
+
__privateGet(this, _logger).error(parsedMessage.error, {
|
|
51
|
+
message
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: parsedMessage.error
|
|
56
|
+
};
|
|
57
|
+
}
|
|
47
58
|
if (!__privateGet(this, _handlers)) {
|
|
48
|
-
|
|
59
|
+
__privateGet(this, _logger).error("No handlers provided", {
|
|
60
|
+
message
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: "No handlers provided"
|
|
65
|
+
};
|
|
49
66
|
}
|
|
50
|
-
const handler = __privateGet(this, _handlers)[parsedMessage.type];
|
|
67
|
+
const handler = __privateGet(this, _handlers)[parsedMessage.data.type];
|
|
51
68
|
if (!handler) {
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
const error = `No handler for message type: ${String(parsedMessage.data.type)}`;
|
|
70
|
+
__privateGet(this, _logger).error(error, {
|
|
71
|
+
message
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error
|
|
76
|
+
};
|
|
54
77
|
}
|
|
55
|
-
const ack = await handler(parsedMessage.payload);
|
|
56
|
-
return
|
|
78
|
+
const ack = await handler(parsedMessage.data.payload);
|
|
79
|
+
return {
|
|
80
|
+
success: true,
|
|
81
|
+
data: ack
|
|
82
|
+
};
|
|
57
83
|
}
|
|
58
84
|
parseMessage(message) {
|
|
59
85
|
const parsedMessage = ZodMessageSchema.safeParse(message);
|
|
60
86
|
if (!parsedMessage.success) {
|
|
61
|
-
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: `Failed to parse message: ${JSON.stringify(parsedMessage.error)}`
|
|
90
|
+
};
|
|
62
91
|
}
|
|
63
92
|
const schema = __privateGet(this, _schema)[parsedMessage.data.type];
|
|
64
93
|
if (!schema) {
|
|
65
|
-
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
error: `Unknown message type: ${parsedMessage.data.type}`
|
|
97
|
+
};
|
|
66
98
|
}
|
|
67
99
|
const parsedPayload = schema.safeParse(parsedMessage.data.payload);
|
|
68
100
|
if (!parsedPayload.success) {
|
|
69
|
-
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: `Failed to parse message payload: ${JSON.stringify(parsedPayload.error)}`
|
|
104
|
+
};
|
|
70
105
|
}
|
|
71
106
|
return {
|
|
72
|
-
|
|
73
|
-
|
|
107
|
+
success: true,
|
|
108
|
+
data: {
|
|
109
|
+
type: parsedMessage.data.type,
|
|
110
|
+
payload: parsedPayload.data
|
|
111
|
+
}
|
|
74
112
|
};
|
|
75
113
|
}
|
|
76
114
|
registerHandlers(emitter, logger) {
|
|
@@ -100,7 +138,14 @@ var _ZodMessageHandler = class _ZodMessageHandler {
|
|
|
100
138
|
});
|
|
101
139
|
}
|
|
102
140
|
if (callback && typeof callback === "function") {
|
|
103
|
-
|
|
141
|
+
if (!ack.success) {
|
|
142
|
+
log.error("Failed to handle message, skipping callback", {
|
|
143
|
+
message,
|
|
144
|
+
error: ack.error
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
callback(ack.data);
|
|
104
149
|
}
|
|
105
150
|
});
|
|
106
151
|
}
|
|
@@ -108,6 +153,7 @@ var _ZodMessageHandler = class _ZodMessageHandler {
|
|
|
108
153
|
};
|
|
109
154
|
_schema = new WeakMap();
|
|
110
155
|
_handlers = new WeakMap();
|
|
156
|
+
_logger = new WeakMap();
|
|
111
157
|
__name(_ZodMessageHandler, "ZodMessageHandler");
|
|
112
158
|
var ZodMessageHandler = _ZodMessageHandler;
|
|
113
159
|
var _schema2, _sender;
|