@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/integration/incremental-read.ts"],"sourcesContent":["/**\n * Integration subsystem — `IncrementalRead<T, F>` + `RandomRead<T>` capability\n * and the providing `IncrementalReadBase<T, F, M>` (RFC-0003 R1).\n *\n * The universal read primitive. Where `IChangeSource.listChanges` is the\n * *transport* contract (stream `Change<T>`, orchestrator owns cursor lifecycle),\n * this base owns *how the body that produces those changes is written* — the\n * level the bare `changeSources = {}` author-seam left unstructured.\n *\n * The read decomposes into two composable verbs the adapter supplies:\n *\n * - `enumerate(mode, filter) → AsyncIterable<Ref<M>[]>` — the cheap delta /\n * backfill walk; streams pages of lightweight refs (id + per-ref cursor +\n * filterable metadata). LAZY: pull-driven so hydrate backpressures it.\n * - `hydrate(ids) → Map<id, raw>` — the expensive fetch-by-id, batched; where\n * bounded concurrency / a vendor `/batch` endpoint lives. Keyed and\n * miss-tolerant (a mid-run 404 cannot shift alignment).\n * - `toCanonical(raw) → T | null` — provider payload → canonical record.\n *\n * The base PROVIDES the orchestration: drain enumerate, **filter before\n * hydrate** (structural — an adapter physically cannot hydrate-then-discard),\n * keyed pairing, per-ref cursor emission, and the `IChangeSource.listChanges`\n * adaptation. It also provides `RandomRead.get()` for free as\n * `toCanonical ∘ hydrate([id])` — so every incremental adapter is a\n * single-record reader (the \"list cheaply, fill on click\" query-surface need)\n * without extra code.\n *\n * The shape generalizes dealbrain's proven HubSpot `listSince` (streams, pushes\n * the filter server-side, carries a per-record cursor) to vendors whose list\n * returns id-stubs (Gmail) or nested resources (Meet). Calendar-style\n * full-object lists override `hydrate` as a passthrough.\n *\n * See RFC-0003 (Track D round-3), ADR-033 (`detection:` config), and\n * `poll-change-source.ts` (the sibling primitive this composes beside).\n */\n\nimport type {\n Change,\n ChangeSource,\n IChangeSource,\n IntegrationSubscriptionView,\n} from './integration-change-source.protocol';\n\n// ============================================================================\n// Capability shapes\n// ============================================================================\n\n/**\n * How a read walks the upstream. Modes are values, not verbs (swe-brain\n * ADR-0003: mode ≠ capability) — one `read()` verb dispatches on these.\n *\n * - `delta` — incremental walk from a persisted cursor.\n * - `full` — cursorless backfill (optionally bounded by `since`).\n * - `reconcile` — gap-repair: re-fetch a known id set the cursor skipped\n * (the repair pass for the silent-tail-skip + #414-style\n * multi-provider divergence).\n */\nexport type ReadMode =\n | { readonly kind: 'delta'; readonly cursor: unknown }\n | { readonly kind: 'full'; readonly since?: Date }\n | { readonly kind: 'reconcile'; readonly knownIds: readonly string[] };\n\n/**\n * A cheap ref from the enumerate pass: identity + per-ref cursor + metadata to\n * filter or display on. `cursor` is the position AS OF this ref — see\n * `IncrementalReadBase.cursorDivisible` (R2) for when it may be checkpointed\n * mid-walk versus withheld until a safe boundary.\n */\nexport interface Ref<M = Record<string, unknown>> {\n readonly externalId: string;\n readonly cursor: unknown;\n readonly meta: M;\n}\n\n/** A read request: the mode, an optional adapter-typed filter, and page size. */\nexport interface ReadRequest<F = unknown> {\n readonly mode: ReadMode;\n readonly filter?: F;\n readonly pageSize?: number;\n}\n\n/**\n * Per-run context threaded from `listChanges` into the vendor read body (R5).\n *\n * Carries the `subscription` framing the run so `enumerate`/`hydrate` can resolve\n * **per-connection credentials** (and raw-landing keys) from\n * `subscription.externalRef` — the gap a multi-account consumer surfaced: a\n * singleton change source cannot hold connection-scoped auth, and before R5 the\n * base forwarded the subscription only into `filterFor`, never into the fetch.\n *\n * Optional throughout (the core contract): a direct `read()` / `get()` call — the\n * query surface's \"fill one record on click\" — may omit it. An adapter that needs\n * per-connection auth reads `ctx?.subscription?.externalRef` and asserts its\n * presence; a provider-level-auth adapter ignores it.\n */\nexport interface ReadContext {\n /** The subscription framing this run; `externalRef` is the upstream scope /\n * connection id the adapter resolves credentials + raw-landing keys from. */\n readonly subscription?: IntegrationSubscriptionView;\n}\n\n/**\n * The `read()`-side envelope: canonical record + the raw vendor payload it came\n * from + the originating external id + the per-ref cursor.\n *\n * Distinct from the runtime's transport envelope `Change<T>`\n * (operation/externalId/cursor/source). The relationship is one-directional:\n * `listChanges()` adapts `read()` → `Change<T>` (dropping `raw`, stamping\n * `operation`). `read()` keeps `raw` and `externalId` so a query surface can\n * re-project without a second fetch.\n */\nexport interface SourcedRecord<T> {\n readonly externalId: string;\n readonly record: T;\n readonly raw: unknown;\n readonly cursor: unknown;\n}\n\n/**\n * The universal read capability — one public verb that streams. Filtering,\n * hydration, and cursor emission are the providing base's concern.\n */\nexport interface IncrementalRead<T, F = unknown> {\n read(req: ReadRequest<F>, ctx?: ReadContext): AsyncIterable<SourcedRecord<T>>;\n}\n\n/**\n * Single-record read by external id — the \"fill on click\" atom. Provided for\n * free by `IncrementalReadBase` (composes `hydrate` + `toCanonical`); declared\n * as its own capability so consumers can depend on it without the streaming\n * surface.\n */\nexport interface RandomRead<T> {\n get(id: string, ctx?: ReadContext): Promise<T | null>;\n}\n\n// ============================================================================\n// Bounded-parallel map helper\n// ============================================================================\n\n/**\n * Map `ids` through `fn` with at most `limit` concurrent in-flight calls,\n * collecting results keyed by id. The workhorse for writing a batched\n * `hydrate` over a single-id fetch without serial N+1 latency.\n */\nexport async function mapConcurrent<R>(\n ids: readonly string[],\n fn: (id: string) => Promise<R>,\n limit: number,\n): Promise<Map<string, R>> {\n const out = new Map<string, R>();\n if (ids.length === 0) return out;\n const width = Math.max(1, Math.min(limit, ids.length));\n let next = 0;\n const worker = async (): Promise<void> => {\n while (next < ids.length) {\n const idx = next++;\n const id = ids[idx]!;\n out.set(id, await fn(id));\n }\n };\n await Promise.all(Array.from({ length: width }, worker));\n return out;\n}\n\n// ============================================================================\n// IncrementalReadBase\n// ============================================================================\n\n/**\n * Providing base for the read capability. A subclass fills exactly three vendor\n * methods — `enumerate`, `hydrate`, `toCanonical` — and gets a streaming,\n * filter-before-hydrate, miss-tolerant `IncrementalRead<T, F>` +\n * `IChangeSource<T>` + `RandomRead<T>`.\n *\n * Type params: `T` canonical record, `F` adapter-typed filter, `M` per-ref\n * metadata (defaults to an untyped bag — surface packages supply a domain `M`).\n */\nexport abstract class IncrementalReadBase<T, F = unknown, M = Record<string, unknown>>\n implements IncrementalRead<T, F>, IChangeSource<T>, RandomRead<T>\n{\n /** Human label for run logs — e.g. `'google-mail-email'`. */\n abstract readonly label: string;\n\n /**\n * Whether the vendor takes the request predicate server-side. Declared, not\n * enforced here — surfaced into the emission manifest (R3) so the falsifier\n * suite (R4) can record which adapters filter post-hydrate. `false` is the\n * honest floor (e.g. Gmail without `q=`), handled via `matchesRecord`.\n */\n protected readonly filterPushdown: boolean = false;\n\n /** Max concurrent in-flight calls for a `mapConcurrent`-built `hydrate`. */\n protected readonly hydrateConcurrency: number = 10;\n\n /** `Change<T>.source` provenance stamped by `listChanges`. */\n protected readonly changeSource: ChangeSource = 'poll';\n\n /**\n * Whether this source's cursor strategy is divisible (RFC-0003 §3). When\n * `true` (default — sortable watermarks like `systemModstamp`/`timestamp`/\n * `replayId`), `listChanges` emits each record's per-ref cursor, so the\n * orchestrator may checkpoint mid-walk and a crash resumes from the last\n * delivered ref.\n *\n * When `false` (atomic opaque tokens — Gmail `historyId`, Calendar\n * `syncToken`), `listChanges` WITHHOLDS per-ref cursors and emits the\n * end-of-walk token only on the final record, so the orchestrator's\n * persist-last-yielded lifecycle can never persist an unresumable mid-walk\n * token. The cost is blast-radius: an interrupted atomic run resumes\n * all-or-nothing from the prior persisted token. For atomic *backfills* that\n * radius is the whole enumerate walk — bound it with `ReadRequest.pageSize`\n * (smaller pages ⇒ shorter walks per run). Per-page atomic checkpointing is a\n * future refinement; R2 gates at end-of-walk.\n *\n * Codegen (R3) sets this from the strategy kind via `isDivisibleCursor`.\n */\n protected readonly cursorDivisible: boolean = true;\n\n // ---- SUPPLIED by the adapter (the irreducible vendor seam) ----\n\n /**\n * The cheap walk. Streams pages of refs; LAZY so `hydrate` backpressures it\n * (one page hydrated before the next is pulled). Mode-dispatch lives here:\n * `delta` resumes from `mode.cursor`, `full` walks from the top, `reconcile`\n * re-fetches `mode.knownIds`.\n *\n * `pageSize` (from `ReadRequest`) is the adapter's requested vendor page size\n * — also the atomic-cursor backfill blast-radius bound (§ `cursorDivisible`).\n * Honor it as a hint; vendors that cap page size clamp it.\n *\n * `ctx?.subscription` (R5) carries the run's subscription, so a per-connection\n * adapter resolves credentials / upstream scope from `externalRef` here; absent\n * on a direct `read()` with no run subscription.\n */\n protected abstract enumerate(\n mode: ReadMode,\n filter?: F,\n pageSize?: number,\n ctx?: ReadContext,\n ): AsyncIterable<Ref<M>[]>;\n\n /**\n * Fetch raw payloads for `ids`, keyed by id. MUST be miss-tolerant: omit (or\n * map to `null`) any id that 404s mid-run rather than throwing or shifting\n * alignment. Write it over `mapConcurrent(ids, (id) => this.fetchOne(id),\n * this.hydrateConcurrency)`; override with a real `/batch` call or a\n * passthrough (full-object list) where the vendor allows.\n *\n * `ctx?.subscription` (R5) carries the run's subscription for per-connection\n * credential resolution (the fetch is where the vendor call happens) and is the\n * natural place to land raw payloads keyed by `subscription.id`.\n */\n protected abstract hydrate(ids: string[], ctx?: ReadContext): Promise<Map<string, unknown>>;\n\n /** Provider payload → canonical record. Return `null` to drop a record. */\n protected abstract toCanonical(raw: unknown): T | null;\n\n // ---- Optional filter hooks — exactly one is live per `filterPushdown` ----\n\n /** Pre-hydrate predicate over the cheap ref (preferred — avoids hydration). */\n protected matchesRef(_ref: Ref<M>, _filter?: F): boolean {\n return true;\n }\n\n /** Post-hydrate predicate over the canonical record (the no-pushdown floor). */\n protected matchesRecord(_record: T, _filter?: F): boolean {\n return true;\n }\n\n /**\n * Resolve the filter for a subscription when adapting to `listChanges`\n * (which has no filter argument). Defaults to none; codegen wiring (R3)\n * overrides this to thread `DetectionConfig.filters`.\n */\n protected filterFor(_subscription: IntegrationSubscriptionView): F | undefined {\n return undefined;\n }\n\n // ---- PROVIDED by the base ----\n\n /**\n * Stream canonical records for a request. Filter is applied BEFORE hydrate\n * (structural: a kept ref is hydrated, a rejected one never is), so an\n * adapter cannot hydrate-then-discard. A hydrate miss (deleted mid-run) is\n * skipped, never fabricated.\n */\n async *read(req: ReadRequest<F>, ctx?: ReadContext): AsyncIterable<SourcedRecord<T>> {\n for await (const refPage of this.enumerate(req.mode, req.filter, req.pageSize, ctx)) {\n const kept = refPage.filter((ref) => this.matchesRef(ref, req.filter));\n if (kept.length === 0) continue;\n const raws = await this.hydrate(\n kept.map((ref) => ref.externalId),\n ctx,\n );\n for (const ref of kept) {\n const raw = raws.get(ref.externalId);\n if (raw === undefined || raw === null) continue; // deleted mid-run → skip\n const record = this.toCanonical(raw);\n if (record !== null && this.matchesRecord(record, req.filter)) {\n yield { externalId: ref.externalId, record, raw, cursor: ref.cursor };\n }\n }\n }\n }\n\n /**\n * `RandomRead<T>` — single-record read, provided for free as\n * `toCanonical ∘ hydrate([id])`. Reuses the adapter's batched fetch + miss\n * tolerance; returns `null` for a missing or undecodable record.\n */\n async get(id: string, ctx?: ReadContext): Promise<T | null> {\n const raws = await this.hydrate([id], ctx);\n const raw = raws.get(id);\n if (raw === undefined || raw === null) return null;\n return this.toCanonical(raw);\n }\n\n /**\n * `IChangeSource<T>` adaptation. Maps the orchestrator's by-value cursor to a\n * `ReadMode` (`null` → `full` backfill, else `delta`), streams `read()`, and\n * stamps each `SourcedRecord` into a `Change<T>`. All records surface as\n * `'updated'`; the orchestrator's diff stage classifies create-vs-update and\n * deletes arrive as tombstone refs (`toCanonical` may flag them).\n *\n * Cursor emission honors `cursorDivisible` (RFC-0003 §3). Divisible: each\n * record carries its own per-ref cursor. Atomic: per-ref cursors are withheld\n * (`undefined`, which the orchestrator skips persisting) and the end-of-walk\n * token rides only on the final record — so a mid-walk crash never persists\n * an unresumable token. If an atomic run yields no surviving records, no\n * cursor is persisted and the next run re-reads the same (empty) delta — a\n * bounded inefficiency, never data loss.\n */\n async *listChanges(\n subscription: IntegrationSubscriptionView,\n cursor: unknown | null,\n ): AsyncIterable<Change<T>> {\n const mode: ReadMode =\n cursor === null || cursor === undefined\n ? { kind: 'full' }\n : { kind: 'delta', cursor };\n const filter = this.filterFor(subscription);\n // R5: thread the run's subscription into the read body so `enumerate`/`hydrate`\n // can resolve per-connection credentials (and raw-landing keys) from it.\n const stream = this.read({ mode, filter }, { subscription });\n\n if (this.cursorDivisible) {\n for await (const sourced of stream) {\n yield this.toChange(sourced, sourced.cursor);\n }\n return;\n }\n\n // Atomic: one-record lookahead. Emit every record but the last with a\n // withheld (`undefined`) cursor; the last record carries the end-of-walk\n // token. Contract: an atomic adapter stamps the (single, shared) end-of-walk\n // token onto its refs' `cursor` — so whichever record survives last carries\n // it. The base emits a real cursor exactly once, on that final record, so the\n // orchestrator can never persist a mid-walk value. If zero records survive,\n // nothing is persisted (next run re-reads the delta — bounded, never lossy).\n let prev: SourcedRecord<T> | null = null;\n for await (const sourced of stream) {\n if (prev !== null) yield this.toChange(prev, undefined);\n prev = sourced;\n }\n if (prev !== null) yield this.toChange(prev, prev.cursor);\n }\n\n /** Stamp a `SourcedRecord` into a `Change<T>` with an explicit emitted cursor. */\n private toChange(sourced: SourcedRecord<T>, cursor: unknown): Change<T> {\n return {\n externalId: sourced.externalId,\n operation: 'updated',\n record: sourced.record,\n cursor,\n source: this.changeSource,\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConnectionBrokenError
|
|
3
|
+
} from "./chunk-2N4UG4VD.js";
|
|
4
|
+
|
|
5
|
+
// runtime/subsystems/auth/runtime/oauth2-refresh.strategy.ts
|
|
6
|
+
var REFRESH_SAFETY_MS = 5 * 60 * 1e3;
|
|
7
|
+
var OAuth2RefreshStrategy = class {
|
|
8
|
+
connectionReader;
|
|
9
|
+
tokenWriter;
|
|
10
|
+
fetchImpl;
|
|
11
|
+
now;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
this.connectionReader = opts.connectionReader;
|
|
14
|
+
this.tokenWriter = opts.tokenWriter;
|
|
15
|
+
this.fetchImpl = opts.fetch ?? fetch;
|
|
16
|
+
this.now = opts.now ?? Date.now;
|
|
17
|
+
}
|
|
18
|
+
async resolve(connectionId, opts = {}) {
|
|
19
|
+
const connection = await this.connectionReader.findByIdDecrypted(connectionId);
|
|
20
|
+
if (!connection) {
|
|
21
|
+
throw new Error(`Connection ${connectionId} not found`);
|
|
22
|
+
}
|
|
23
|
+
if (connection.provider !== this.provider) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`${this.constructor.name} called for non-${this.provider} connection ${connectionId} (provider=${connection.provider})`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const needsRefresh = opts.forceRefresh || this.isExpiring(connection.expiresAt) || !connection.accessToken;
|
|
29
|
+
if (!needsRefresh) {
|
|
30
|
+
return this.buildCredentials(connection.accessToken, connection);
|
|
31
|
+
}
|
|
32
|
+
if (!connection.refreshToken) {
|
|
33
|
+
throw new ConnectionBrokenError(
|
|
34
|
+
connectionId,
|
|
35
|
+
"no_refresh_token",
|
|
36
|
+
"Connection has no refresh token; user must reconnect"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const { parsed, raw } = await this.executeRefresh(
|
|
40
|
+
connectionId,
|
|
41
|
+
connection.refreshToken
|
|
42
|
+
);
|
|
43
|
+
const newExpiresAt = new Date(
|
|
44
|
+
this.now() + (parsed.expiresInSec ?? this.defaultExpiresInSec) * 1e3
|
|
45
|
+
);
|
|
46
|
+
await this.tokenWriter.persistRefresh({
|
|
47
|
+
connectionId,
|
|
48
|
+
accessToken: parsed.accessToken,
|
|
49
|
+
refreshToken: parsed.refreshToken ?? void 0,
|
|
50
|
+
expiresAt: newExpiresAt
|
|
51
|
+
});
|
|
52
|
+
return this.buildCredentials(parsed.accessToken, connection, raw);
|
|
53
|
+
}
|
|
54
|
+
async executeRefresh(connectionId, refreshToken) {
|
|
55
|
+
const body = new URLSearchParams({
|
|
56
|
+
grant_type: "refresh_token",
|
|
57
|
+
refresh_token: refreshToken,
|
|
58
|
+
...this.refreshBodyExtras()
|
|
59
|
+
});
|
|
60
|
+
const response = await this.fetchImpl(this.tokenEndpoint(), {
|
|
61
|
+
method: "POST",
|
|
62
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
63
|
+
body: body.toString()
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
const err = await safeJson(response);
|
|
67
|
+
if (response.status === 400 && (err.error === "invalid_grant" || err.error === "invalid_token")) {
|
|
68
|
+
throw new ConnectionBrokenError(
|
|
69
|
+
connectionId,
|
|
70
|
+
err.error ?? "invalid_grant",
|
|
71
|
+
err.error_description ?? err.message ?? "refresh token rejected"
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
throw new Error(
|
|
75
|
+
`${this.provider} token refresh failed: ${response.status} ${err.error ?? ""} ${err.error_description ?? err.message ?? ""}`.trim()
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const raw = await response.json();
|
|
79
|
+
return { parsed: this.parseRefreshResponse(raw), raw };
|
|
80
|
+
}
|
|
81
|
+
isExpiring(expiresAt) {
|
|
82
|
+
if (!expiresAt) return true;
|
|
83
|
+
return expiresAt.getTime() - this.now() < REFRESH_SAFETY_MS;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
async function safeJson(response) {
|
|
87
|
+
try {
|
|
88
|
+
return await response.clone().json();
|
|
89
|
+
} catch {
|
|
90
|
+
return {};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
OAuth2RefreshStrategy
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=chunk-M6QLSLPO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/auth/runtime/oauth2-refresh.strategy.ts"],"sourcesContent":["/**\n * Abstract base class for OAuth2 refresh-token strategies.\n *\n * Template-method pattern: `resolve()` is concrete; four small hooks inject\n * provider specifics. Validated across two providers (Salesforce, HubSpot)\n * in the extraction-source app before being extracted here — see\n * `docs/gate-1-auth-extraction-findings.md` for the \"build first, extract\n * later\" evidence.\n *\n * Subclass contract:\n * - `provider` — slug matched against `connections.provider`\n * - `defaultExpiresInSec` — fallback when refresh response omits `expires_in`\n * - `tokenEndpoint()` — URL to POST the refresh grant\n * - `refreshBodyExtras()` — provider-specific body params\n * - `parseRefreshResponse()` — raw JSON → ParsedRefreshResponse\n * - `buildCredentials()` — stored or freshly-refreshed access token +\n * connection + optional raw refresh response\n * → provider credentials\n *\n * Base handles: expiry check w/ 5-min safety window, `forceRefresh` escape\n * hatch, POST form-urlencoded body, OAuth2 error mapping to\n * `ConnectionBrokenError`, refresh-token rotation persistence, fetch +\n * clock injection for tests.\n */\nimport type {\n AuthCredentials,\n AuthResolveOptions,\n IAuthStrategy,\n} from '../protocols/auth-strategy';\nimport type {\n DecryptedConnection,\n IConnectionReader,\n IConnectionTokenWriter,\n} from '../protocols/connection-store';\nimport { ConnectionBrokenError } from './connection-broken.error';\n\nexport type FetchLike = (\n input: string | URL | Request,\n init?: RequestInit,\n) => Promise<Response>;\n\n/** Safety window before expiry that triggers a refresh. */\nconst REFRESH_SAFETY_MS = 5 * 60 * 1000;\n\nexport interface OAuth2RefreshStrategyOptions {\n connectionReader: IConnectionReader;\n tokenWriter: IConnectionTokenWriter;\n /** Injectable fetch for tests. Defaults to the global `fetch`. */\n fetch?: FetchLike;\n /** Injectable clock for tests. Defaults to `Date.now`. */\n now?: () => number;\n}\n\nexport interface ParsedRefreshResponse {\n accessToken: string;\n /**\n * New refresh token if the provider rotated it (HubSpot: always, Salesforce:\n * sometimes). Omit when the provider reused the old refresh token.\n */\n refreshToken?: string;\n /** Seconds from now. If omitted, subclass `defaultExpiresInSec` applies. */\n expiresInSec?: number;\n}\n\nexport abstract class OAuth2RefreshStrategy implements IAuthStrategy {\n protected abstract readonly provider: string;\n protected abstract readonly defaultExpiresInSec: number;\n\n protected readonly connectionReader: IConnectionReader;\n protected readonly tokenWriter: IConnectionTokenWriter;\n protected readonly fetchImpl: FetchLike;\n protected readonly now: () => number;\n\n constructor(opts: OAuth2RefreshStrategyOptions) {\n this.connectionReader = opts.connectionReader;\n this.tokenWriter = opts.tokenWriter;\n this.fetchImpl = opts.fetch ?? fetch;\n this.now = opts.now ?? Date.now;\n }\n\n async resolve(\n connectionId: string,\n opts: AuthResolveOptions = {},\n ): Promise<AuthCredentials> {\n const connection =\n await this.connectionReader.findByIdDecrypted(connectionId);\n if (!connection) {\n throw new Error(`Connection ${connectionId} not found`);\n }\n if (connection.provider !== this.provider) {\n throw new Error(\n `${this.constructor.name} called for non-${this.provider} connection ${connectionId} (provider=${connection.provider})`,\n );\n }\n\n const needsRefresh =\n opts.forceRefresh ||\n this.isExpiring(connection.expiresAt) ||\n !connection.accessToken;\n\n if (!needsRefresh) {\n return this.buildCredentials(connection.accessToken, connection);\n }\n\n if (!connection.refreshToken) {\n throw new ConnectionBrokenError(\n connectionId,\n 'no_refresh_token',\n 'Connection has no refresh token; user must reconnect',\n );\n }\n\n const { parsed, raw } = await this.executeRefresh(\n connectionId,\n connection.refreshToken,\n );\n const newExpiresAt = new Date(\n this.now() + (parsed.expiresInSec ?? this.defaultExpiresInSec) * 1000,\n );\n await this.tokenWriter.persistRefresh({\n connectionId,\n accessToken: parsed.accessToken,\n refreshToken: parsed.refreshToken ?? undefined,\n expiresAt: newExpiresAt,\n });\n\n return this.buildCredentials(parsed.accessToken, connection, raw);\n }\n\n protected abstract tokenEndpoint(): string;\n protected abstract refreshBodyExtras(): Record<string, string>;\n protected abstract parseRefreshResponse(raw: unknown): ParsedRefreshResponse;\n protected abstract buildCredentials(\n accessToken: string,\n connection: DecryptedConnection,\n refreshRaw?: unknown,\n ): AuthCredentials;\n\n private async executeRefresh(\n connectionId: string,\n refreshToken: string,\n ): Promise<{ parsed: ParsedRefreshResponse; raw: unknown }> {\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n ...this.refreshBodyExtras(),\n });\n const response = await this.fetchImpl(this.tokenEndpoint(), {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n });\n if (!response.ok) {\n const err = (await safeJson(response)) as Partial<{\n error: string;\n error_description: string;\n message: string;\n }>;\n if (\n response.status === 400 &&\n (err.error === 'invalid_grant' || err.error === 'invalid_token')\n ) {\n throw new ConnectionBrokenError(\n connectionId,\n err.error ?? 'invalid_grant',\n err.error_description ?? err.message ?? 'refresh token rejected',\n );\n }\n throw new Error(\n `${this.provider} token refresh failed: ${response.status} ${err.error ?? ''} ${err.error_description ?? err.message ?? ''}`.trim(),\n );\n }\n const raw = await response.json();\n return { parsed: this.parseRefreshResponse(raw), raw };\n }\n\n private isExpiring(expiresAt: Date | null): boolean {\n if (!expiresAt) return true;\n return expiresAt.getTime() - this.now() < REFRESH_SAFETY_MS;\n }\n}\n\nasync function safeJson(response: Response): Promise<unknown> {\n try {\n return await response.clone().json();\n } catch {\n return {};\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// runtime/subsystems/integration/integration-errors.ts
|
|
2
|
+
var MissingTenantIdError = class extends Error {
|
|
3
|
+
name = "MissingTenantIdError";
|
|
4
|
+
constructor(operation) {
|
|
5
|
+
super(
|
|
6
|
+
`Missing tenantId for integration operation '${operation}'. IntegrationModule is configured with multiTenant: true \u2014 every call must include a non-null tenantId. Either pass the tenantId or disable multi-tenancy on the module.`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
function assertTenantId(tenantId, options) {
|
|
11
|
+
if (!options.multiTenant) return;
|
|
12
|
+
if (tenantId === void 0 || tenantId === null) {
|
|
13
|
+
throw new MissingTenantIdError(options.operation);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
MissingTenantIdError,
|
|
19
|
+
assertTenantId
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=chunk-MZ6GV4YF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/integration/integration-errors.ts"],"sourcesContent":["/**\n * Typed errors + shared boundary helpers for the integration subsystem.\n *\n * Classes (not bare Error) so consumers can `instanceof` them in catch\n * blocks and exception filters can map them to HTTP codes.\n *\n * Mirrors the shape of `events-errors.ts` and `jobs-errors.ts`.\n */\n\n/**\n * Thrown by the Drizzle cursor-store / run-recorder backends AND by the\n * orchestrator entry point when `INTEGRATION_MULTI_TENANT` is enabled but the\n * caller did not supply a non-null `tenantId`. Strict enforcement at the\n * boundary — explicit `null` still throws.\n *\n * Disable multi-tenancy on the module (`multiTenant: false`, the default)\n * to opt out of the requirement entirely.\n *\n * `operation` identifies the call site (e.g. `'cursor.put'`,\n * `'startRun'`, `'execute'`) so the stack-trace message points at the\n * specific boundary that rejected the input.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(operation: string) {\n super(\n `Missing tenantId for integration operation '${operation}'. IntegrationModule is ` +\n `configured with multiTenant: true — every call must include a ` +\n `non-null tenantId. Either pass the tenantId or disable multi-` +\n `tenancy on the module.`,\n );\n }\n}\n\n/**\n * Shared boundary guard — used at the orchestrator entry AND inside the\n * Drizzle backends. Keeping the check in one function guarantees every\n * `MissingTenantIdError` carries the same message shape regardless of the\n * site that raised it, which makes it easier for consumers to pattern-\n * match on the error in logs/metrics.\n *\n * When `multiTenant` is false, the function is a no-op — `tenantId` may\n * be anything (including `undefined`). When true, `undefined` or `null`\n * throws.\n */\nexport function assertTenantId(\n tenantId: string | null | undefined,\n options: { multiTenant: boolean; operation: string },\n): asserts tenantId is string {\n if (!options.multiTenant) return;\n if (tenantId === undefined || tenantId === null) {\n throw new MissingTenantIdError(options.operation);\n }\n}\n"],"mappings":";AAsBO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC5B,OAAO;AAAA,EACzB,YAAY,WAAmB;AAC7B;AAAA,MACE,+CAA+C,SAAS;AAAA,IAI1D;AAAA,EACF;AACF;AAaO,SAAS,eACd,UACA,SAC4B;AAC5B,MAAI,CAAC,QAAQ,YAAa;AAC1B,MAAI,aAAa,UAAa,aAAa,MAAM;AAC/C,UAAM,IAAI,qBAAqB,QAAQ,SAAS;AAAA,EAClD;AACF;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OAuthStateError
|
|
3
|
+
} from "./chunk-BPARRK6F.js";
|
|
4
|
+
import {
|
|
5
|
+
authOAuthState
|
|
6
|
+
} from "./chunk-NPFPZ2HO.js";
|
|
7
|
+
|
|
8
|
+
// runtime/subsystems/auth/backends/state-store.drizzle-backend.ts
|
|
9
|
+
import { randomBytes } from "crypto";
|
|
10
|
+
import { eq } from "drizzle-orm";
|
|
11
|
+
var DrizzleOAuthStateStore = class {
|
|
12
|
+
constructor(db, opts = {}) {
|
|
13
|
+
this.db = db;
|
|
14
|
+
this.ttlMs = opts.ttlMs ?? 10 * 60 * 1e3;
|
|
15
|
+
this.now = opts.now ?? (() => Date.now());
|
|
16
|
+
this.generateToken = opts.generateToken ?? (() => randomBytes(32).toString("base64url"));
|
|
17
|
+
}
|
|
18
|
+
db;
|
|
19
|
+
ttlMs;
|
|
20
|
+
now;
|
|
21
|
+
generateToken;
|
|
22
|
+
async generate(record) {
|
|
23
|
+
const state = this.generateToken();
|
|
24
|
+
const expiresAt = new Date(this.now() + this.ttlMs);
|
|
25
|
+
await this.db.insert(authOAuthState).values({
|
|
26
|
+
state,
|
|
27
|
+
userId: record.userId,
|
|
28
|
+
redirect: record.redirect ?? null,
|
|
29
|
+
expiresAt
|
|
30
|
+
});
|
|
31
|
+
return state;
|
|
32
|
+
}
|
|
33
|
+
async consume(state) {
|
|
34
|
+
const rows = await this.db.delete(authOAuthState).where(eq(authOAuthState.state, state)).returning();
|
|
35
|
+
const row = rows[0];
|
|
36
|
+
if (!row) {
|
|
37
|
+
throw new OAuthStateError(
|
|
38
|
+
`OAuth state token unknown or already consumed`,
|
|
39
|
+
"missing"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (row.expiresAt.getTime() <= this.now()) {
|
|
43
|
+
throw new OAuthStateError(`OAuth state token expired`, "expired");
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
userId: row.userId,
|
|
47
|
+
redirect: row.redirect ?? void 0
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
DrizzleOAuthStateStore
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=chunk-N5OTOWTP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/auth/backends/state-store.drizzle-backend.ts"],"sourcesContent":["/**\n * Drizzle-backed `IOAuthStateStore`.\n *\n * Uses the `auth_oauth_state` table (see `auth-oauth-state.schema.ts`).\n * Single-use semantics enforced via `DELETE ... RETURNING`: the consume\n * path atomically deletes and returns the row, so a concurrent /callback\n * with the same state cannot replay.\n *\n * Behaviour:\n * - `generate(record)` mints a 256-bit base64url token, INSERTs the row\n * with `expires_at = now() + ttlMs`.\n * - `consume(state)` runs `DELETE ... WHERE state = $1 RETURNING ...`\n * once. Throws `OAuthStateError('missing')` if no row was deleted\n * (unknown or already consumed) and `OAuthStateError('expired')` if\n * the deleted row was past its `expires_at`.\n */\nimport { randomBytes } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\nimport type { DrizzleClient } from '../../../types/drizzle';\nimport { authOAuthState } from '../auth-oauth-state.schema';\nimport {\n type IOAuthStateStore,\n type OAuthStateRecord,\n OAuthStateError,\n} from '../protocols/oauth-state-store';\n\nexport interface DrizzleOAuthStateStoreOptions {\n /** TTL in ms. Default 10 minutes. */\n ttlMs?: number;\n /** Injectable clock for tests. Default `Date.now`. */\n now?: () => number;\n /** Injectable token generator for tests. Default 32-byte base64url. */\n generateToken?: () => string;\n}\n\nexport class DrizzleOAuthStateStore implements IOAuthStateStore {\n private readonly ttlMs: number;\n private readonly now: () => number;\n private readonly generateToken: () => string;\n\n constructor(\n private readonly db: DrizzleClient,\n opts: DrizzleOAuthStateStoreOptions = {},\n ) {\n this.ttlMs = opts.ttlMs ?? 10 * 60 * 1000;\n this.now = opts.now ?? (() => Date.now());\n this.generateToken =\n opts.generateToken ?? (() => randomBytes(32).toString('base64url'));\n }\n\n async generate(record: OAuthStateRecord): Promise<string> {\n const state = this.generateToken();\n const expiresAt = new Date(this.now() + this.ttlMs);\n await this.db.insert(authOAuthState).values({\n state,\n userId: record.userId,\n redirect: record.redirect ?? null,\n expiresAt,\n });\n return state;\n }\n\n async consume(state: string): Promise<OAuthStateRecord> {\n const rows = await this.db\n .delete(authOAuthState)\n .where(eq(authOAuthState.state, state))\n .returning();\n const row = rows[0];\n if (!row) {\n throw new OAuthStateError(\n `OAuth state token unknown or already consumed`,\n 'missing',\n );\n }\n if (row.expiresAt.getTime() <= this.now()) {\n throw new OAuthStateError(`OAuth state token expired`, 'expired');\n }\n return {\n userId: row.userId,\n redirect: row.redirect ?? undefined,\n };\n }\n}\n"],"mappings":";;;;;;;;AAgBA,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AAkBZ,IAAM,yBAAN,MAAyD;AAAA,EAK9D,YACmB,IACjB,OAAsC,CAAC,GACvC;AAFiB;AAGjB,SAAK,QAAQ,KAAK,SAAS,KAAK,KAAK;AACrC,SAAK,MAAM,KAAK,QAAQ,MAAM,KAAK,IAAI;AACvC,SAAK,gBACH,KAAK,kBAAkB,MAAM,YAAY,EAAE,EAAE,SAAS,WAAW;AAAA,EACrE;AAAA,EAPmB;AAAA,EALF;AAAA,EACA;AAAA,EACA;AAAA,EAYjB,MAAM,SAAS,QAA2C;AACxD,UAAM,QAAQ,KAAK,cAAc;AACjC,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK;AAClD,UAAM,KAAK,GAAG,OAAO,cAAc,EAAE,OAAO;AAAA,MAC1C;AAAA,MACA,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO,YAAY;AAAA,MAC7B;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,OAA0C;AACtD,UAAM,OAAO,MAAM,KAAK,GACrB,OAAO,cAAc,EACrB,MAAM,GAAG,eAAe,OAAO,KAAK,CAAC,EACrC,UAAU;AACb,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,IAAI,UAAU,QAAQ,KAAK,KAAK,IAAI,GAAG;AACzC,YAAM,IAAI,gBAAgB,6BAA6B,SAAS;AAAA,IAClE;AACA,WAAO;AAAA,MACL,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI,YAAY;AAAA,IAC5B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseRepository
|
|
3
|
+
} from "./chunk-J6KZS54B.js";
|
|
4
|
+
|
|
5
|
+
// runtime/base-classes/knowledge-entity-repository.ts
|
|
6
|
+
var KnowledgeEntityRepository = class extends BaseRepository {
|
|
7
|
+
// pgvector-dependent methods will be added when the extension is available:
|
|
8
|
+
// semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
KnowledgeEntityRepository
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=chunk-NN7XZEGF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/base-classes/knowledge-entity-repository.ts"],"sourcesContent":["/**\n * KnowledgeEntityRepository<TEntity>\n *\n * Stub for the knowledge family (requires pgvector — parked for now).\n * Concrete repos extend this when pgvector is available.\n */\nimport { BaseRepository } from './base-repository';\n\nexport abstract class KnowledgeEntityRepository<TEntity> extends BaseRepository<TEntity> {\n // pgvector-dependent methods will be added when the extension is available:\n // semanticSearch, findPendingByOpportunityId, updateStatus, updateStatusBatch\n}\n"],"mappings":";;;;;AAQO,IAAe,4BAAf,cAA0D,eAAwB;AAAA;AAAA;AAGzF;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// runtime/subsystems/auth/auth-oauth-state.schema.ts
|
|
2
|
+
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
3
|
+
var authOAuthState = pgTable("auth_oauth_state", {
|
|
4
|
+
state: text("state").primaryKey(),
|
|
5
|
+
userId: text("user_id").notNull(),
|
|
6
|
+
redirect: text("redirect"),
|
|
7
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull()
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
authOAuthState
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=chunk-NPFPZ2HO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/auth/auth-oauth-state.schema.ts"],"sourcesContent":["/**\n * Drizzle schema for the `auth_oauth_state` table — backs the\n * `DrizzleOAuthStateStore` (`state-store.drizzle-backend.ts`).\n *\n * One row per outstanding /connect → /callback dance. Single-use; rows are\n * deleted on consume. A periodic sweep (or a `WHERE expires_at < now()`\n * filter on read) clears abandoned rows.\n *\n * Columns:\n * - `state` — opaque random token, primary key.\n * - `user_id` — text (matches the consumer-defined user-id shape;\n * the auth subsystem doesn't constrain this to UUID\n * because some apps key users by external id).\n * - `redirect` — optional post-callback redirect path.\n * - `expires_at` — TTL boundary; entries past this are treated as absent.\n *\n * Convention: schema files live at the root of the subsystem dir\n * (mirrors `cache.schema.ts`, `integration-audit.schema.ts`, `domain-events.schema.ts`).\n */\nimport { pgTable, text, timestamp } from 'drizzle-orm/pg-core';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nexport const authOAuthState = pgTable('auth_oauth_state', {\n state: text('state').primaryKey(),\n userId: text('user_id').notNull(),\n redirect: text('redirect'),\n expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),\n});\n\nexport type AuthOAuthState = InferSelectModel<typeof authOAuthState>;\n"],"mappings":";AAmBA,SAAS,SAAS,MAAM,iBAAiB;AAGlC,IAAM,iBAAiB,QAAQ,oBAAoB;AAAA,EACxD,OAAO,KAAK,OAAO,EAAE,WAAW;AAAA,EAChC,QAAQ,KAAK,SAAS,EAAE,QAAQ;AAAA,EAChC,UAAU,KAAK,UAAU;AAAA,EACzB,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ;AACrE,CAAC;","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// runtime/subsystems/bridge/bridge-errors.ts
|
|
2
|
+
var MissingTenantIdError = class extends Error {
|
|
3
|
+
constructor(callSite) {
|
|
4
|
+
super(
|
|
5
|
+
`MissingTenantIdError: BridgeModule was configured with multiTenant=true but ${callSite} was called without tenantId (undefined). Pass an explicit tenantId, or pass null for cross-tenant work.`
|
|
6
|
+
);
|
|
7
|
+
this.callSite = callSite;
|
|
8
|
+
}
|
|
9
|
+
callSite;
|
|
10
|
+
name = "MissingTenantIdError";
|
|
11
|
+
};
|
|
12
|
+
var BridgeReservedPoolsNotPolledError = class extends Error {
|
|
13
|
+
constructor(missingPools) {
|
|
14
|
+
super(
|
|
15
|
+
`BridgeModule loaded but JobWorkerModule is not polling reserved pool '${missingPools[0]}'. Add ...BRIDGE_RESERVED_POOLS to your JobWorkerModule.forRoot({ pools }) configuration. Missing pools: ${missingPools.join(", ")}. (Bridge-fanout wrappers will sit pending forever without these pollers.)`
|
|
16
|
+
);
|
|
17
|
+
this.missingPools = missingPools;
|
|
18
|
+
}
|
|
19
|
+
missingPools;
|
|
20
|
+
name = "BridgeReservedPoolsNotPolledError";
|
|
21
|
+
};
|
|
22
|
+
var UniqueConstraintError = class extends Error {
|
|
23
|
+
constructor(constraint, eventId, triggerId) {
|
|
24
|
+
super(
|
|
25
|
+
`UniqueConstraintError: duplicate insert into bridge_delivery for (event_id='${eventId}', trigger_id='${triggerId}') \u2014 violates constraint '${constraint}'.`
|
|
26
|
+
);
|
|
27
|
+
this.constraint = constraint;
|
|
28
|
+
this.eventId = eventId;
|
|
29
|
+
this.triggerId = triggerId;
|
|
30
|
+
}
|
|
31
|
+
constraint;
|
|
32
|
+
eventId;
|
|
33
|
+
triggerId;
|
|
34
|
+
name = "UniqueConstraintError";
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
MissingTenantIdError,
|
|
39
|
+
BridgeReservedPoolsNotPolledError,
|
|
40
|
+
UniqueConstraintError
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=chunk-NXXDZ6ZF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/bridge/bridge-errors.ts"],"sourcesContent":["/**\n * Typed errors for the bridge subsystem (ADR-023 Phase 2, BRIDGE-2).\n *\n * All thrown by the three enforcement sites named in ADR-023 §Multi-tenancy:\n * - `EventFlowService.publishAndStart` entry (BRIDGE-7)\n * - `BridgeDeliveryHandler.handle` entry (BRIDGE-5)\n * - `DrizzleBridgeDeliveryRepo.insertDelivery` pre-write (BRIDGE-4)\n *\n * Same shape as `runtime/subsystems/jobs/jobs-errors.ts` and\n * `runtime/subsystems/events/events-errors.ts` so consumers can catch them\n * with the same exception-filter pattern across all three subsystems.\n */\n\n/**\n * Thrown when `BridgeModule` was configured with `multiTenant: true` but\n * the caller did not pass a `tenantId` at one of the three enforcement\n * sites listed above.\n *\n * **Strict enforcement rationale (mirrors JOB-8 / SYNC-6 stance, locked\n * 2026-04-18 for jobs; same rationale applies here).** Cross-tenant data\n * leakage is the worst class of bug a multi-tenant system can ship;\n * surfacing the misuse loudly at the call site (rather than silently\n * defaulting to `null` or to \"the last tenant seen\") prevents both\n * accidental global writes and sneaky reads that return a union of tenants.\n *\n * - `undefined` `tenantId` → throw this error.\n * - Explicit `null` `tenantId` → passes; opts the call into cross-tenant\n * work (e.g. a system housekeeping event with no owning tenant). The\n * `bridge_delivery` row is persisted with `tenant_id = NULL`.\n *\n * The `callSite` constructor argument names which of the three enforcement\n * sites threw — review reports and ops dashboards rely on a stable site\n * name, so use the canonical strings: `'EventFlowService.publishAndStart'`,\n * `'BridgeDeliveryHandler.handle'`,\n * `'DrizzleBridgeDeliveryRepo.insertDelivery'`.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(public readonly callSite: string) {\n super(\n `MissingTenantIdError: BridgeModule was configured with ` +\n `multiTenant=true but ${callSite} was called without tenantId ` +\n `(undefined). Pass an explicit tenantId, or pass null for ` +\n `cross-tenant work.`,\n );\n }\n}\n\n/**\n * Synthetic error thrown by `MemoryBridgeDeliveryRepo.insertDelivery` when\n * a duplicate `(event_id, trigger_id)` insert hits the simulated UNIQUE\n * constraint (BRIDGE-3).\n *\n * Carries a `constraint` field equal to the Drizzle constraint name\n * declared in BRIDGE-1's schema (`uq_bridge_delivery_event_trigger`) so\n * call sites can branch on the same discriminator regardless of which\n * backend is wired up. This matters because ADR-023 explicitly leans on\n * the constraint as the dedup mechanism in two places — outbox replay\n * and `publishAndStart` Case B — and BRIDGE-4 / BRIDGE-7 will share a\n * type-check path with BRIDGE-3-driven tests.\n *\n * The Drizzle backend (BRIDGE-4) does NOT throw this error: it uses\n * `INSERT … ON CONFLICT (event_id, trigger_id) DO NOTHING RETURNING id`\n * per the BRIDGE-4 spec recommendation, so collisions surface as an empty\n * result set rather than an exception. The error exists so the memory\n * backend can faithfully model the \"duplicate raises\" behaviour for tests\n * that want to assert the constraint actually fires.\n */\n/**\n * Thrown by `BridgeModule.onModuleInit` when `JobWorkerModule` is wired\n * alongside the bridge but its active `pools` list does not include one\n * or more of the three reserved bridge pools (`events_inbound`,\n * `events_change`, `events_outbound`).\n *\n * Without a worker polling those pools, the wrapper `job_run` rows the\n * outbox drain inserts (BRIDGE-4) sit `pending` forever — a silent\n * footgun where `eventFlow.publish(...)` returns success but no user\n * job ever spawns. The boot-time check converts that into a fail-fast.\n *\n * Operators can either (a) add `...BRIDGE_RESERVED_POOLS` to their\n * `JobWorkerModule.forRoot({ pools })` configuration so the same\n * process polls the reserved pools, or (b) run a separate worker\n * process per reserved pool for lane isolation (ADR-022 §Pool\n * isolation).\n */\nexport class BridgeReservedPoolsNotPolledError extends Error {\n override readonly name = 'BridgeReservedPoolsNotPolledError';\n constructor(public readonly missingPools: readonly string[]) {\n super(\n `BridgeModule loaded but JobWorkerModule is not polling reserved ` +\n `pool '${missingPools[0]}'. Add ...BRIDGE_RESERVED_POOLS to your ` +\n `JobWorkerModule.forRoot({ pools }) configuration. Missing pools: ` +\n `${missingPools.join(', ')}. (Bridge-fanout wrappers will sit ` +\n `pending forever without these pollers.)`,\n );\n }\n}\n\nexport class UniqueConstraintError extends Error {\n override readonly name = 'UniqueConstraintError';\n constructor(\n public readonly constraint: string,\n public readonly eventId: string,\n public readonly triggerId: string,\n ) {\n super(\n `UniqueConstraintError: duplicate insert into bridge_delivery for ` +\n `(event_id='${eventId}', trigger_id='${triggerId}') — violates ` +\n `constraint '${constraint}'.`,\n );\n }\n}\n"],"mappings":";AAoCO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAE9C,YAA4B,UAAkB;AAC5C;AAAA,MACE,+EAC0B,QAAQ;AAAA,IAGpC;AAN0B;AAAA,EAO5B;AAAA,EAP4B;AAAA,EADV,OAAO;AAS3B;AAuCO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAE3D,YAA4B,cAAiC;AAC3D;AAAA,MACE,yEACW,aAAa,CAAC,CAAC,4GAErB,aAAa,KAAK,IAAI,CAAC;AAAA,IAE9B;AAP0B;AAAA,EAQ5B;AAAA,EAR4B;AAAA,EADV,OAAO;AAU3B;AAEO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAE/C,YACkB,YACA,SACA,WAChB;AACA;AAAA,MACE,+EACgB,OAAO,kBAAkB,SAAS,kCACjC,UAAU;AAAA,IAC7B;AARgB;AACA;AACA;AAAA,EAOlB;AAAA,EATkB;AAAA,EACA;AAAA,EACA;AAAA,EAJA,OAAO;AAY3B;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/storage/storage.tokens.ts"],"sourcesContent":["/**\n * Injection token for the storage service.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(STORAGE) private readonly storage: IStorageService) {}\n * ```\n *\n * ADR-037: namespaced `Symbol.for(...)` key (via `tokenKey()`) so the token matches\n * by value across import boundaries (package vs vendored runtime copy).\n */\nimport { tokenKey } from '../token-key';\n\nexport const STORAGE = Symbol.for(tokenKey('storage', 'storage'));\n"],"mappings":";;;;;AAaO,IAAM,UAAU,OAAO,IAAI,SAAS,WAAW,SAAS,CAAC;","names":[]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DrizzleJobRunService
|
|
3
|
+
} from "./chunk-FBGHYQIZ.js";
|
|
4
|
+
import {
|
|
5
|
+
MemoryJobRunService
|
|
6
|
+
} from "./chunk-RDVTWIYY.js";
|
|
7
|
+
import {
|
|
8
|
+
DrizzleJobStepService
|
|
9
|
+
} from "./chunk-DV4RV2DC.js";
|
|
10
|
+
import {
|
|
11
|
+
BULLMQ_CONNECTION,
|
|
12
|
+
BULLMQ_RESOLVED_CONFIG,
|
|
13
|
+
resolveBullMqConfig
|
|
14
|
+
} from "./chunk-I6MVCB5A.js";
|
|
15
|
+
import {
|
|
16
|
+
DrizzleJobOrchestrator
|
|
17
|
+
} from "./chunk-5Y7W3XR6.js";
|
|
18
|
+
import {
|
|
19
|
+
MemoryJobOrchestrator
|
|
20
|
+
} from "./chunk-4RFHUZXU.js";
|
|
21
|
+
import {
|
|
22
|
+
MemoryJobStepService
|
|
23
|
+
} from "./chunk-PNZSGAB2.js";
|
|
24
|
+
import {
|
|
25
|
+
MemoryJobStore
|
|
26
|
+
} from "./chunk-SNQ3TOWP.js";
|
|
27
|
+
import {
|
|
28
|
+
JOBS_MULTI_TENANT,
|
|
29
|
+
JOB_ORCHESTRATOR,
|
|
30
|
+
JOB_RUN_SERVICE,
|
|
31
|
+
JOB_STEP_SERVICE
|
|
32
|
+
} from "./chunk-BIO6F7YI.js";
|
|
33
|
+
import {
|
|
34
|
+
DRIZZLE
|
|
35
|
+
} from "./chunk-U64T4YZE.js";
|
|
36
|
+
import {
|
|
37
|
+
__decorateClass
|
|
38
|
+
} from "./chunk-2E224ZSN.js";
|
|
39
|
+
|
|
40
|
+
// runtime/subsystems/jobs/jobs-domain.module.ts
|
|
41
|
+
import { Module } from "@nestjs/common";
|
|
42
|
+
var JobsDomainModule = class {
|
|
43
|
+
static forRoot(opts) {
|
|
44
|
+
const multiTenant = opts.multiTenant ?? false;
|
|
45
|
+
const providers = [
|
|
46
|
+
// JOB-8 — boolean provider consumed by the four service-layer backends.
|
|
47
|
+
// Always provided (even when `multiTenant === false`) so `@Inject`
|
|
48
|
+
// always resolves; backends short-circuit the enforcement path when
|
|
49
|
+
// the value is `false`. See `jobs-domain.tokens.ts` for the claim-loop
|
|
50
|
+
// cross-tenant-by-design decision.
|
|
51
|
+
{ provide: JOBS_MULTI_TENANT, useValue: multiTenant }
|
|
52
|
+
];
|
|
53
|
+
if (opts.backend === "memory") {
|
|
54
|
+
const store = new MemoryJobStore();
|
|
55
|
+
providers.push({ provide: MemoryJobStore, useValue: store });
|
|
56
|
+
providers.push(MemoryJobStepService);
|
|
57
|
+
providers.push({ provide: JOB_STEP_SERVICE, useExisting: MemoryJobStepService });
|
|
58
|
+
providers.push(MemoryJobOrchestrator);
|
|
59
|
+
providers.push({ provide: JOB_ORCHESTRATOR, useExisting: MemoryJobOrchestrator });
|
|
60
|
+
providers.push(MemoryJobRunService);
|
|
61
|
+
providers.push({ provide: JOB_RUN_SERVICE, useExisting: MemoryJobRunService });
|
|
62
|
+
} else if (opts.backend === "bullmq") {
|
|
63
|
+
const resolved = resolveBullMqConfig(opts.extensions?.bullmq);
|
|
64
|
+
providers.push({ provide: BULLMQ_CONNECTION, useValue: resolved.connection });
|
|
65
|
+
providers.push({ provide: BULLMQ_RESOLVED_CONFIG, useValue: resolved });
|
|
66
|
+
providers.push({
|
|
67
|
+
provide: JOB_ORCHESTRATOR,
|
|
68
|
+
useFactory: async (...args) => {
|
|
69
|
+
const specifier = "./job-orchestrator.bullmq-backend";
|
|
70
|
+
const mod = await import(specifier);
|
|
71
|
+
return new mod.BullMQJobOrchestrator(...args);
|
|
72
|
+
},
|
|
73
|
+
// The bullmq orchestrator constructor mirrors DrizzleJobOrchestrator's
|
|
74
|
+
// injection list: DRIZZLE + JOBS_MULTI_TENANT + the resolved BullMQ
|
|
75
|
+
// tokens. Importing token references would force a static dep on the
|
|
76
|
+
// tokens file in this module's import graph; using the existing
|
|
77
|
+
// symbols already in scope is sufficient.
|
|
78
|
+
inject: [DRIZZLE, JOBS_MULTI_TENANT, BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG]
|
|
79
|
+
});
|
|
80
|
+
providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });
|
|
81
|
+
providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });
|
|
82
|
+
} else {
|
|
83
|
+
providers.push({ provide: JOB_ORCHESTRATOR, useClass: DrizzleJobOrchestrator });
|
|
84
|
+
providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });
|
|
85
|
+
providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });
|
|
86
|
+
}
|
|
87
|
+
const exports = [
|
|
88
|
+
JOB_ORCHESTRATOR,
|
|
89
|
+
JOB_RUN_SERVICE,
|
|
90
|
+
JOB_STEP_SERVICE,
|
|
91
|
+
JOBS_MULTI_TENANT
|
|
92
|
+
];
|
|
93
|
+
if (opts.backend === "bullmq") {
|
|
94
|
+
exports.push(BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
module: JobsDomainModule,
|
|
98
|
+
global: true,
|
|
99
|
+
providers,
|
|
100
|
+
exports
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
JobsDomainModule = __decorateClass([
|
|
105
|
+
Module({})
|
|
106
|
+
], JobsDomainModule);
|
|
107
|
+
|
|
108
|
+
export {
|
|
109
|
+
JobsDomainModule
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=chunk-O37C3YE6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/jobs/jobs-domain.module.ts"],"sourcesContent":["/**\n * JobsDomainModule — `DynamicModule.forRoot({ backend })` factory wiring\n * the three jobs-domain protocol tokens to a backend implementation\n * (ADR-022, JOB-5).\n *\n * Mirrors `EventsModule.forRoot()` exactly:\n * - `global: true` so consumer entity modules don't have to import this\n * individually — `JOB_ORCHESTRATOR` / `JOB_RUN_SERVICE` /\n * `JOB_STEP_SERVICE` are available project-wide.\n * - One backend at a time (Drizzle for production, Memory for tests).\n *\n * Backend swappability follows the core/extension protocol from CLAUDE.md:\n * the three tokens are the **core contract**; backend-specific tunables\n * live under `extensions.<backend>` so opting into a feature is explicit\n * and the type system reserves the slot.\n */\nimport { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport { DRIZZLE } from '../../constants/tokens';\nimport {\n JOB_ORCHESTRATOR,\n JOB_RUN_SERVICE,\n JOB_STEP_SERVICE,\n JOBS_MULTI_TENANT,\n} from './jobs-domain.tokens';\nimport { DrizzleJobOrchestrator } from './job-orchestrator.drizzle-backend';\nimport { DrizzleJobRunService } from './job-run-service.drizzle-backend';\nimport { DrizzleJobStepService } from './job-step-service.drizzle-backend';\n// #6 — `BullMQJobOrchestrator` is lazy-loaded only when `backend: 'bullmq'`\n// is selected. The backend file is filtered out of drizzle/memory installs\n// (see `backendFileFilter`); a non-literal dynamic import below sidesteps\n// consumer-side tsc resolution of an absent file.\nimport { MemoryJobOrchestrator } from './job-orchestrator.memory-backend';\nimport { MemoryJobRunService } from './job-run-service.memory-backend';\nimport { MemoryJobStepService } from './job-step-service.memory-backend';\nimport { MemoryJobStore } from './memory-job-store';\nimport {\n BULLMQ_CONNECTION,\n BULLMQ_RESOLVED_CONFIG,\n resolveBullMqConfig,\n type BullMqExtensionsConfig,\n} from './bullmq.config';\n\n/**\n * Drizzle backend extensions surface. None are wired into the Drizzle\n * orchestrator yet — this is the **typed reservation** for the LISTEN/NOTIFY\n * + tunable poll-interval extensions called out in ADR-022. App code\n * passing these today is parsed but not yet dispatched; when the\n * Drizzle orchestrator grows the consumer hooks, opt-in code paths will\n * read directly from these fields.\n */\nexport interface DrizzleBackendExtensions {\n /** Use Postgres LISTEN/NOTIFY to wake the polling loop. Default false. */\n listenNotify?: boolean;\n /** Polling interval when LISTEN/NOTIFY is off (ms). Default 1000. */\n pollIntervalMs?: number;\n}\n\nexport interface JobsDomainModuleOptions {\n backend: 'drizzle' | 'memory' | 'bullmq';\n /**\n * Backend-specific extensions. Only the matching backend's extensions\n * are read at boot; non-matching keys are ignored. This is the\n * core/extension protocol surface — see CLAUDE.md.\n */\n extensions?: {\n drizzle?: DrizzleBackendExtensions;\n /**\n * BullMQ backend extensions (BULLMQ-1). Snake_case mirrors the YAML\n * under `jobs.extensions.bullmq`. `redis_url` falls back to\n * `process.env.REDIS_URL` then `redis://localhost:6379`.\n */\n bullmq?: BullMqExtensionsConfig;\n };\n /** Multi-tenancy opt-in. Wired by JOB-8; module signature stays stable. */\n multiTenant?: boolean;\n}\n\n@Module({})\nexport class JobsDomainModule {\n static forRoot(opts: JobsDomainModuleOptions): DynamicModule {\n const multiTenant = opts.multiTenant ?? false;\n\n const providers: Provider[] = [\n // JOB-8 — boolean provider consumed by the four service-layer backends.\n // Always provided (even when `multiTenant === false`) so `@Inject`\n // always resolves; backends short-circuit the enforcement path when\n // the value is `false`. See `jobs-domain.tokens.ts` for the claim-loop\n // cross-tenant-by-design decision.\n { provide: JOBS_MULTI_TENANT, useValue: multiTenant },\n ];\n\n if (opts.backend === 'memory') {\n // The store is a plain class — wired as a singleton `useValue` so\n // unit tests can pull it out via `.get(MemoryJobStore)` for direct\n // assertions (matches the access pattern in JOB-4 specs).\n const store = new MemoryJobStore();\n providers.push({ provide: MemoryJobStore, useValue: store });\n providers.push(MemoryJobStepService);\n providers.push({ provide: JOB_STEP_SERVICE, useExisting: MemoryJobStepService });\n providers.push(MemoryJobOrchestrator);\n providers.push({ provide: JOB_ORCHESTRATOR, useExisting: MemoryJobOrchestrator });\n providers.push(MemoryJobRunService);\n providers.push({ provide: JOB_RUN_SERVICE, useExisting: MemoryJobRunService });\n } else if (opts.backend === 'bullmq') {\n // BULLMQ-1 — BullMQ orchestrator over a Postgres source of truth. The\n // run/step services stay Drizzle (domain reads + `listForScope` are\n // Postgres queries, unchanged per spec). Only the orchestrator's\n // claim/dispatch half swaps to BullMQ.\n //\n // #6 — the bullmq backend module is filtered out of drizzle/memory\n // installs (no `bullmq` peer dep, no consumer-side tsc compile of an\n // unused file). The factory below dynamic-imports it via a non-literal\n // specifier so TS treats the module type as `any` and never tries to\n // resolve the absent file on a drizzle/memory consumer.\n const resolved = resolveBullMqConfig(opts.extensions?.bullmq);\n providers.push({ provide: BULLMQ_CONNECTION, useValue: resolved.connection });\n providers.push({ provide: BULLMQ_RESOLVED_CONFIG, useValue: resolved });\n providers.push({\n provide: JOB_ORCHESTRATOR,\n useFactory: async (...args: unknown[]): Promise<object> => {\n const specifier = './job-orchestrator.bullmq-backend';\n const mod = (await import(specifier)) as {\n BullMQJobOrchestrator: new (...args: unknown[]) => object;\n };\n return new mod.BullMQJobOrchestrator(...args);\n },\n // The bullmq orchestrator constructor mirrors DrizzleJobOrchestrator's\n // injection list: DRIZZLE + JOBS_MULTI_TENANT + the resolved BullMQ\n // tokens. Importing token references would force a static dep on the\n // tokens file in this module's import graph; using the existing\n // symbols already in scope is sufficient.\n inject: [DRIZZLE, JOBS_MULTI_TENANT, BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG],\n });\n providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });\n providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });\n } else {\n providers.push({ provide: JOB_ORCHESTRATOR, useClass: DrizzleJobOrchestrator });\n providers.push({ provide: JOB_RUN_SERVICE, useClass: DrizzleJobRunService });\n providers.push({ provide: JOB_STEP_SERVICE, useClass: DrizzleJobStepService });\n }\n\n const exports = [\n JOB_ORCHESTRATOR,\n JOB_RUN_SERVICE,\n JOB_STEP_SERVICE,\n JOBS_MULTI_TENANT,\n ];\n // BULLMQ-1 — only export the BullMQ tokens when they were actually\n // provided. Nest throws \"exported but not provided\" otherwise. Exported so\n // JobWorkerModule (which imports this module) can read the resolved\n // connection/config to spawn BullMQ workers.\n if (opts.backend === 'bullmq') {\n exports.push(BULLMQ_CONNECTION, BULLMQ_RESOLVED_CONFIG);\n }\n\n return {\n module: JobsDomainModule,\n global: true,\n providers,\n exports,\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,SAAS,cAAiD;AA8DnD,IAAM,mBAAN,MAAuB;AAAA,EAC5B,OAAO,QAAQ,MAA8C;AAC3D,UAAM,cAAc,KAAK,eAAe;AAExC,UAAM,YAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAM5B,EAAE,SAAS,mBAAmB,UAAU,YAAY;AAAA,IACtD;AAEA,QAAI,KAAK,YAAY,UAAU;AAI7B,YAAM,QAAQ,IAAI,eAAe;AACjC,gBAAU,KAAK,EAAE,SAAS,gBAAgB,UAAU,MAAM,CAAC;AAC3D,gBAAU,KAAK,oBAAoB;AACnC,gBAAU,KAAK,EAAE,SAAS,kBAAkB,aAAa,qBAAqB,CAAC;AAC/E,gBAAU,KAAK,qBAAqB;AACpC,gBAAU,KAAK,EAAE,SAAS,kBAAkB,aAAa,sBAAsB,CAAC;AAChF,gBAAU,KAAK,mBAAmB;AAClC,gBAAU,KAAK,EAAE,SAAS,iBAAiB,aAAa,oBAAoB,CAAC;AAAA,IAC/E,WAAW,KAAK,YAAY,UAAU;AAWpC,YAAM,WAAW,oBAAoB,KAAK,YAAY,MAAM;AAC5D,gBAAU,KAAK,EAAE,SAAS,mBAAmB,UAAU,SAAS,WAAW,CAAC;AAC5E,gBAAU,KAAK,EAAE,SAAS,wBAAwB,UAAU,SAAS,CAAC;AACtE,gBAAU,KAAK;AAAA,QACb,SAAS;AAAA,QACT,YAAY,UAAU,SAAqC;AACzD,gBAAM,YAAY;AAClB,gBAAM,MAAO,MAAM,OAAO;AAG1B,iBAAO,IAAI,IAAI,sBAAsB,GAAG,IAAI;AAAA,QAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMA,QAAQ,CAAC,SAAS,mBAAmB,mBAAmB,sBAAsB;AAAA,MAChF,CAAC;AACD,gBAAU,KAAK,EAAE,SAAS,iBAAiB,UAAU,qBAAqB,CAAC;AAC3E,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,sBAAsB,CAAC;AAAA,IAC/E,OAAO;AACL,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,uBAAuB,CAAC;AAC9E,gBAAU,KAAK,EAAE,SAAS,iBAAiB,UAAU,qBAAqB,CAAC;AAC3E,gBAAU,KAAK,EAAE,SAAS,kBAAkB,UAAU,sBAAsB,CAAC;AAAA,IAC/E;AAEA,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAKA,QAAI,KAAK,YAAY,UAAU;AAC7B,cAAQ,KAAK,mBAAmB,sBAAsB;AAAA,IACxD;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AApFa,mBAAN;AAAA,EADN,OAAO,CAAC,CAAC;AAAA,GACG;","names":[]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// runtime/subsystems/events/domain-events.schema.ts
|
|
2
|
+
import {
|
|
3
|
+
check,
|
|
4
|
+
index,
|
|
5
|
+
jsonb,
|
|
6
|
+
pgTable,
|
|
7
|
+
text,
|
|
8
|
+
timestamp,
|
|
9
|
+
uuid
|
|
10
|
+
} from "drizzle-orm/pg-core";
|
|
11
|
+
import { sql } from "drizzle-orm";
|
|
12
|
+
var domainEvents = pgTable(
|
|
13
|
+
"domain_events",
|
|
14
|
+
{
|
|
15
|
+
id: uuid("id").primaryKey(),
|
|
16
|
+
type: text("type").notNull(),
|
|
17
|
+
aggregateId: text("aggregate_id").notNull(),
|
|
18
|
+
aggregateType: text("aggregate_type").notNull(),
|
|
19
|
+
payload: jsonb("payload").notNull().$type(),
|
|
20
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
21
|
+
processedAt: timestamp("processed_at", { withTimezone: true }),
|
|
22
|
+
/** Lifecycle status: pending | processed | failed */
|
|
23
|
+
status: text("status").notNull().default("pending"),
|
|
24
|
+
/** Error message from the last failed dispatch attempt. */
|
|
25
|
+
error: text("error"),
|
|
26
|
+
metadata: jsonb("metadata").$type(),
|
|
27
|
+
/** Routing pool (e.g. `events_inbound`, `events_change`, `events_outbound`). Populated by DrizzleEventBus.publish() in EVT-4. NULL when `tier='audit'`. */
|
|
28
|
+
pool: text("pool"),
|
|
29
|
+
/** Routing direction: `inbound` | `change` | `outbound`. Populated by DrizzleEventBus.publish() in EVT-4. NULL when `tier='audit'`. */
|
|
30
|
+
direction: text("direction"),
|
|
31
|
+
/**
|
|
32
|
+
* Event tier: `'domain'` (default) or `'audit'`. Audit-tier rows are
|
|
33
|
+
* observability-only and have null `pool`/`direction` by construction —
|
|
34
|
+
* enforced by the `domain_events_tier_routing_check` CHECK constraint
|
|
35
|
+
* declared below. (AUDIT-1)
|
|
36
|
+
*/
|
|
37
|
+
tier: text("tier").notNull().default("domain"),
|
|
38
|
+
// conditional: emitted only when events.multi_tenant: true
|
|
39
|
+
tenantId: text("tenant_id")
|
|
40
|
+
},
|
|
41
|
+
(t) => ({
|
|
42
|
+
/** Polling drain filter (existing — promoted from comment to declaration in EVT-1). */
|
|
43
|
+
idxDomainEventsStatusOccurredAt: index("idx_domain_events_status_occurred_at").on(
|
|
44
|
+
t.status,
|
|
45
|
+
t.occurredAt
|
|
46
|
+
),
|
|
47
|
+
/** Event replay per aggregate (existing — promoted from comment to declaration in EVT-1). */
|
|
48
|
+
idxDomainEventsAggregate: index("idx_domain_events_aggregate").on(
|
|
49
|
+
t.aggregateId,
|
|
50
|
+
t.aggregateType
|
|
51
|
+
),
|
|
52
|
+
/** Per-pool drain filter (EVT-1). Enables DrizzleEventBus to drain a single pool without scanning all events. */
|
|
53
|
+
idxDomainEventsPoolStatusOccurredAt: index(
|
|
54
|
+
"idx_domain_events_pool_status_occurred_at"
|
|
55
|
+
).on(t.pool, t.status, t.occurredAt),
|
|
56
|
+
/** Per-tier filter (AUDIT-1). Backs the observability viewer's tier toggle. */
|
|
57
|
+
idxDomainEventsTierStatusOccurredAt: index(
|
|
58
|
+
"idx_domain_events_tier_status_occurred_at"
|
|
59
|
+
).on(t.tier, t.status, t.occurredAt),
|
|
60
|
+
/**
|
|
61
|
+
* Tier ↔ routing-fields invariant (AUDIT-1):
|
|
62
|
+
* - `tier` is one of `'domain' | 'audit'`.
|
|
63
|
+
* - `tier='audit'` ⇔ `pool IS NULL AND direction IS NULL`.
|
|
64
|
+
* - `tier='domain'` ⇒ `pool` and `direction` are populated (the
|
|
65
|
+
* DrizzleEventBus inserts always supply them; the bus stamps them
|
|
66
|
+
* in AUDIT-3).
|
|
67
|
+
*/
|
|
68
|
+
tierRoutingCheck: check(
|
|
69
|
+
"domain_events_tier_routing_check",
|
|
70
|
+
sql`${t.tier} in ('domain','audit') AND ((${t.tier} = 'audit') = (${t.pool} is null and ${t.direction} is null))`
|
|
71
|
+
)
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
export {
|
|
76
|
+
domainEvents
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=chunk-OFRRBC7M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/events/domain-events.schema.ts"],"sourcesContent":["/**\n * Drizzle schema for the domain_events outbox table.\n *\n * This table backs the DrizzleEventBus. Events are inserted within the\n * same database transaction as the domain write (outbox pattern). A\n * polling process reads unprocessed rows and dispatches to subscribers.\n *\n * First-class routing columns (EVT-1):\n * - `pool` — populated by DrizzleEventBus.publish() (EVT-4); enables\n * pool-filtered drain queries without unpacking metadata JSON.\n * NULL when `tier='audit'` (audit events are not routed).\n * - `direction` — `inbound` | `change` | `outbound`; mirrors the routing\n * dimension used by jobs' reserved `events_inbound` /\n * `events_change` / `events_outbound` pools.\n * NULL when `tier='audit'`.\n * - `tenant_id` — conditional: emitted only when `events.multi_tenant: true`\n * in `codegen.config.yaml`. The runtime source declares it\n * unconditionally; EVT-8's scaffold template handles the\n * config-driven include/exclude.\n *\n * Audit-tier column (AUDIT-1):\n * - `tier` — `'domain'` | `'audit'`. Defaults to `'domain'`. Audit-tier\n * rows are observability-only (subscribers may observe but\n * the bridge MUST NOT spawn jobs from them); they have null\n * `pool` and `direction` by construction. The CHECK\n * constraint `domain_events_tier_routing_check` enforces\n * `tier='audit' ⇔ (pool IS NULL AND direction IS NULL)`.\n *\n * The `metadata` JSON column continues to carry these values for protocol\n * stability; the first-class columns are an optimization for drain filtering.\n *\n * Indexes (declared below in the index callback):\n * - (status, occurred_at) — polling drain filter\n * - (aggregate_id, aggregate_type) — event replay per aggregate\n * - (pool, status, occurred_at) — per-pool drain filter (EVT-1)\n * - (tier, status, occurred_at) — per-tier filter for the observability\n * viewer's tier toggle (AUDIT-1).\n */\nimport {\n check,\n index,\n jsonb,\n pgTable,\n text,\n timestamp,\n uuid,\n} from 'drizzle-orm/pg-core';\nimport { sql } from 'drizzle-orm';\nimport type { InferSelectModel } from 'drizzle-orm';\n\nexport const domainEvents = pgTable(\n 'domain_events',\n {\n id: uuid('id').primaryKey(),\n type: text('type').notNull(),\n aggregateId: text('aggregate_id').notNull(),\n aggregateType: text('aggregate_type').notNull(),\n payload: jsonb('payload').notNull().$type<Record<string, unknown>>(),\n occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(),\n processedAt: timestamp('processed_at', { withTimezone: true }),\n /** Lifecycle status: pending | processed | failed */\n status: text('status').notNull().default('pending'),\n /** Error message from the last failed dispatch attempt. */\n error: text('error'),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n /** Routing pool (e.g. `events_inbound`, `events_change`, `events_outbound`). Populated by DrizzleEventBus.publish() in EVT-4. NULL when `tier='audit'`. */\n pool: text('pool'),\n /** Routing direction: `inbound` | `change` | `outbound`. Populated by DrizzleEventBus.publish() in EVT-4. NULL when `tier='audit'`. */\n direction: text('direction'),\n /**\n * Event tier: `'domain'` (default) or `'audit'`. Audit-tier rows are\n * observability-only and have null `pool`/`direction` by construction —\n * enforced by the `domain_events_tier_routing_check` CHECK constraint\n * declared below. (AUDIT-1)\n */\n tier: text('tier').notNull().default('domain'),\n // conditional: emitted only when events.multi_tenant: true\n tenantId: text('tenant_id'),\n },\n (t) => ({\n /** Polling drain filter (existing — promoted from comment to declaration in EVT-1). */\n idxDomainEventsStatusOccurredAt: index('idx_domain_events_status_occurred_at').on(\n t.status,\n t.occurredAt,\n ),\n /** Event replay per aggregate (existing — promoted from comment to declaration in EVT-1). */\n idxDomainEventsAggregate: index('idx_domain_events_aggregate').on(\n t.aggregateId,\n t.aggregateType,\n ),\n /** Per-pool drain filter (EVT-1). Enables DrizzleEventBus to drain a single pool without scanning all events. */\n idxDomainEventsPoolStatusOccurredAt: index(\n 'idx_domain_events_pool_status_occurred_at',\n ).on(t.pool, t.status, t.occurredAt),\n /** Per-tier filter (AUDIT-1). Backs the observability viewer's tier toggle. */\n idxDomainEventsTierStatusOccurredAt: index(\n 'idx_domain_events_tier_status_occurred_at',\n ).on(t.tier, t.status, t.occurredAt),\n /**\n * Tier ↔ routing-fields invariant (AUDIT-1):\n * - `tier` is one of `'domain' | 'audit'`.\n * - `tier='audit'` ⇔ `pool IS NULL AND direction IS NULL`.\n * - `tier='domain'` ⇒ `pool` and `direction` are populated (the\n * DrizzleEventBus inserts always supply them; the bus stamps them\n * in AUDIT-3).\n */\n tierRoutingCheck: check(\n 'domain_events_tier_routing_check',\n sql`${t.tier} in ('domain','audit') AND ((${t.tier} = 'audit') = (${t.pool} is null and ${t.direction} is null))`,\n ),\n }),\n);\n\nexport type DomainEventRecord = InferSelectModel<typeof domainEvents>;\n"],"mappings":";AAsCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAW;AAGb,IAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW;AAAA,IAC1B,MAAM,KAAK,MAAM,EAAE,QAAQ;AAAA,IAC3B,aAAa,KAAK,cAAc,EAAE,QAAQ;AAAA,IAC1C,eAAe,KAAK,gBAAgB,EAAE,QAAQ;AAAA,IAC9C,SAAS,MAAM,SAAS,EAAE,QAAQ,EAAE,MAA+B;AAAA,IACnE,YAAY,UAAU,eAAe,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ;AAAA,IACrE,aAAa,UAAU,gBAAgB,EAAE,cAAc,KAAK,CAAC;AAAA;AAAA,IAE7D,QAAQ,KAAK,QAAQ,EAAE,QAAQ,EAAE,QAAQ,SAAS;AAAA;AAAA,IAElD,OAAO,KAAK,OAAO;AAAA,IACnB,UAAU,MAAM,UAAU,EAAE,MAA+B;AAAA;AAAA,IAE3D,MAAM,KAAK,MAAM;AAAA;AAAA,IAEjB,WAAW,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAO3B,MAAM,KAAK,MAAM,EAAE,QAAQ,EAAE,QAAQ,QAAQ;AAAA;AAAA,IAE7C,UAAU,KAAK,WAAW;AAAA,EAC5B;AAAA,EACA,CAAC,OAAO;AAAA;AAAA,IAEN,iCAAiC,MAAM,sCAAsC,EAAE;AAAA,MAC7E,EAAE;AAAA,MACF,EAAE;AAAA,IACJ;AAAA;AAAA,IAEA,0BAA0B,MAAM,6BAA6B,EAAE;AAAA,MAC7D,EAAE;AAAA,MACF,EAAE;AAAA,IACJ;AAAA;AAAA,IAEA,qCAAqC;AAAA,MACnC;AAAA,IACF,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;AAAA;AAAA,IAEnC,qCAAqC;AAAA,MACnC;AAAA,IACF,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASnC,kBAAkB;AAAA,MAChB;AAAA,MACA,MAAM,EAAE,IAAI,gCAAgC,EAAE,IAAI,kBAAkB,EAAE,IAAI,gBAAgB,EAAE,SAAS;AAAA,IACvG;AAAA,EACF;AACF;","names":[]}
|