@pattern-stack/codegen 0.15.1 → 0.15.3
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/CHANGELOG.md +85 -0
- package/dist/chunk-27ETSJ2X.js +84 -0
- package/dist/chunk-27ETSJ2X.js.map +1 -0
- package/dist/chunk-2E224ZSN.js +20 -0
- package/dist/chunk-2E224ZSN.js.map +1 -0
- package/dist/chunk-2FTZLDBP.js +179 -0
- package/dist/chunk-2FTZLDBP.js.map +1 -0
- package/dist/chunk-2N4UG4VD.js +20 -0
- package/dist/chunk-2N4UG4VD.js.map +1 -0
- package/dist/chunk-2TVVBC53.js +92 -0
- package/dist/chunk-2TVVBC53.js.map +1 -0
- package/dist/chunk-2VHZ7EKC.js +37 -0
- package/dist/chunk-2VHZ7EKC.js.map +1 -0
- package/dist/chunk-32BMMV4H.js +109 -0
- package/dist/chunk-32BMMV4H.js.map +1 -0
- package/dist/chunk-32DOFN3T.js +4042 -0
- package/dist/chunk-32DOFN3T.js.map +1 -0
- package/dist/chunk-36U5UGIO.js +107 -0
- package/dist/chunk-36U5UGIO.js.map +1 -0
- package/dist/chunk-3CJFPU6Q.js +14 -0
- package/dist/chunk-3CJFPU6Q.js.map +1 -0
- package/dist/chunk-3NMCDN7L.js +90 -0
- package/dist/chunk-3NMCDN7L.js.map +1 -0
- package/dist/chunk-3SZFUTXE.js +62 -0
- package/dist/chunk-3SZFUTXE.js.map +1 -0
- package/dist/chunk-4DOJBQTP.js +117 -0
- package/dist/chunk-4DOJBQTP.js.map +1 -0
- package/dist/chunk-4H3PETLM.js +290 -0
- package/dist/chunk-4H3PETLM.js.map +1 -0
- package/dist/chunk-4JLJYWJC.js +308 -0
- package/dist/chunk-4JLJYWJC.js.map +1 -0
- package/dist/chunk-4KNXX6TI.js +29 -0
- package/dist/chunk-4KNXX6TI.js.map +1 -0
- package/dist/chunk-4LH67P4U.js +17 -0
- package/dist/chunk-4LH67P4U.js.map +1 -0
- package/dist/chunk-4MF3HKJA.js +94 -0
- package/dist/chunk-4MF3HKJA.js.map +1 -0
- package/dist/chunk-4MVGAMUA.js +40 -0
- package/dist/chunk-4MVGAMUA.js.map +1 -0
- package/dist/chunk-4RFHUZXU.js +635 -0
- package/dist/chunk-4RFHUZXU.js.map +1 -0
- package/dist/chunk-5A432NZJ.js +7 -0
- package/dist/chunk-5A432NZJ.js.map +1 -0
- package/dist/chunk-5Y7W3XR6.js +356 -0
- package/dist/chunk-5Y7W3XR6.js.map +1 -0
- package/dist/chunk-6DWFJNIK.js +15 -0
- package/dist/chunk-6DWFJNIK.js.map +1 -0
- package/dist/chunk-6I7ULIN6.js +15 -0
- package/dist/chunk-6I7ULIN6.js.map +1 -0
- package/dist/chunk-6XY6ZMMD.js +25 -0
- package/dist/chunk-6XY6ZMMD.js.map +1 -0
- package/dist/chunk-7B3RYX45.js +63 -0
- package/dist/chunk-7B3RYX45.js.map +1 -0
- package/dist/chunk-7C3FOSDI.js +1 -0
- package/dist/chunk-7C3FOSDI.js.map +1 -0
- package/dist/chunk-7KOW6PU6.js +59 -0
- package/dist/chunk-7KOW6PU6.js.map +1 -0
- package/dist/chunk-7RELQJIN.js +22 -0
- package/dist/chunk-7RELQJIN.js.map +1 -0
- package/dist/chunk-7YGORYZD.js +112 -0
- package/dist/chunk-7YGORYZD.js.map +1 -0
- package/dist/chunk-AHV4GDYM.js +63 -0
- package/dist/chunk-AHV4GDYM.js.map +1 -0
- package/dist/chunk-AQFQ4BYM.js +81 -0
- package/dist/chunk-AQFQ4BYM.js.map +1 -0
- package/dist/chunk-AS3NAZB6.js +14 -0
- package/dist/chunk-AS3NAZB6.js.map +1 -0
- package/dist/chunk-BGULBWKJ.js +88 -0
- package/dist/chunk-BGULBWKJ.js.map +1 -0
- package/dist/chunk-BIO6F7YI.js +17 -0
- package/dist/chunk-BIO6F7YI.js.map +1 -0
- package/dist/chunk-BOPZWRJK.js +36 -0
- package/dist/chunk-BOPZWRJK.js.map +1 -0
- package/dist/chunk-BPARRK6F.js +14 -0
- package/dist/chunk-BPARRK6F.js.map +1 -0
- package/dist/chunk-CO6LUM72.js +59 -0
- package/dist/chunk-CO6LUM72.js.map +1 -0
- package/dist/chunk-DCCZB4UC.js +100 -0
- package/dist/chunk-DCCZB4UC.js.map +1 -0
- package/dist/chunk-DV4RV2DC.js +59 -0
- package/dist/chunk-DV4RV2DC.js.map +1 -0
- package/dist/chunk-EDKJU5BO.js +11 -0
- package/dist/chunk-EDKJU5BO.js.map +1 -0
- package/dist/chunk-EO2QPOKH.js +116 -0
- package/dist/chunk-EO2QPOKH.js.map +1 -0
- package/dist/chunk-EOLLMEAH.js +155 -0
- package/dist/chunk-EOLLMEAH.js.map +1 -0
- package/dist/chunk-EWYCWP4H.js +14 -0
- package/dist/chunk-EWYCWP4H.js.map +1 -0
- package/dist/chunk-EXVDJMIY.js +33 -0
- package/dist/chunk-EXVDJMIY.js.map +1 -0
- package/dist/chunk-FASRXRX5.js +19 -0
- package/dist/chunk-FASRXRX5.js.map +1 -0
- package/dist/chunk-FBGHYQIZ.js +201 -0
- package/dist/chunk-FBGHYQIZ.js.map +1 -0
- package/dist/chunk-FI34KYZ5.js +1 -0
- package/dist/chunk-FI34KYZ5.js.map +1 -0
- package/dist/chunk-FN2PYDPP.js +1 -0
- package/dist/chunk-FN2PYDPP.js.map +1 -0
- package/dist/chunk-GCYKMF22.js +81 -0
- package/dist/chunk-GCYKMF22.js.map +1 -0
- package/dist/chunk-GM3RMJIJ.js +92 -0
- package/dist/chunk-GM3RMJIJ.js.map +1 -0
- package/dist/chunk-GYGNEQSC.js +9 -0
- package/dist/chunk-GYGNEQSC.js.map +1 -0
- package/dist/chunk-H5NH7KPE.js +21 -0
- package/dist/chunk-H5NH7KPE.js.map +1 -0
- package/dist/chunk-HNWZFNKP.js +168 -0
- package/dist/chunk-HNWZFNKP.js.map +1 -0
- package/dist/chunk-HUH73XGI.js +1 -0
- package/dist/chunk-HUH73XGI.js.map +1 -0
- package/dist/chunk-I6MVCB5A.js +39 -0
- package/dist/chunk-I6MVCB5A.js.map +1 -0
- package/dist/chunk-IBGER4YK.js +12 -0
- package/dist/chunk-IBGER4YK.js.map +1 -0
- package/dist/chunk-IF5I3DAA.js +92 -0
- package/dist/chunk-IF5I3DAA.js.map +1 -0
- package/dist/chunk-IP4OO26U.js +54 -0
- package/dist/chunk-IP4OO26U.js.map +1 -0
- package/dist/chunk-IWAOY6KC.js +1 -0
- package/dist/chunk-IWAOY6KC.js.map +1 -0
- package/dist/chunk-IYNSRIGR.js +122 -0
- package/dist/chunk-IYNSRIGR.js.map +1 -0
- package/dist/chunk-J37YWU7Y.js +19 -0
- package/dist/chunk-J37YWU7Y.js.map +1 -0
- package/dist/chunk-J6KZS54B.js +269 -0
- package/dist/chunk-J6KZS54B.js.map +1 -0
- package/dist/chunk-J6MN42LG.js +19 -0
- package/dist/chunk-J6MN42LG.js.map +1 -0
- package/dist/chunk-J7JMVS2B.js +53 -0
- package/dist/chunk-J7JMVS2B.js.map +1 -0
- package/dist/chunk-JRQO2IOF.js +65 -0
- package/dist/chunk-JRQO2IOF.js.map +1 -0
- package/dist/chunk-JWNHNUYL.js +96 -0
- package/dist/chunk-JWNHNUYL.js.map +1 -0
- package/dist/chunk-K2I6XIK5.js +122 -0
- package/dist/chunk-K2I6XIK5.js.map +1 -0
- package/dist/chunk-KVOWSC5S.js +1 -0
- package/dist/chunk-KVOWSC5S.js.map +1 -0
- package/dist/chunk-KYR3B3OW.js +79 -0
- package/dist/chunk-KYR3B3OW.js.map +1 -0
- package/dist/chunk-L3LZWWSX.js +61 -0
- package/dist/chunk-L3LZWWSX.js.map +1 -0
- package/dist/chunk-L4SDDEEU.js +1 -0
- package/dist/chunk-L4SDDEEU.js.map +1 -0
- package/dist/chunk-L6FTY45T.js +13 -0
- package/dist/chunk-L6FTY45T.js.map +1 -0
- package/dist/chunk-L7BNNRGI.js +134 -0
- package/dist/chunk-L7BNNRGI.js.map +1 -0
- package/dist/chunk-LG57S2SC.js +150 -0
- package/dist/chunk-LG57S2SC.js.map +1 -0
- package/dist/chunk-M6QLSLPO.js +97 -0
- package/dist/chunk-M6QLSLPO.js.map +1 -0
- package/dist/chunk-MZ6GV4YF.js +21 -0
- package/dist/chunk-MZ6GV4YF.js.map +1 -0
- package/dist/chunk-N5OTOWTP.js +55 -0
- package/dist/chunk-N5OTOWTP.js.map +1 -0
- package/dist/chunk-NN7XZEGF.js +14 -0
- package/dist/chunk-NN7XZEGF.js.map +1 -0
- package/dist/chunk-NPFPZ2HO.js +13 -0
- package/dist/chunk-NPFPZ2HO.js.map +1 -0
- package/dist/chunk-NXXDZ6ZF.js +42 -0
- package/dist/chunk-NXXDZ6ZF.js.map +1 -0
- package/dist/chunk-NYBCQZC7.js +11 -0
- package/dist/chunk-NYBCQZC7.js.map +1 -0
- package/dist/chunk-O37C3YE6.js +111 -0
- package/dist/chunk-O37C3YE6.js.map +1 -0
- package/dist/chunk-OFRRBC7M.js +78 -0
- package/dist/chunk-OFRRBC7M.js.map +1 -0
- package/dist/chunk-OGIZXGPY.js +222 -0
- package/dist/chunk-OGIZXGPY.js.map +1 -0
- package/dist/chunk-OKXZ63IA.js +168 -0
- package/dist/chunk-OKXZ63IA.js.map +1 -0
- package/dist/chunk-OSQRXVG2.js +58 -0
- package/dist/chunk-OSQRXVG2.js.map +1 -0
- package/dist/chunk-OTDN3OUQ.js +215 -0
- package/dist/chunk-OTDN3OUQ.js.map +1 -0
- package/dist/chunk-PNZSGAB2.js +114 -0
- package/dist/chunk-PNZSGAB2.js.map +1 -0
- package/dist/chunk-PRWIX6UW.js +21 -0
- package/dist/chunk-PRWIX6UW.js.map +1 -0
- package/dist/chunk-PSXUNOVU.js +7 -0
- package/dist/chunk-PSXUNOVU.js.map +1 -0
- package/dist/chunk-QLTJSCE6.js +44 -0
- package/dist/chunk-QLTJSCE6.js.map +1 -0
- package/dist/chunk-RC23QROE.js +447 -0
- package/dist/chunk-RC23QROE.js.map +1 -0
- package/dist/chunk-RDVTWIYY.js +212 -0
- package/dist/chunk-RDVTWIYY.js.map +1 -0
- package/dist/chunk-RFH7N6EP.js +36 -0
- package/dist/chunk-RFH7N6EP.js.map +1 -0
- package/dist/chunk-RHVN6NA7.js +134 -0
- package/dist/chunk-RHVN6NA7.js.map +1 -0
- package/dist/chunk-S7C6TIIF.js +21 -0
- package/dist/chunk-S7C6TIIF.js.map +1 -0
- package/dist/chunk-SNQ3TOWP.js +20 -0
- package/dist/chunk-SNQ3TOWP.js.map +1 -0
- package/dist/chunk-SOVM2VEK.js +14 -0
- package/dist/chunk-SOVM2VEK.js.map +1 -0
- package/dist/chunk-SQDOBLBP.js +13 -0
- package/dist/chunk-SQDOBLBP.js.map +1 -0
- package/dist/chunk-SR7F3TJY.js +130 -0
- package/dist/chunk-SR7F3TJY.js.map +1 -0
- package/dist/chunk-SZVPIHWE.js +129 -0
- package/dist/chunk-SZVPIHWE.js.map +1 -0
- package/dist/chunk-T4BIIU5E.js +89 -0
- package/dist/chunk-T4BIIU5E.js.map +1 -0
- package/dist/chunk-T6SCOJF4.js +92 -0
- package/dist/chunk-T6SCOJF4.js.map +1 -0
- package/dist/chunk-TNXH7BJS.js +48 -0
- package/dist/chunk-TNXH7BJS.js.map +1 -0
- package/dist/chunk-U64T4YZE.js +9 -0
- package/dist/chunk-U64T4YZE.js.map +1 -0
- package/dist/chunk-UQ5EHOH2.js +39 -0
- package/dist/chunk-UQ5EHOH2.js.map +1 -0
- package/dist/chunk-UTN4GBPQ.js +1 -0
- package/dist/chunk-UTN4GBPQ.js.map +1 -0
- package/dist/chunk-V4AF6DI4.js +16 -0
- package/dist/chunk-V4AF6DI4.js.map +1 -0
- package/dist/chunk-W72PRNJY.js +126 -0
- package/dist/chunk-W72PRNJY.js.map +1 -0
- package/dist/chunk-WL67FZGF.js +21 -0
- package/dist/chunk-WL67FZGF.js.map +1 -0
- package/dist/chunk-WWGYCIJX.js +29 -0
- package/dist/chunk-WWGYCIJX.js.map +1 -0
- package/dist/chunk-X2GMTYPA.js +50 -0
- package/dist/chunk-X2GMTYPA.js.map +1 -0
- package/dist/chunk-XCEI7NUH.js +41 -0
- package/dist/chunk-XCEI7NUH.js.map +1 -0
- package/dist/chunk-Y7GDG744.js +88 -0
- package/dist/chunk-Y7GDG744.js.map +1 -0
- package/dist/chunk-Y7RRSEOC.js +9 -0
- package/dist/chunk-Y7RRSEOC.js.map +1 -0
- package/dist/chunk-YLPAPPLW.js +75 -0
- package/dist/chunk-YLPAPPLW.js.map +1 -0
- package/dist/chunk-YPWODKD5.js +184 -0
- package/dist/chunk-YPWODKD5.js.map +1 -0
- package/dist/chunk-YSLTTQLC.js +25 -0
- package/dist/chunk-YSLTTQLC.js.map +1 -0
- package/dist/chunk-YTN6BKWA.js +121 -0
- package/dist/chunk-YTN6BKWA.js.map +1 -0
- package/dist/chunk-Z7PQCAVK.js +200 -0
- package/dist/chunk-Z7PQCAVK.js.map +1 -0
- package/dist/chunk-ZUKFQL6E.js +47 -0
- package/dist/chunk-ZUKFQL6E.js.map +1 -0
- package/dist/chunk-ZUMULSEQ.js +1 -0
- package/dist/chunk-ZUMULSEQ.js.map +1 -0
- package/dist/runtime/analytics/index.js +8 -41
- package/dist/runtime/analytics/index.js.map +1 -1
- package/dist/runtime/analytics/types.js +8 -41
- package/dist/runtime/analytics/types.js.map +1 -1
- package/dist/runtime/base-classes/activity-entity-repository.js +6 -312
- package/dist/runtime/base-classes/activity-entity-repository.js.map +1 -1
- package/dist/runtime/base-classes/activity-entity-service.js +6 -212
- package/dist/runtime/base-classes/activity-entity-service.js.map +1 -1
- package/dist/runtime/base-classes/base-read-use-cases.js +5 -27
- package/dist/runtime/base-classes/base-read-use-cases.js.map +1 -1
- package/dist/runtime/base-classes/base-repository.js +5 -277
- package/dist/runtime/base-classes/base-repository.js.map +1 -1
- package/dist/runtime/base-classes/base-service.js +5 -184
- package/dist/runtime/base-classes/base-service.js.map +1 -1
- package/dist/runtime/base-classes/index.js +59 -1076
- package/dist/runtime/base-classes/index.js.map +1 -1
- package/dist/runtime/base-classes/integrated-entity-repository.js +6 -486
- package/dist/runtime/base-classes/integrated-entity-repository.js.map +1 -1
- package/dist/runtime/base-classes/integrated-entity-service.js +6 -213
- package/dist/runtime/base-classes/integrated-entity-service.js.map +1 -1
- package/dist/runtime/base-classes/junction-integration-repository.js +8 -448
- package/dist/runtime/base-classes/junction-integration-repository.js.map +1 -1
- package/dist/runtime/base-classes/knowledge-entity-repository.js +6 -283
- package/dist/runtime/base-classes/knowledge-entity-repository.js.map +1 -1
- package/dist/runtime/base-classes/knowledge-entity-service.js +6 -190
- package/dist/runtime/base-classes/knowledge-entity-service.js.map +1 -1
- package/dist/runtime/base-classes/lifecycle-events.js +8 -70
- package/dist/runtime/base-classes/lifecycle-events.js.map +1 -1
- package/dist/runtime/base-classes/metadata-entity-repository.js +6 -330
- package/dist/runtime/base-classes/metadata-entity-repository.js.map +1 -1
- package/dist/runtime/base-classes/metadata-entity-service.js +6 -212
- package/dist/runtime/base-classes/metadata-entity-service.js.map +1 -1
- package/dist/runtime/base-classes/tenant-context.js +10 -36
- package/dist/runtime/base-classes/tenant-context.js.map +1 -1
- package/dist/runtime/base-classes/with-analytics.js +4 -7
- package/dist/runtime/base-classes/with-analytics.js.map +1 -1
- package/dist/runtime/constants/tokens.js +5 -3
- package/dist/runtime/constants/tokens.js.map +1 -1
- package/dist/runtime/eav-helpers.js +2 -0
- package/dist/runtime/eav-helpers.js.map +1 -1
- package/dist/runtime/pipes/zod-validation.pipe.js +3 -10
- package/dist/runtime/pipes/zod-validation.pipe.js.map +1 -1
- package/dist/runtime/shared/openapi/error-response.dto.js +5 -8
- package/dist/runtime/shared/openapi/error-response.dto.js.map +1 -1
- package/dist/runtime/shared/openapi/errors.js +5 -19
- package/dist/runtime/shared/openapi/errors.js.map +1 -1
- package/dist/runtime/shared/openapi/index.js +15 -106
- package/dist/runtime/shared/openapi/index.js.map +1 -1
- package/dist/runtime/shared/openapi/registry.js +6 -103
- package/dist/runtime/shared/openapi/registry.js.map +1 -1
- package/dist/runtime/shared/openapi/registry.tokens.js +4 -2
- package/dist/runtime/shared/openapi/registry.tokens.js.map +1 -1
- package/dist/runtime/subsystems/analytics/analytics.module.js +8 -117
- package/dist/runtime/subsystems/analytics/analytics.module.js.map +1 -1
- package/dist/runtime/subsystems/analytics/analytics.tokens.js +7 -8
- package/dist/runtime/subsystems/analytics/analytics.tokens.js.map +1 -1
- package/dist/runtime/subsystems/analytics/cube-backend.js +6 -71
- package/dist/runtime/subsystems/analytics/cube-backend.js.map +1 -1
- package/dist/runtime/subsystems/analytics/index.js +16 -117
- package/dist/runtime/subsystems/analytics/index.js.map +1 -1
- package/dist/runtime/subsystems/analytics/noop-backend.js +4 -21
- package/dist/runtime/subsystems/analytics/noop-backend.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js +4 -8
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.module.js +12 -359
- package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.tokens.js +12 -13
- package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/encryption-key/env.js +4 -49
- package/dist/runtime/subsystems/auth/backends/encryption-key/env.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js +6 -64
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js +5 -47
- package/dist/runtime/subsystems/auth/backends/state-store.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js +5 -139
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -1
- package/dist/runtime/subsystems/auth/index.js +53 -542
- package/dist/runtime/subsystems/auth/index.js.map +1 -1
- package/dist/runtime/subsystems/auth/middleware/requester-context.js +9 -65
- package/dist/runtime/subsystems/auth/middleware/requester-context.js.map +1 -1
- package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js +4 -9
- package/dist/runtime/subsystems/auth/protocols/oauth-state-store.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js +4 -15
- package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js +5 -104
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/session-expired.error.js +5 -16
- package/dist/runtime/subsystems/auth/runtime/session-expired.error.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js +5 -29
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js.map +1 -1
- package/dist/runtime/subsystems/bridge/assert-tenant-id.js +5 -18
- package/dist/runtime/subsystems/bridge/assert-tenant-id.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js +12 -184
- package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js +10 -448
- package/dist/runtime/subsystems/bridge/bridge-delivery.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-delivery.memory-backend.js +5 -126
- package/dist/runtime/subsystems/bridge/bridge-delivery.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-delivery.schema.js +6 -308
- package/dist/runtime/subsystems/bridge/bridge-delivery.schema.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-errors.js +6 -35
- package/dist/runtime/subsystems/bridge/bridge-errors.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js +14 -606
- package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge.module.js +35 -3476
- package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge.tokens.js +9 -7
- package/dist/runtime/subsystems/bridge/bridge.tokens.js.map +1 -1
- package/dist/runtime/subsystems/bridge/event-flow.service.js +11 -137
- package/dist/runtime/subsystems/bridge/event-flow.service.js.map +1 -1
- package/dist/runtime/subsystems/bridge/generated/registry.js +4 -2
- package/dist/runtime/subsystems/bridge/generated/registry.js.map +1 -1
- package/dist/runtime/subsystems/bridge/index.js +60 -3470
- package/dist/runtime/subsystems/bridge/index.js.map +1 -1
- package/dist/runtime/subsystems/bridge/reserved-pools.js +4 -6
- package/dist/runtime/subsystems/bridge/reserved-pools.js.map +1 -1
- package/dist/runtime/subsystems/cache/cache.drizzle-backend.js +10 -133
- package/dist/runtime/subsystems/cache/cache.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/cache/cache.memory-backend.js +6 -101
- package/dist/runtime/subsystems/cache/cache.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/cache/cache.module.js +10 -278
- package/dist/runtime/subsystems/cache/cache.module.js.map +1 -1
- package/dist/runtime/subsystems/cache/cache.schema.js +4 -14
- package/dist/runtime/subsystems/cache/cache.schema.js.map +1 -1
- package/dist/runtime/subsystems/cache/cache.tokens.js +6 -7
- package/dist/runtime/subsystems/cache/cache.tokens.js.map +1 -1
- package/dist/runtime/subsystems/cache/index.js +20 -278
- package/dist/runtime/subsystems/cache/index.js.map +1 -1
- package/dist/runtime/subsystems/events/domain-events.schema.js +3 -72
- package/dist/runtime/subsystems/events/domain-events.schema.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +9 -413
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js +7 -235
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.redis-backend.js +8 -20
- package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-keyset-cursor.js +8 -30
- package/dist/runtime/subsystems/events/event-keyset-cursor.js.map +1 -1
- package/dist/runtime/subsystems/events/event-read.protocol.js +2 -0
- package/dist/runtime/subsystems/events/event-read.protocol.js.map +1 -1
- package/dist/runtime/subsystems/events/events-errors.js +4 -11
- package/dist/runtime/subsystems/events/events-errors.js.map +1 -1
- package/dist/runtime/subsystems/events/events.module.js +15 -949
- package/dist/runtime/subsystems/events/events.module.js.map +1 -1
- package/dist/runtime/subsystems/events/events.tokens.js +10 -11
- package/dist/runtime/subsystems/events/events.tokens.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/bus.js +9 -240
- package/dist/runtime/subsystems/events/generated/bus.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/index.js +23 -240
- package/dist/runtime/subsystems/events/generated/index.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/registry.js +5 -82
- package/dist/runtime/subsystems/events/generated/registry.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/schemas.js +12 -52
- package/dist/runtime/subsystems/events/generated/schemas.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/types.js +1 -0
- package/dist/runtime/subsystems/events/index.js +32 -949
- package/dist/runtime/subsystems/events/index.js.map +1 -1
- package/dist/runtime/subsystems/index.d.ts +5 -1
- package/dist/runtime/subsystems/index.js +182 -5912
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/integration/build-change-source.js +6 -178
- package/dist/runtime/subsystems/integration/build-change-source.js.map +1 -1
- package/dist/runtime/subsystems/integration/deep-equal.differ.js +4 -109
- package/dist/runtime/subsystems/integration/deep-equal.differ.js.map +1 -1
- package/dist/runtime/subsystems/integration/detection-config.schema.js +11 -78
- package/dist/runtime/subsystems/integration/detection-config.schema.js.map +1 -1
- package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js +5 -30
- package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js.map +1 -1
- package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js +4 -9
- package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js.map +1 -1
- package/dist/runtime/subsystems/integration/execute-integration.use-case.js +6 -239
- package/dist/runtime/subsystems/integration/execute-integration.use-case.js.map +1 -1
- package/dist/runtime/subsystems/integration/incremental-read.js +5 -144
- package/dist/runtime/subsystems/integration/incremental-read.js.map +1 -1
- package/dist/runtime/subsystems/integration/index.js +83 -1352
- package/dist/runtime/subsystems/integration/index.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-audit.schema.js +10 -155
- package/dist/runtime/subsystems/integration/integration-audit.schema.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js +7 -270
- package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-cursor-store.memory-backend.js +4 -65
- package/dist/runtime/subsystems/integration/integration-cursor-store.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-errors.js +5 -15
- package/dist/runtime/subsystems/integration/integration-errors.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-field-diff.protocol.js +5 -7
- package/dist/runtime/subsystems/integration/integration-field-diff.protocol.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js +8 -303
- package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration-run-recorder.memory-backend.js +5 -125
- package/dist/runtime/subsystems/integration/integration-run-recorder.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration.module.js +13 -700
- package/dist/runtime/subsystems/integration/integration.module.js.map +1 -1
- package/dist/runtime/subsystems/integration/integration.tokens.js +11 -9
- package/dist/runtime/subsystems/integration/integration.tokens.js.map +1 -1
- package/dist/runtime/subsystems/integration/loopback.middleware.js +4 -16
- package/dist/runtime/subsystems/integration/loopback.middleware.js.map +1 -1
- package/dist/runtime/subsystems/integration/poll-change-source.d.ts +1 -1
- package/dist/runtime/subsystems/integration/poll-change-source.js +4 -89
- package/dist/runtime/subsystems/integration/poll-change-source.js.map +1 -1
- package/dist/runtime/subsystems/integration/webhook-change-source.d.ts +4 -3
- package/dist/runtime/subsystems/integration/webhook-change-source.js +4 -70
- package/dist/runtime/subsystems/integration/webhook-change-source.js.map +1 -1
- package/dist/runtime/subsystems/jobs/bullmq.config.js +9 -140
- package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
- package/dist/runtime/subsystems/jobs/index.js +88 -2691
- package/dist/runtime/subsystems/jobs/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-handler.base.js +10 -49
- package/dist/runtime/subsystems/jobs/job-handler.base.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestration.schema.js +13 -152
- package/dist/runtime/subsystems/jobs/job-orchestration.schema.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +36 -699
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js +10 -564
- package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js +10 -824
- package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.js +9 -51
- package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +9 -416
- package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js +9 -290
- package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-step-service.drizzle-backend.js +5 -213
- package/dist/runtime/subsystems/jobs/job-step-service.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-step-service.memory-backend.js +5 -131
- package/dist/runtime/subsystems/jobs/job-step-service.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +9 -175
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.js +14 -613
- package/dist/runtime/subsystems/jobs/job-worker.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.js +23 -2647
- package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +19 -1897
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js +8 -9
- package/dist/runtime/subsystems/jobs/jobs-domain.tokens.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-errors.js +10 -78
- package/dist/runtime/subsystems/jobs/jobs-errors.js.map +1 -1
- package/dist/runtime/subsystems/jobs/memory-job-store.js +4 -15
- package/dist/runtime/subsystems/jobs/memory-job-store.js.map +1 -1
- package/dist/runtime/subsystems/jobs/pool-config.loader.js +9 -124
- package/dist/runtime/subsystems/jobs/pool-config.loader.js.map +1 -1
- package/dist/runtime/subsystems/observability/index.js +21 -310
- package/dist/runtime/subsystems/observability/index.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability-errors.js +4 -9
- package/dist/runtime/subsystems/observability/observability-errors.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.module.js +11 -300
- package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.service.js +9 -197
- package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.tokens.js +5 -3
- package/dist/runtime/subsystems/observability/observability.tokens.js.map +1 -1
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js +4 -84
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js.map +1 -1
- package/dist/runtime/subsystems/observability/reporters/index.js +5 -84
- package/dist/runtime/subsystems/observability/reporters/index.js.map +1 -1
- package/dist/runtime/subsystems/storage/index.js +15 -200
- package/dist/runtime/subsystems/storage/index.js.map +1 -1
- package/dist/runtime/subsystems/storage/storage.local-backend.js +4 -103
- package/dist/runtime/subsystems/storage/storage.local-backend.js.map +1 -1
- package/dist/runtime/subsystems/storage/storage.memory-backend.js +5 -68
- package/dist/runtime/subsystems/storage/storage.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/storage/storage.module.js +8 -200
- package/dist/runtime/subsystems/storage/storage.module.js.map +1 -1
- package/dist/runtime/subsystems/storage/storage.tokens.js +5 -6
- package/dist/runtime/subsystems/storage/storage.tokens.js.map +1 -1
- package/dist/runtime/subsystems/storage/storage.utils.js +4 -14
- package/dist/runtime/subsystems/storage/storage.utils.js.map +1 -1
- package/dist/runtime/subsystems/token-key.js +5 -3
- package/dist/runtime/subsystems/token-key.js.map +1 -1
- package/dist/src/cli/index.js +637 -5454
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.js +68 -4170
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/subsystems/bridge/bridge-outbox-drain-hook.ts +44 -21
- package/runtime/subsystems/index.ts +27 -0
- package/runtime/subsystems/integration/poll-change-source.ts +10 -7
- package/runtime/subsystems/integration/webhook-change-source.ts +12 -8
- package/runtime/subsystems/jobs/job-worker.ts +17 -11
|
@@ -1,238 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (kind && result) __defProp(target, key, result);
|
|
9
|
-
return result;
|
|
10
|
-
};
|
|
11
|
-
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
12
|
-
|
|
13
|
-
// runtime/subsystems/events/event-bus.memory-backend.ts
|
|
14
|
-
import { Inject, Injectable, Logger, Optional } from "@nestjs/common";
|
|
15
|
-
|
|
16
|
-
// runtime/subsystems/events/event-keyset-cursor.ts
|
|
17
|
-
var DEFAULT_EVENT_LIST_LIMIT = 50;
|
|
18
|
-
var MAX_EVENT_LIST_LIMIT = 200;
|
|
19
|
-
function clampEventLimit(limit) {
|
|
20
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
21
|
-
return DEFAULT_EVENT_LIST_LIMIT;
|
|
22
|
-
}
|
|
23
|
-
const floored = Math.floor(limit);
|
|
24
|
-
if (floored < 1) return 1;
|
|
25
|
-
if (floored > MAX_EVENT_LIST_LIMIT) return MAX_EVENT_LIST_LIMIT;
|
|
26
|
-
return floored;
|
|
27
|
-
}
|
|
28
|
-
function encodeEventCursor(keyset) {
|
|
29
|
-
const tuple = [keyset.occurredAt.toISOString(), keyset.id];
|
|
30
|
-
return Buffer.from(JSON.stringify(tuple), "utf8").toString("base64url");
|
|
31
|
-
}
|
|
32
|
-
function decodeEventCursor(cursor) {
|
|
33
|
-
try {
|
|
34
|
-
const json = Buffer.from(cursor, "base64url").toString("utf8");
|
|
35
|
-
const parsed = JSON.parse(json);
|
|
36
|
-
if (!Array.isArray(parsed) || parsed.length !== 2) return null;
|
|
37
|
-
const [iso, id] = parsed;
|
|
38
|
-
if (typeof iso !== "string" || typeof id !== "string") return null;
|
|
39
|
-
const occurredAt = new Date(iso);
|
|
40
|
-
if (Number.isNaN(occurredAt.getTime())) return null;
|
|
41
|
-
return { occurredAt, id };
|
|
42
|
-
} catch {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// runtime/subsystems/token-key.ts
|
|
48
|
-
var PKG = "@pattern-stack/codegen";
|
|
49
|
-
var tokenKey = (area, name) => `${PKG}.${area}.${name}`;
|
|
50
|
-
|
|
51
|
-
// runtime/subsystems/events/events.tokens.ts
|
|
52
|
-
var REDIS_URL = Symbol.for(tokenKey("events", "redis-url"));
|
|
53
|
-
var EVENTS_MODULE_OPTIONS = "EVENTS_MODULE_OPTIONS";
|
|
54
|
-
|
|
55
|
-
// runtime/subsystems/events/event-bus.memory-backend.ts
|
|
56
|
-
function toEventSummary(event) {
|
|
57
|
-
const metadata = event.metadata;
|
|
58
|
-
const str = (key) => {
|
|
59
|
-
const v = metadata?.[key];
|
|
60
|
-
return typeof v === "string" ? v : null;
|
|
61
|
-
};
|
|
62
|
-
return {
|
|
63
|
-
id: event.id,
|
|
64
|
-
type: event.type,
|
|
65
|
-
aggregateId: event.aggregateId,
|
|
66
|
-
aggregateType: event.aggregateType,
|
|
67
|
-
status: "processed",
|
|
68
|
-
pool: str("pool"),
|
|
69
|
-
direction: str("direction"),
|
|
70
|
-
tier: str("tier") ?? "domain",
|
|
71
|
-
rootRunId: str("rootRunId"),
|
|
72
|
-
tenantId: str("tenantId"),
|
|
73
|
-
occurredAt: event.occurredAt,
|
|
74
|
-
processedAt: event.occurredAt
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
var MemoryEventBus = class {
|
|
78
|
-
logger = new Logger(MemoryEventBus.name);
|
|
79
|
-
/** All events published since construction (or last clear). */
|
|
80
|
-
publishedEvents = [];
|
|
81
|
-
handlers = /* @__PURE__ */ new Map();
|
|
82
|
-
opts;
|
|
83
|
-
constructor(opts) {
|
|
84
|
-
this.opts = opts ?? { backend: "memory" };
|
|
85
|
-
}
|
|
86
|
-
async publish(event) {
|
|
87
|
-
this.assertTierRouting(event);
|
|
88
|
-
this.publishedEvents.push(event);
|
|
89
|
-
if (this.shouldDispatch(event)) {
|
|
90
|
-
await this.dispatch(event);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
async publishMany(events) {
|
|
94
|
-
for (const event of events) {
|
|
95
|
-
await this.publish(event);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
async findById(eventId) {
|
|
99
|
-
return this.publishedEvents.find((e) => e.id === eventId) ?? null;
|
|
100
|
-
}
|
|
101
|
-
subscribe(eventType, handler) {
|
|
102
|
-
if (!this.handlers.has(eventType)) {
|
|
103
|
-
this.handlers.set(eventType, /* @__PURE__ */ new Set());
|
|
104
|
-
}
|
|
105
|
-
const set = this.handlers.get(eventType);
|
|
106
|
-
const h = handler;
|
|
107
|
-
set.add(h);
|
|
108
|
-
return () => {
|
|
109
|
-
set.delete(h);
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// ============================================================================
|
|
113
|
-
// IEventReadPort (OBS-LIST-1)
|
|
114
|
-
// ============================================================================
|
|
115
|
-
async listEvents(query = {}) {
|
|
116
|
-
const limit = clampEventLimit(query.limit);
|
|
117
|
-
const keyset = query.cursor ? decodeEventCursor(query.cursor) : null;
|
|
118
|
-
const str = (e, key) => {
|
|
119
|
-
const v = e.metadata?.[key];
|
|
120
|
-
return typeof v === "string" ? v : null;
|
|
121
|
-
};
|
|
122
|
-
const matched = this.publishedEvents.filter((e) => {
|
|
123
|
-
if (query.poolId && str(e, "pool") !== query.poolId) return false;
|
|
124
|
-
if (query.direction && str(e, "direction") !== query.direction)
|
|
125
|
-
return false;
|
|
126
|
-
if (query.rootRunId && str(e, "rootRunId") !== query.rootRunId)
|
|
127
|
-
return false;
|
|
128
|
-
if (query.since && e.occurredAt.getTime() < query.since.getTime())
|
|
129
|
-
return false;
|
|
130
|
-
if (query.tenantId !== void 0) {
|
|
131
|
-
const t = str(e, "tenantId");
|
|
132
|
-
if (query.tenantId === null) {
|
|
133
|
-
if (t !== null) return false;
|
|
134
|
-
} else if (t !== query.tenantId) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return true;
|
|
139
|
-
});
|
|
140
|
-
matched.sort((a, b) => {
|
|
141
|
-
const dt = b.occurredAt.getTime() - a.occurredAt.getTime();
|
|
142
|
-
if (dt !== 0) return dt;
|
|
143
|
-
return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
|
|
144
|
-
});
|
|
145
|
-
const seeked = keyset ? matched.filter((e) => {
|
|
146
|
-
const ct = e.occurredAt.getTime();
|
|
147
|
-
const kt = keyset.occurredAt.getTime();
|
|
148
|
-
if (ct < kt) return true;
|
|
149
|
-
if (ct > kt) return false;
|
|
150
|
-
return e.id < keyset.id;
|
|
151
|
-
}) : matched;
|
|
152
|
-
const hasMore = seeked.length > limit;
|
|
153
|
-
const page = hasMore ? seeked.slice(0, limit) : seeked;
|
|
154
|
-
const items = page.map(toEventSummary);
|
|
155
|
-
const last = page[page.length - 1];
|
|
156
|
-
const nextCursor = hasMore && last ? encodeEventCursor({ occurredAt: last.occurredAt, id: last.id }) : null;
|
|
157
|
-
return { items, nextCursor };
|
|
158
|
-
}
|
|
159
|
-
/** Remove all published events and subscriptions. Useful in beforeEach. */
|
|
160
|
-
clear() {
|
|
161
|
-
this.publishedEvents.length = 0;
|
|
162
|
-
this.handlers.clear();
|
|
163
|
-
}
|
|
164
|
-
/** Filter published events by `metadata.pool`. */
|
|
165
|
-
publishedEventsForPool(pool) {
|
|
166
|
-
return this.publishedEvents.filter((e) => e.metadata?.["pool"] === pool);
|
|
167
|
-
}
|
|
168
|
-
/** Filter published events by `metadata.direction`. */
|
|
169
|
-
publishedEventsForDirection(direction) {
|
|
170
|
-
return this.publishedEvents.filter((e) => e.metadata?.["direction"] === direction);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Decide whether `event` should be dispatched to handlers given the
|
|
174
|
-
* current pool filter.
|
|
175
|
-
*
|
|
176
|
-
* Semantics (mirroring `DrizzleEventBus.processBatch`):
|
|
177
|
-
* - `opts.pools` undefined → dispatch everything (no filter).
|
|
178
|
-
* - `opts.pools` empty array → treated as "no filter" to match the
|
|
179
|
-
* Drizzle backend, where `pools && pools.length > 0` is the gate on
|
|
180
|
-
* the `inArray` WHERE clause. Empty arrays dispatch everything.
|
|
181
|
-
* - `opts.pools` non-empty → dispatch only when `event.metadata.pool`
|
|
182
|
-
* is in the list. Events without `metadata.pool` do NOT match — they
|
|
183
|
-
* are out of all configured pools by definition.
|
|
184
|
-
*/
|
|
185
|
-
shouldDispatch(event) {
|
|
186
|
-
const pools = this.opts.pools;
|
|
187
|
-
if (!pools || pools.length === 0) return true;
|
|
188
|
-
const eventPool = event.metadata?.["pool"];
|
|
189
|
-
return typeof eventPool === "string" && pools.includes(eventPool);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Mirror the `domain_events_tier_routing_check` DB CHECK at the memory
|
|
193
|
-
* backend (AUDIT-1). Audit-tier events MUST have null/undefined
|
|
194
|
-
* `pool` and `direction` in metadata; the bridge dispatcher relies on
|
|
195
|
-
* this invariant.
|
|
196
|
-
*/
|
|
197
|
-
assertTierRouting(event) {
|
|
198
|
-
const tier = event.metadata?.["tier"];
|
|
199
|
-
if (tier !== "audit") return;
|
|
200
|
-
const pool = event.metadata?.["pool"];
|
|
201
|
-
const direction = event.metadata?.["direction"];
|
|
202
|
-
const poolIsNull = pool === null || pool === void 0;
|
|
203
|
-
const directionIsNull = direction === null || direction === void 0;
|
|
204
|
-
if (!poolIsNull || !directionIsNull) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`MemoryEventBus: tier='audit' events must have null pool and direction (got pool=${String(pool)}, direction=${String(direction)}). This mirrors the domain_events CHECK constraint.`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
async dispatch(event) {
|
|
211
|
-
const set = this.handlers.get(event.type);
|
|
212
|
-
if (!set) return;
|
|
213
|
-
let firstError;
|
|
214
|
-
for (const handler of set) {
|
|
215
|
-
try {
|
|
216
|
-
await handler(event);
|
|
217
|
-
} catch (err) {
|
|
218
|
-
this.logger.error(
|
|
219
|
-
`Handler error for event type "${event.type}" (id: ${event.id}): ${err}`
|
|
220
|
-
);
|
|
221
|
-
if (firstError === void 0) {
|
|
222
|
-
firstError = err;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (firstError !== void 0) {
|
|
227
|
-
throw firstError;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
MemoryEventBus = __decorateClass([
|
|
232
|
-
Injectable(),
|
|
233
|
-
__decorateParam(0, Optional()),
|
|
234
|
-
__decorateParam(0, Inject(EVENTS_MODULE_OPTIONS))
|
|
235
|
-
], MemoryEventBus);
|
|
1
|
+
import {
|
|
2
|
+
MemoryEventBus
|
|
3
|
+
} from "../../../chunk-Z7PQCAVK.js";
|
|
4
|
+
import "../../../chunk-UQ5EHOH2.js";
|
|
5
|
+
import "../../../chunk-H5NH7KPE.js";
|
|
6
|
+
import "../../../chunk-GYGNEQSC.js";
|
|
7
|
+
import "../../../chunk-2E224ZSN.js";
|
|
236
8
|
export {
|
|
237
9
|
MemoryEventBus
|
|
238
10
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../runtime/subsystems/events/event-bus.memory-backend.ts","../../../../runtime/subsystems/events/event-keyset-cursor.ts","../../../../runtime/subsystems/token-key.ts","../../../../runtime/subsystems/events/events.tokens.ts"],"sourcesContent":["/**\n * MemoryEventBus — in-memory backend for the event bus.\n *\n * Dispatches events synchronously to registered subscribers. The `tx`\n * parameter is ignored — all events are dispatched immediately.\n *\n * Use this backend in tests to assert event publication without a database.\n * Swap via EventsModule.forRoot({ backend: 'memory' }).\n *\n * Pool awareness (EVT-5):\n * - Mirrors the `DrizzleEventBus` per-process restriction (EVT-4). When\n * `opts.pools` is set, `publish`/`publishMany` still push the event into\n * `publishedEvents` (so test code can assert the full set of emitted\n * events regardless of pool filter), but handlers are NOT invoked for\n * events whose `metadata.pool` is outside the configured pools.\n * - `publishedEventsForPool(pool)` and `publishedEventsForDirection(dir)`\n * helpers are provided for targeted assertions.\n * - Shares the `EventsModuleOptions` shape (same token as Drizzle) rather\n * than introducing a memory-only options type — the surface is the same\n * and keeping them unified avoids drift between backends.\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport type { DomainEvent, IEventBus } from './event-bus.protocol';\nimport type {\n EventPage,\n EventSummary,\n IEventReadPort,\n ListEventsQuery,\n} from './event-read.protocol';\nimport {\n clampEventLimit,\n decodeEventCursor,\n encodeEventCursor,\n} from './event-keyset-cursor';\nimport { EVENTS_MODULE_OPTIONS } from './events.tokens';\nimport type { EventsModuleOptions } from './events.module';\n\n/**\n * Project an in-memory `DomainEvent` into the narrow `EventSummary` shape.\n * The memory backend has no first-class columns, so `pool` / `direction` /\n * `tier` / `tenantId` / `rootRunId` are read from `metadata` (mirroring how\n * the Drizzle backend stamps them onto columns at publish time). `status`\n * is reported as `'processed'` — the memory bus dispatches synchronously,\n * so once an event is in `publishedEvents` it has been handled.\n */\nfunction toEventSummary(event: DomainEvent): EventSummary {\n const metadata = event.metadata;\n const str = (key: string): string | null => {\n const v = metadata?.[key];\n return typeof v === 'string' ? v : null;\n };\n return {\n id: event.id,\n type: event.type,\n aggregateId: event.aggregateId,\n aggregateType: event.aggregateType,\n status: 'processed',\n pool: str('pool'),\n direction: str('direction'),\n tier: str('tier') ?? 'domain',\n rootRunId: str('rootRunId'),\n tenantId: str('tenantId'),\n occurredAt: event.occurredAt,\n processedAt: event.occurredAt,\n };\n}\n\n@Injectable()\nexport class MemoryEventBus implements IEventBus, IEventReadPort {\n private readonly logger = new Logger(MemoryEventBus.name);\n\n /** All events published since construction (or last clear). */\n readonly publishedEvents: DomainEvent[] = [];\n\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n private readonly opts: EventsModuleOptions;\n\n constructor(\n @Optional() @Inject(EVENTS_MODULE_OPTIONS) opts?: EventsModuleOptions,\n ) {\n // Default so direct construction (e.g. `new MemoryEventBus()` from a\n // unit test outside NestJS DI) keeps working without an explicit\n // options object.\n this.opts = opts ?? { backend: 'memory' };\n }\n\n async publish(event: DomainEvent): Promise<void> {\n // Mirror the `domain_events_tier_routing_check` DB constraint at the\n // memory backend boundary so misuse fails the same way regardless of\n // backend (AUDIT-1).\n this.assertTierRouting(event);\n\n // Always record the event — even if this process is configured with a\n // pool filter that excludes it. Test code relies on `publishedEvents`\n // being a complete log of what was published, not a filtered view.\n this.publishedEvents.push(event);\n\n if (this.shouldDispatch(event)) {\n await this.dispatch(event);\n }\n }\n\n async publishMany(events: DomainEvent[]): Promise<void> {\n for (const event of events) {\n await this.publish(event);\n }\n }\n\n async findById(eventId: string): Promise<DomainEvent | null> {\n return this.publishedEvents.find((e) => e.id === eventId) ?? null;\n }\n\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n }\n // Cast is safe — callers pass a typed handler; we store as the base type\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n\n return () => {\n set.delete(h);\n };\n }\n\n // ============================================================================\n // IEventReadPort (OBS-LIST-1)\n // ============================================================================\n\n async listEvents(query: ListEventsQuery = {}): Promise<EventPage> {\n const limit = clampEventLimit(query.limit);\n const keyset = query.cursor ? decodeEventCursor(query.cursor) : null;\n\n const str = (e: DomainEvent, key: string): string | null => {\n const v = e.metadata?.[key];\n return typeof v === 'string' ? v : null;\n };\n\n const matched = this.publishedEvents.filter((e) => {\n if (query.poolId && str(e, 'pool') !== query.poolId) return false;\n if (query.direction && str(e, 'direction') !== query.direction)\n return false;\n if (query.rootRunId && str(e, 'rootRunId') !== query.rootRunId)\n return false;\n if (query.since && e.occurredAt.getTime() < query.since.getTime())\n return false;\n if (query.tenantId !== undefined) {\n const t = str(e, 'tenantId');\n if (query.tenantId === null) {\n if (t !== null) return false;\n } else if (t !== query.tenantId) {\n return false;\n }\n }\n return true;\n });\n\n // Order occurred_at DESC, id DESC to match the Drizzle backend keyset.\n matched.sort((a, b) => {\n const dt = b.occurredAt.getTime() - a.occurredAt.getTime();\n if (dt !== 0) return dt;\n return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;\n });\n\n const seeked = keyset\n ? matched.filter((e) => {\n const ct = e.occurredAt.getTime();\n const kt = keyset.occurredAt.getTime();\n if (ct < kt) return true;\n if (ct > kt) return false;\n return e.id < keyset.id;\n })\n : matched;\n\n const hasMore = seeked.length > limit;\n const page = hasMore ? seeked.slice(0, limit) : seeked;\n const items = page.map(toEventSummary);\n const last = page[page.length - 1];\n const nextCursor =\n hasMore && last\n ? encodeEventCursor({ occurredAt: last.occurredAt, id: last.id })\n : null;\n\n return { items, nextCursor };\n }\n\n /** Remove all published events and subscriptions. Useful in beforeEach. */\n clear(): void {\n this.publishedEvents.length = 0;\n this.handlers.clear();\n }\n\n /** Filter published events by `metadata.pool`. */\n publishedEventsForPool(pool: string): DomainEvent[] {\n return this.publishedEvents.filter((e) => e.metadata?.['pool'] === pool);\n }\n\n /** Filter published events by `metadata.direction`. */\n publishedEventsForDirection(direction: string): DomainEvent[] {\n return this.publishedEvents.filter((e) => e.metadata?.['direction'] === direction);\n }\n\n /**\n * Decide whether `event` should be dispatched to handlers given the\n * current pool filter.\n *\n * Semantics (mirroring `DrizzleEventBus.processBatch`):\n * - `opts.pools` undefined → dispatch everything (no filter).\n * - `opts.pools` empty array → treated as \"no filter\" to match the\n * Drizzle backend, where `pools && pools.length > 0` is the gate on\n * the `inArray` WHERE clause. Empty arrays dispatch everything.\n * - `opts.pools` non-empty → dispatch only when `event.metadata.pool`\n * is in the list. Events without `metadata.pool` do NOT match — they\n * are out of all configured pools by definition.\n */\n private shouldDispatch(event: DomainEvent): boolean {\n const pools = this.opts.pools;\n if (!pools || pools.length === 0) return true;\n const eventPool = event.metadata?.['pool'];\n return typeof eventPool === 'string' && pools.includes(eventPool);\n }\n\n /**\n * Mirror the `domain_events_tier_routing_check` DB CHECK at the memory\n * backend (AUDIT-1). Audit-tier events MUST have null/undefined\n * `pool` and `direction` in metadata; the bridge dispatcher relies on\n * this invariant.\n */\n private assertTierRouting(event: DomainEvent): void {\n const tier = event.metadata?.['tier'];\n if (tier !== 'audit') return;\n const pool = event.metadata?.['pool'];\n const direction = event.metadata?.['direction'];\n const poolIsNull = pool === null || pool === undefined;\n const directionIsNull = direction === null || direction === undefined;\n if (!poolIsNull || !directionIsNull) {\n throw new Error(\n `MemoryEventBus: tier='audit' events must have null pool and direction ` +\n `(got pool=${String(pool)}, direction=${String(direction)}). ` +\n `This mirrors the domain_events CHECK constraint.`,\n );\n }\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n\n let firstError: unknown;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n if (firstError === undefined) {\n firstError = err;\n }\n }\n }\n\n if (firstError !== undefined) {\n throw firstError;\n }\n }\n}\n","/**\n * Keyset (seek) cursor codec for `IEventReadPort.listEvents` (OBS-LIST-1).\n *\n * The list is ordered `occurred_at DESC, id DESC`. The cursor encodes the\n * `(occurredAt, id)` of the last row on the previous page so the next page\n * seeks with `WHERE (occurred_at, id) < (cursorOccurredAt, cursorId)`.\n *\n * The cursor is opaque to consumers: a base64url-encoded JSON tuple. Shape\n * is an implementation detail — never parse it outside this module.\n *\n * Mirrors the jobs keyset codec; kept separate because the events subsystem\n * must not depend on `runtime/subsystems/jobs/`.\n */\n\nexport interface EventKeyset {\n occurredAt: Date;\n id: string;\n}\n\n/** Default page size when `limit` is omitted. */\nexport const DEFAULT_EVENT_LIST_LIMIT = 50;\n/** Hard upper bound on page size. */\nexport const MAX_EVENT_LIST_LIMIT = 200;\n\n/** Clamp a caller-supplied `limit` into `[1, MAX_EVENT_LIST_LIMIT]`. */\nexport function clampEventLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit)) {\n return DEFAULT_EVENT_LIST_LIMIT;\n }\n const floored = Math.floor(limit);\n if (floored < 1) return 1;\n if (floored > MAX_EVENT_LIST_LIMIT) return MAX_EVENT_LIST_LIMIT;\n return floored;\n}\n\nexport function encodeEventCursor(keyset: EventKeyset): string {\n const tuple = [keyset.occurredAt.toISOString(), keyset.id];\n return Buffer.from(JSON.stringify(tuple), 'utf8').toString('base64url');\n}\n\n/**\n * Decode an opaque cursor back into its `(occurredAt, id)` keyset. Returns\n * `null` for malformed input so user-supplied garbage is treated as \"start\n * from the beginning\" rather than throwing.\n */\nexport function decodeEventCursor(cursor: string): EventKeyset | null {\n try {\n const json = Buffer.from(cursor, 'base64url').toString('utf8');\n const parsed = JSON.parse(json) as unknown;\n if (!Array.isArray(parsed) || parsed.length !== 2) return null;\n const [iso, id] = parsed;\n if (typeof iso !== 'string' || typeof id !== 'string') return null;\n const occurredAt = new Date(iso);\n if (Number.isNaN(occurredAt.getTime())) return null;\n return { occurredAt, id };\n } catch {\n return null;\n }\n}\n","/** Canonical package namespace for cross-boundary DI token keys. MUST be a hardcoded\n * constant (NOT derived from package.json) so a vendored copy — which lives inside the\n * CONSUMER's package — produces the identical key and the two copies share the symbol. */\nexport const PKG = '@pattern-stack/codegen';\n// TODO(token-version): if/when a runtime contract version is adopted, inject it HERE only\n// (e.g. `${PKG}#${ABI}.${area}.${name}`) — this helper is the single chokepoint.\nexport const tokenKey = (area: string, name: string): string => `${PKG}.${area}.${name}`;\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nimport { tokenKey } from '../token-key';\n\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the read-side `IEventReadPort` over `domain_events`\n * (OBS-LIST-1).\n *\n * Bound by `EventsModule.forRoot` to the same backend instance as\n * `EVENT_BUS` for the `drizzle` and `memory` backends (both implement\n * `IEventReadPort`). The `redis` backend retains no history and therefore\n * does NOT provide this token — consumers composing it (e.g. the\n * observability combiner) inject it `@Optional()` and degrade to empty\n * results.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENT_READ_PORT = 'EVENT_READ_PORT' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n *\n * ADR-037: namespaced `Symbol.for(...)` (via `tokenKey()`) so it matches by value\n * across runtime copies (the sibling string tokens above are already value-stable).\n * Note the jobs subsystem defines its own `REDIS_URL`-equivalent; this is the\n * events one.\n */\nexport const REDIS_URL = Symbol.for(tokenKey('events', 'redis-url'));\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return result;
|
|
10
|
-
};
|
|
11
|
-
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
1
|
+
import {
|
|
2
|
+
REDIS_URL
|
|
3
|
+
} from "../../../chunk-H5NH7KPE.js";
|
|
4
|
+
import "../../../chunk-GYGNEQSC.js";
|
|
5
|
+
import {
|
|
6
|
+
__decorateClass,
|
|
7
|
+
__decorateParam
|
|
8
|
+
} from "../../../chunk-2E224ZSN.js";
|
|
12
9
|
|
|
13
10
|
// runtime/subsystems/events/event-bus.redis-backend.ts
|
|
14
11
|
import { Injectable, Inject, Logger } from "@nestjs/common";
|
|
15
|
-
|
|
16
|
-
// runtime/subsystems/token-key.ts
|
|
17
|
-
var PKG = "@pattern-stack/codegen";
|
|
18
|
-
var tokenKey = (area, name) => `${PKG}.${area}.${name}`;
|
|
19
|
-
|
|
20
|
-
// runtime/subsystems/events/events.tokens.ts
|
|
21
|
-
var REDIS_URL = Symbol.for(tokenKey("events", "redis-url"));
|
|
22
|
-
|
|
23
|
-
// runtime/subsystems/events/event-bus.redis-backend.ts
|
|
24
12
|
var CHANNEL_PREFIX = "events:";
|
|
25
13
|
async function createRedisClient(url) {
|
|
26
14
|
let Redis;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../runtime/subsystems/events/event-bus.redis-backend.ts","../../../../runtime/subsystems/token-key.ts","../../../../runtime/subsystems/events/events.tokens.ts"],"sourcesContent":["/**\n * RedisEventBus — Redis Pub/Sub backend for the event bus.\n *\n * Publishes events to Redis channels and dispatches incoming messages to\n * registered in-process subscribers. Events are serialized as JSON strings.\n *\n * Channel naming:\n * - Per-type channel: events:{event.type} (e.g. events:contact_created)\n * - Catch-all channel: events:*\n *\n * Transactional semantics:\n * The `tx` parameter (Drizzle transaction) is accepted to satisfy the\n * IEventBus interface but has no effect — Redis Pub/Sub is not transactional.\n * Events published with a `tx` argument are dispatched immediately without\n * waiting for the surrounding transaction to commit. If you need\n * at-least-once delivery tied to a database transaction, use DrizzleEventBus.\n *\n * Connection model:\n * ioredis requires a dedicated connection for subscribers (a client in\n * subscribe mode cannot issue regular commands). This backend creates two\n * clients: one for publishing (`publisher`) and one for subscribing\n * (`subscriber`). Both are connected on module init and disconnected on\n * module destroy.\n *\n * Usage:\n * EventsModule.forRoot({ backend: 'redis', redisUrl: 'redis://localhost:6379' })\n *\n * Requires `ioredis` — install it separately if you use this backend:\n * npm install ioredis / bun add ioredis\n */\nimport { Injectable, OnModuleInit, OnModuleDestroy, Inject, Logger } from '@nestjs/common';\nimport type { DomainEvent, DrizzleTransaction, IEventBus } from './event-bus.protocol';\nimport { REDIS_URL } from './events.tokens';\n\n/** Redis channel prefix for all domain events. */\nconst CHANNEL_PREFIX = 'events:';\n/** Catch-all channel that receives every published event. */\nconst WILDCARD_CHANNEL = 'events:*';\n\n// ioredis is an optional peer dependency; import lazily so consumers who do\n// not use this backend do not need it on their classpath.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RedisClient = any;\n\nasync function createRedisClient(url: string): Promise<RedisClient> {\n let Redis: { new (url: string): RedisClient };\n try {\n const mod = await import('ioredis');\n Redis = mod.default ?? mod;\n } catch {\n throw new Error(\n 'RedisEventBus requires the \"ioredis\" package. Install it with: npm install ioredis',\n );\n }\n return new Redis(url);\n}\n\n@Injectable()\nexport class RedisEventBus implements IEventBus, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisEventBus.name);\n\n private publisher: RedisClient | null = null;\n private subscriber: RedisClient | null = null;\n private connected = false;\n\n /**\n * In-process subscriber registry. Handlers registered here are called when\n * a message arrives on the subscriber client — keeping fan-out within the\n * same process without an extra round-trip through Redis.\n */\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n\n /**\n * Track which event types have active Redis subscriptions.\n * Used to avoid subscribing multiple times to the same type channel.\n */\n private readonly subscribedTypes = new Set<string>();\n\n constructor(@Inject(REDIS_URL) private readonly redisUrl: string) {}\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n async onModuleInit(): Promise<void> {\n this.publisher = await createRedisClient(this.redisUrl);\n this.subscriber = await createRedisClient(this.redisUrl);\n\n // Surface connection errors without crashing the process.\n this.publisher.on('error', (err: Error) =>\n this.logger.error(`Redis publisher error: ${err.message}`, err.stack),\n );\n this.subscriber.on('error', (err: Error) =>\n this.logger.error(`Redis subscriber error: ${err.message}`, err.stack),\n );\n\n // Set up message listener for per-type subscriptions.\n // Subscriptions are created lazily when the first handler is registered for a type.\n this.subscriber.on('message', (channel: string, message: string) => {\n void this.handleMessage(channel, message);\n });\n\n this.connected = true;\n this.logger.log(`RedisEventBus connected to ${this.redisUrl}`);\n }\n\n async onModuleDestroy(): Promise<void> {\n this.connected = false;\n\n if (this.subscriber) {\n // Unsubscribe from all channels and disconnect the subscriber.\n // unsubscribe() with no args unsubscribes from all channels.\n await this.subscriber.unsubscribe();\n this.subscriber.disconnect();\n this.subscriber = null;\n }\n\n if (this.publisher) {\n this.publisher.disconnect();\n this.publisher = null;\n }\n\n this.subscribedTypes.clear();\n this.logger.log('RedisEventBus disconnected');\n }\n\n // ============================================================================\n // IEventBus\n // ============================================================================\n\n /**\n * Publish a single event.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publish(event: DomainEvent, tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n this.assertConnected();\n\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n\n await this.publisher!.publish(channel, payload);\n }\n\n /**\n * Publish multiple events using a pipeline so all PUBLISH commands are sent\n * in a single round-trip.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publishMany(events: DomainEvent[], tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n if (events.length === 0) return;\n this.assertConnected();\n\n const pipeline = this.publisher!.pipeline();\n for (const event of events) {\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n pipeline.publish(channel, payload);\n }\n await pipeline.exec();\n }\n\n /**\n * Register a handler for a specific event type.\n * Returns an unsubscribe function — call it to remove the handler.\n *\n * On first handler for a type, subscribes to the per-type Redis channel.\n * On removal of the last handler for a type, unsubscribes from the channel.\n */\n /**\n * Lookup by id is unsupported on the Redis Pub/Sub backend — Pub/Sub\n * does not retain history. Always returns `null`. Logs a warning the\n * first time it's called so a misconfiguration surfaces visibly. Using\n * the bridge with the Redis backend is unsupported (the bridge requires\n * a durable event store).\n */\n private warnedFindById = false;\n async findById(_eventId: string): Promise<DomainEvent | null> {\n if (!this.warnedFindById) {\n this.warnedFindById = true;\n this.logger.warn(\n 'RedisEventBus.findById is unsupported (Pub/Sub has no history). ' +\n 'The bridge subsystem requires a durable event store; switch to ' +\n 'DrizzleEventBus if you need bridge fanout.',\n );\n }\n return null;\n }\n\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n // First handler for this type — subscribe to the per-type channel in Redis.\n void this.subscribeToType(eventType);\n }\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n\n return () => {\n set.delete(h);\n // If no more handlers for this type, unsubscribe from the Redis channel.\n if (set.size === 0) {\n this.handlers.delete(eventType);\n void this.unsubscribeFromType(eventType);\n }\n };\n }\n\n // ============================================================================\n // Internal helpers\n // ============================================================================\n\n private assertConnected(): void {\n if (!this.connected || !this.publisher) {\n throw new Error(\n 'RedisEventBus is not connected. Ensure the module has been initialised before publishing.',\n );\n }\n }\n\n private serialize(event: DomainEvent): string {\n return JSON.stringify({\n ...event,\n occurredAt: event.occurredAt.toISOString(),\n });\n }\n\n private deserialize(raw: string): DomainEvent {\n const parsed = JSON.parse(raw) as DomainEvent & { occurredAt: string };\n return {\n ...parsed,\n occurredAt: new Date(parsed.occurredAt),\n };\n }\n\n private async handleMessage(channel: string, message: string): Promise<void> {\n let event: DomainEvent;\n try {\n event = this.deserialize(message);\n } catch (err) {\n this.logger.warn(`Failed to deserialize event on channel \"${channel}\": ${err}`);\n return;\n }\n\n await this.dispatch(event);\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n }\n }\n }\n\n /**\n * Subscribe to a per-type Redis channel.\n * Called lazily when the first handler is registered for a type.\n */\n private async subscribeToType(eventType: string): Promise<void> {\n if (this.subscribedTypes.has(eventType)) {\n return; // Already subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.subscribe(channel);\n this.subscribedTypes.add(eventType);\n } catch (err) {\n this.logger.error(`Failed to subscribe to channel \"${channel}\": ${err}`);\n }\n }\n\n /**\n * Unsubscribe from a per-type Redis channel.\n * Called when the last handler for a type is removed.\n */\n private async unsubscribeFromType(eventType: string): Promise<void> {\n if (!this.subscribedTypes.has(eventType)) {\n return; // Not subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.unsubscribe(channel);\n this.subscribedTypes.delete(eventType);\n } catch (err) {\n this.logger.error(`Failed to unsubscribe from channel \"${channel}\": ${err}`);\n }\n }\n}\n","/** Canonical package namespace for cross-boundary DI token keys. MUST be a hardcoded\n * constant (NOT derived from package.json) so a vendored copy — which lives inside the\n * CONSUMER's package — produces the identical key and the two copies share the symbol. */\nexport const PKG = '@pattern-stack/codegen';\n// TODO(token-version): if/when a runtime contract version is adopted, inject it HERE only\n// (e.g. `${PKG}#${ABI}.${area}.${name}`) — this helper is the single chokepoint.\nexport const tokenKey = (area: string, name: string): string => `${PKG}.${area}.${name}`;\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nimport { tokenKey } from '../token-key';\n\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the read-side `IEventReadPort` over `domain_events`\n * (OBS-LIST-1).\n *\n * Bound by `EventsModule.forRoot` to the same backend instance as\n * `EVENT_BUS` for the `drizzle` and `memory` backends (both implement\n * `IEventReadPort`). The `redis` backend retains no history and therefore\n * does NOT provide this token — consumers composing it (e.g. the\n * observability combiner) inject it `@Optional()` and degrade to empty\n * results.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENT_READ_PORT = 'EVENT_READ_PORT' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n *\n * ADR-037: namespaced `Symbol.for(...)` (via `tokenKey()`) so it matches by value\n * across runtime copies (the sibling string tokens above are already value-stable).\n * Note the jobs subsystem defines its own `REDIS_URL`-equivalent; this is the\n * events one.\n */\nexport const REDIS_URL = Symbol.for(tokenKey('events', 'redis-url'));\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../runtime/subsystems/events/event-bus.redis-backend.ts"],"sourcesContent":["/**\n * RedisEventBus — Redis Pub/Sub backend for the event bus.\n *\n * Publishes events to Redis channels and dispatches incoming messages to\n * registered in-process subscribers. Events are serialized as JSON strings.\n *\n * Channel naming:\n * - Per-type channel: events:{event.type} (e.g. events:contact_created)\n * - Catch-all channel: events:*\n *\n * Transactional semantics:\n * The `tx` parameter (Drizzle transaction) is accepted to satisfy the\n * IEventBus interface but has no effect — Redis Pub/Sub is not transactional.\n * Events published with a `tx` argument are dispatched immediately without\n * waiting for the surrounding transaction to commit. If you need\n * at-least-once delivery tied to a database transaction, use DrizzleEventBus.\n *\n * Connection model:\n * ioredis requires a dedicated connection for subscribers (a client in\n * subscribe mode cannot issue regular commands). This backend creates two\n * clients: one for publishing (`publisher`) and one for subscribing\n * (`subscriber`). Both are connected on module init and disconnected on\n * module destroy.\n *\n * Usage:\n * EventsModule.forRoot({ backend: 'redis', redisUrl: 'redis://localhost:6379' })\n *\n * Requires `ioredis` — install it separately if you use this backend:\n * npm install ioredis / bun add ioredis\n */\nimport { Injectable, OnModuleInit, OnModuleDestroy, Inject, Logger } from '@nestjs/common';\nimport type { DomainEvent, DrizzleTransaction, IEventBus } from './event-bus.protocol';\nimport { REDIS_URL } from './events.tokens';\n\n/** Redis channel prefix for all domain events. */\nconst CHANNEL_PREFIX = 'events:';\n/** Catch-all channel that receives every published event. */\nconst WILDCARD_CHANNEL = 'events:*';\n\n// ioredis is an optional peer dependency; import lazily so consumers who do\n// not use this backend do not need it on their classpath.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype RedisClient = any;\n\nasync function createRedisClient(url: string): Promise<RedisClient> {\n let Redis: { new (url: string): RedisClient };\n try {\n const mod = await import('ioredis');\n Redis = mod.default ?? mod;\n } catch {\n throw new Error(\n 'RedisEventBus requires the \"ioredis\" package. Install it with: npm install ioredis',\n );\n }\n return new Redis(url);\n}\n\n@Injectable()\nexport class RedisEventBus implements IEventBus, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisEventBus.name);\n\n private publisher: RedisClient | null = null;\n private subscriber: RedisClient | null = null;\n private connected = false;\n\n /**\n * In-process subscriber registry. Handlers registered here are called when\n * a message arrives on the subscriber client — keeping fan-out within the\n * same process without an extra round-trip through Redis.\n */\n private readonly handlers = new Map<string, Set<(event: DomainEvent) => Promise<void>>>();\n\n /**\n * Track which event types have active Redis subscriptions.\n * Used to avoid subscribing multiple times to the same type channel.\n */\n private readonly subscribedTypes = new Set<string>();\n\n constructor(@Inject(REDIS_URL) private readonly redisUrl: string) {}\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n async onModuleInit(): Promise<void> {\n this.publisher = await createRedisClient(this.redisUrl);\n this.subscriber = await createRedisClient(this.redisUrl);\n\n // Surface connection errors without crashing the process.\n this.publisher.on('error', (err: Error) =>\n this.logger.error(`Redis publisher error: ${err.message}`, err.stack),\n );\n this.subscriber.on('error', (err: Error) =>\n this.logger.error(`Redis subscriber error: ${err.message}`, err.stack),\n );\n\n // Set up message listener for per-type subscriptions.\n // Subscriptions are created lazily when the first handler is registered for a type.\n this.subscriber.on('message', (channel: string, message: string) => {\n void this.handleMessage(channel, message);\n });\n\n this.connected = true;\n this.logger.log(`RedisEventBus connected to ${this.redisUrl}`);\n }\n\n async onModuleDestroy(): Promise<void> {\n this.connected = false;\n\n if (this.subscriber) {\n // Unsubscribe from all channels and disconnect the subscriber.\n // unsubscribe() with no args unsubscribes from all channels.\n await this.subscriber.unsubscribe();\n this.subscriber.disconnect();\n this.subscriber = null;\n }\n\n if (this.publisher) {\n this.publisher.disconnect();\n this.publisher = null;\n }\n\n this.subscribedTypes.clear();\n this.logger.log('RedisEventBus disconnected');\n }\n\n // ============================================================================\n // IEventBus\n // ============================================================================\n\n /**\n * Publish a single event.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publish(event: DomainEvent, tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n this.assertConnected();\n\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n\n await this.publisher!.publish(channel, payload);\n }\n\n /**\n * Publish multiple events using a pipeline so all PUBLISH commands are sent\n * in a single round-trip.\n *\n * `tx` is accepted but ignored — see module-level JSDoc for details.\n */\n async publishMany(events: DomainEvent[], tx?: DrizzleTransaction): Promise<void> {\n void tx; // intentionally unused — Redis Pub/Sub is not transactional\n if (events.length === 0) return;\n this.assertConnected();\n\n const pipeline = this.publisher!.pipeline();\n for (const event of events) {\n const payload = this.serialize(event);\n const channel = `${CHANNEL_PREFIX}${event.type}`;\n pipeline.publish(channel, payload);\n }\n await pipeline.exec();\n }\n\n /**\n * Register a handler for a specific event type.\n * Returns an unsubscribe function — call it to remove the handler.\n *\n * On first handler for a type, subscribes to the per-type Redis channel.\n * On removal of the last handler for a type, unsubscribes from the channel.\n */\n /**\n * Lookup by id is unsupported on the Redis Pub/Sub backend — Pub/Sub\n * does not retain history. Always returns `null`. Logs a warning the\n * first time it's called so a misconfiguration surfaces visibly. Using\n * the bridge with the Redis backend is unsupported (the bridge requires\n * a durable event store).\n */\n private warnedFindById = false;\n async findById(_eventId: string): Promise<DomainEvent | null> {\n if (!this.warnedFindById) {\n this.warnedFindById = true;\n this.logger.warn(\n 'RedisEventBus.findById is unsupported (Pub/Sub has no history). ' +\n 'The bridge subsystem requires a durable event store; switch to ' +\n 'DrizzleEventBus if you need bridge fanout.',\n );\n }\n return null;\n }\n\n subscribe<T extends DomainEvent = DomainEvent>(\n eventType: string,\n handler: (event: T) => Promise<void>,\n ): () => void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n // First handler for this type — subscribe to the per-type channel in Redis.\n void this.subscribeToType(eventType);\n }\n const set = this.handlers.get(eventType)!;\n const h = handler as (event: DomainEvent) => Promise<void>;\n set.add(h);\n\n return () => {\n set.delete(h);\n // If no more handlers for this type, unsubscribe from the Redis channel.\n if (set.size === 0) {\n this.handlers.delete(eventType);\n void this.unsubscribeFromType(eventType);\n }\n };\n }\n\n // ============================================================================\n // Internal helpers\n // ============================================================================\n\n private assertConnected(): void {\n if (!this.connected || !this.publisher) {\n throw new Error(\n 'RedisEventBus is not connected. Ensure the module has been initialised before publishing.',\n );\n }\n }\n\n private serialize(event: DomainEvent): string {\n return JSON.stringify({\n ...event,\n occurredAt: event.occurredAt.toISOString(),\n });\n }\n\n private deserialize(raw: string): DomainEvent {\n const parsed = JSON.parse(raw) as DomainEvent & { occurredAt: string };\n return {\n ...parsed,\n occurredAt: new Date(parsed.occurredAt),\n };\n }\n\n private async handleMessage(channel: string, message: string): Promise<void> {\n let event: DomainEvent;\n try {\n event = this.deserialize(message);\n } catch (err) {\n this.logger.warn(`Failed to deserialize event on channel \"${channel}\": ${err}`);\n return;\n }\n\n await this.dispatch(event);\n }\n\n private async dispatch(event: DomainEvent): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n for (const handler of set) {\n try {\n await handler(event);\n } catch (err) {\n this.logger.error(\n `Handler error for event type \"${event.type}\" (id: ${event.id}): ${err}`,\n );\n }\n }\n }\n\n /**\n * Subscribe to a per-type Redis channel.\n * Called lazily when the first handler is registered for a type.\n */\n private async subscribeToType(eventType: string): Promise<void> {\n if (this.subscribedTypes.has(eventType)) {\n return; // Already subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.subscribe(channel);\n this.subscribedTypes.add(eventType);\n } catch (err) {\n this.logger.error(`Failed to subscribe to channel \"${channel}\": ${err}`);\n }\n }\n\n /**\n * Unsubscribe from a per-type Redis channel.\n * Called when the last handler for a type is removed.\n */\n private async unsubscribeFromType(eventType: string): Promise<void> {\n if (!this.subscribedTypes.has(eventType)) {\n return; // Not subscribed to this type.\n }\n\n const channel = `${CHANNEL_PREFIX}${eventType}`;\n try {\n await this.subscriber!.unsubscribe(channel);\n this.subscribedTypes.delete(eventType);\n } catch (err) {\n this.logger.error(`Failed to unsubscribe from channel \"${channel}\": ${err}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,33 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (floored < 1) return 1;
|
|
10
|
-
if (floored > MAX_EVENT_LIST_LIMIT) return MAX_EVENT_LIST_LIMIT;
|
|
11
|
-
return floored;
|
|
12
|
-
}
|
|
13
|
-
function encodeEventCursor(keyset) {
|
|
14
|
-
const tuple = [keyset.occurredAt.toISOString(), keyset.id];
|
|
15
|
-
return Buffer.from(JSON.stringify(tuple), "utf8").toString("base64url");
|
|
16
|
-
}
|
|
17
|
-
function decodeEventCursor(cursor) {
|
|
18
|
-
try {
|
|
19
|
-
const json = Buffer.from(cursor, "base64url").toString("utf8");
|
|
20
|
-
const parsed = JSON.parse(json);
|
|
21
|
-
if (!Array.isArray(parsed) || parsed.length !== 2) return null;
|
|
22
|
-
const [iso, id] = parsed;
|
|
23
|
-
if (typeof iso !== "string" || typeof id !== "string") return null;
|
|
24
|
-
const occurredAt = new Date(iso);
|
|
25
|
-
if (Number.isNaN(occurredAt.getTime())) return null;
|
|
26
|
-
return { occurredAt, id };
|
|
27
|
-
} catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_EVENT_LIST_LIMIT,
|
|
3
|
+
MAX_EVENT_LIST_LIMIT,
|
|
4
|
+
clampEventLimit,
|
|
5
|
+
decodeEventCursor,
|
|
6
|
+
encodeEventCursor
|
|
7
|
+
} from "../../../chunk-UQ5EHOH2.js";
|
|
8
|
+
import "../../../chunk-2E224ZSN.js";
|
|
31
9
|
export {
|
|
32
10
|
DEFAULT_EVENT_LIST_LIMIT,
|
|
33
11
|
MAX_EVENT_LIST_LIMIT,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../runtime/subsystems/events/event-read.protocol.ts"],"sourcesContent":["/**\n * IEventReadPort — read-side port over `domain_events` (OBS-LIST-1).\n *\n * The publish/subscribe `IEventBus` (EVENT_BUS) is a *write + dispatch*\n * port; it deliberately does not expose tabular reads beyond `findById`.\n * The observability combiner needs a paginated, filterable list of\n * `domain_events` for its events viewer, so we add a dedicated read port\n * rather than overloading `IEventBus`.\n *\n * Keeping reads on a separate port means:\n * - the combiner can compose it `@Optional()` independently of EVENT_BUS;\n * - the Redis backend (which retains no history) simply does not provide\n * it — there is no \"list\" semantics to fake;\n * - the write/dispatch surface stays minimal.\n *\n * Both `DrizzleEventBus` and `MemoryEventBus` implement this port (they\n * already hold the rows / in-memory log); `EventsModule.forRoot` binds the\n * `EVENT_READ_PORT` token to the same instance for drizzle/memory backends.\n */\n\nimport type { DomainEvent } from './event-bus.protocol';\n\n/**\n * Filter + keyset-pagination input for `IEventReadPort.listEvents`.\n *\n * Ordered `occurred_at DESC, id DESC`. `rootRunId` filters on the JSON\n * `metadata->>'rootRunId'` — the correlation id stamped by the jobs/bridge\n * machinery so an event can be traced back to the run tree that emitted it.\n */\nexport interface ListEventsQuery {\n /** Filter on `metadata->>'rootRunId'` (correlation id). */\n rootRunId?: string;\n /** Filter on the first-class `pool` column. */\n poolId?: string;\n /** Filter on the first-class `direction` column (inbound|change|outbound). */\n direction?: string;\n /** Lower bound on `occurred_at` (inclusive). */\n since?: Date;\n /** Opaque keyset cursor from a previous page's `nextCursor`. */\n cursor?: string;\n /** Page size. Backend clamps to a sane default + max. */\n limit?: number;\n /**\n * Multi-tenancy filter on the first-class `tenant_id` column. Only\n * meaningful when the consumer publishes tenant-scoped events\n * (`events.multi_tenant: true`); otherwise leave undefined.\n * - `string` — filter `tenant_id = :tenantId`.\n * - `null` — filter `tenant_id IS NULL`.\n * - `undefined` — no tenant filter.\n */\n tenantId?: string | null;\n}\n\n/**\n * Summary row for the events list. A narrow projection over `domain_events`\n * carrying what the viewer + correlation timeline need. `rootRunId` is\n * surfaced (lifted out of `metadata`) so the timeline can stitch without a\n * second metadata dig.\n */\nexport interface EventSummary {\n id: string;\n type: string;\n aggregateId: string;\n aggregateType: string;\n status: string;\n pool: string | null;\n direction: string | null;\n tier: string;\n rootRunId: string | null;\n tenantId: string | null;\n occurredAt: Date;\n processedAt: Date | null;\n}\n\n/**\n * One page of `listEvents` results. `nextCursor` is `null` when there are\n * no more rows.\n */\nexport interface EventPage {\n items: EventSummary[];\n nextCursor: string | null;\n}\n\nexport interface IEventReadPort {\n /**\n * Paginated, filterable list of `domain_events` (OBS-LIST-1). Newest\n * first (`occurred_at` desc, `id` desc keyset tie-break). Returns an\n * `EventPage` with an opaque `nextCursor` for keyset pagination.\n */\n listEvents(query?: ListEventsQuery): Promise<EventPage>;\n}\n\n/** A `DomainEvent` whose metadata may carry a `rootRunId` correlation id. */\nexport function rootRunIdOf(event: DomainEvent): string | null {\n const v = event.metadata?.['rootRunId'];\n return typeof v === 'string' ? v : null;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../../runtime/subsystems/events/event-read.protocol.ts"],"sourcesContent":["/**\n * IEventReadPort — read-side port over `domain_events` (OBS-LIST-1).\n *\n * The publish/subscribe `IEventBus` (EVENT_BUS) is a *write + dispatch*\n * port; it deliberately does not expose tabular reads beyond `findById`.\n * The observability combiner needs a paginated, filterable list of\n * `domain_events` for its events viewer, so we add a dedicated read port\n * rather than overloading `IEventBus`.\n *\n * Keeping reads on a separate port means:\n * - the combiner can compose it `@Optional()` independently of EVENT_BUS;\n * - the Redis backend (which retains no history) simply does not provide\n * it — there is no \"list\" semantics to fake;\n * - the write/dispatch surface stays minimal.\n *\n * Both `DrizzleEventBus` and `MemoryEventBus` implement this port (they\n * already hold the rows / in-memory log); `EventsModule.forRoot` binds the\n * `EVENT_READ_PORT` token to the same instance for drizzle/memory backends.\n */\n\nimport type { DomainEvent } from './event-bus.protocol';\n\n/**\n * Filter + keyset-pagination input for `IEventReadPort.listEvents`.\n *\n * Ordered `occurred_at DESC, id DESC`. `rootRunId` filters on the JSON\n * `metadata->>'rootRunId'` — the correlation id stamped by the jobs/bridge\n * machinery so an event can be traced back to the run tree that emitted it.\n */\nexport interface ListEventsQuery {\n /** Filter on `metadata->>'rootRunId'` (correlation id). */\n rootRunId?: string;\n /** Filter on the first-class `pool` column. */\n poolId?: string;\n /** Filter on the first-class `direction` column (inbound|change|outbound). */\n direction?: string;\n /** Lower bound on `occurred_at` (inclusive). */\n since?: Date;\n /** Opaque keyset cursor from a previous page's `nextCursor`. */\n cursor?: string;\n /** Page size. Backend clamps to a sane default + max. */\n limit?: number;\n /**\n * Multi-tenancy filter on the first-class `tenant_id` column. Only\n * meaningful when the consumer publishes tenant-scoped events\n * (`events.multi_tenant: true`); otherwise leave undefined.\n * - `string` — filter `tenant_id = :tenantId`.\n * - `null` — filter `tenant_id IS NULL`.\n * - `undefined` — no tenant filter.\n */\n tenantId?: string | null;\n}\n\n/**\n * Summary row for the events list. A narrow projection over `domain_events`\n * carrying what the viewer + correlation timeline need. `rootRunId` is\n * surfaced (lifted out of `metadata`) so the timeline can stitch without a\n * second metadata dig.\n */\nexport interface EventSummary {\n id: string;\n type: string;\n aggregateId: string;\n aggregateType: string;\n status: string;\n pool: string | null;\n direction: string | null;\n tier: string;\n rootRunId: string | null;\n tenantId: string | null;\n occurredAt: Date;\n processedAt: Date | null;\n}\n\n/**\n * One page of `listEvents` results. `nextCursor` is `null` when there are\n * no more rows.\n */\nexport interface EventPage {\n items: EventSummary[];\n nextCursor: string | null;\n}\n\nexport interface IEventReadPort {\n /**\n * Paginated, filterable list of `domain_events` (OBS-LIST-1). Newest\n * first (`occurred_at` desc, `id` desc keyset tie-break). Returns an\n * `EventPage` with an opaque `nextCursor` for keyset pagination.\n */\n listEvents(query?: ListEventsQuery): Promise<EventPage>;\n}\n\n/** A `DomainEvent` whose metadata may carry a `rootRunId` correlation id. */\nexport function rootRunIdOf(event: DomainEvent): string | null {\n const v = event.metadata?.['rootRunId'];\n return typeof v === 'string' ? v : null;\n}\n"],"mappings":";;;AA6FO,SAAS,YAAY,OAAmC;AAC7D,QAAM,IAAI,MAAM,WAAW,WAAW;AACtC,SAAO,OAAO,MAAM,WAAW,IAAI;AACrC;","names":[]}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
`Missing tenantId for event '${eventType}'. EventsModule is configured with multiTenant: true \u2014 every publish must include opts.metadata.tenantId. Either pass the tenantId or disable multi-tenancy on the module.`
|
|
6
|
-
);
|
|
7
|
-
this.eventType = eventType;
|
|
8
|
-
}
|
|
9
|
-
eventType;
|
|
10
|
-
name = "MissingTenantIdError";
|
|
11
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
MissingTenantIdError
|
|
3
|
+
} from "../../../chunk-V4AF6DI4.js";
|
|
4
|
+
import "../../../chunk-2E224ZSN.js";
|
|
12
5
|
export {
|
|
13
6
|
MissingTenantIdError
|
|
14
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|