@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,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertTenantId
|
|
3
|
+
} from "./chunk-6DWFJNIK.js";
|
|
4
|
+
import {
|
|
5
|
+
bridgeDelivery
|
|
6
|
+
} from "./chunk-2TVVBC53.js";
|
|
7
|
+
import {
|
|
8
|
+
BRIDGE_MULTI_TENANT
|
|
9
|
+
} from "./chunk-4LH67P4U.js";
|
|
10
|
+
import {
|
|
11
|
+
DRIZZLE
|
|
12
|
+
} from "./chunk-U64T4YZE.js";
|
|
13
|
+
import {
|
|
14
|
+
__decorateClass,
|
|
15
|
+
__decorateParam
|
|
16
|
+
} from "./chunk-2E224ZSN.js";
|
|
17
|
+
|
|
18
|
+
// runtime/subsystems/bridge/bridge-delivery.drizzle-backend.ts
|
|
19
|
+
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
20
|
+
import { eq, and, gte, isNull, sql } from "drizzle-orm";
|
|
21
|
+
var DrizzleBridgeDeliveryRepo = class {
|
|
22
|
+
constructor(db, multiTenant = false) {
|
|
23
|
+
this.db = db;
|
|
24
|
+
this.multiTenant = multiTenant;
|
|
25
|
+
}
|
|
26
|
+
db;
|
|
27
|
+
multiTenant;
|
|
28
|
+
async insertDelivery(row, tx) {
|
|
29
|
+
assertTenantId(
|
|
30
|
+
"DrizzleBridgeDeliveryRepo.insertDelivery",
|
|
31
|
+
this.multiTenant,
|
|
32
|
+
row.tenantId
|
|
33
|
+
);
|
|
34
|
+
const client = tx ?? this.db;
|
|
35
|
+
await client.insert(bridgeDelivery).values(row).onConflictDoNothing({
|
|
36
|
+
target: [bridgeDelivery.eventId, bridgeDelivery.triggerId]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async findDelivery(eventId, triggerId) {
|
|
40
|
+
const rows = await this.db.select().from(bridgeDelivery).where(
|
|
41
|
+
and(
|
|
42
|
+
eq(bridgeDelivery.eventId, eventId),
|
|
43
|
+
eq(bridgeDelivery.triggerId, triggerId)
|
|
44
|
+
)
|
|
45
|
+
).limit(1);
|
|
46
|
+
return rows[0] ?? null;
|
|
47
|
+
}
|
|
48
|
+
async findDeliveryById(id) {
|
|
49
|
+
const rows = await this.db.select().from(bridgeDelivery).where(eq(bridgeDelivery.id, id)).limit(1);
|
|
50
|
+
return rows[0] ?? null;
|
|
51
|
+
}
|
|
52
|
+
async markDelivered(id, userRunId, tx) {
|
|
53
|
+
const client = tx ?? this.db;
|
|
54
|
+
await client.update(bridgeDelivery).set({
|
|
55
|
+
status: "delivered",
|
|
56
|
+
userRunId,
|
|
57
|
+
deliveredAt: /* @__PURE__ */ new Date()
|
|
58
|
+
}).where(eq(bridgeDelivery.id, id));
|
|
59
|
+
}
|
|
60
|
+
async markSkipped(id, reason, tx) {
|
|
61
|
+
const client = tx ?? this.db;
|
|
62
|
+
await client.update(bridgeDelivery).set({ status: "skipped", skipReason: reason }).where(eq(bridgeDelivery.id, id));
|
|
63
|
+
}
|
|
64
|
+
async markFailed(id, error, tx) {
|
|
65
|
+
const client = tx ?? this.db;
|
|
66
|
+
await client.update(bridgeDelivery).set({ status: "failed", error }).where(eq(bridgeDelivery.id, id));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Observability read — see `IJobBridge.getStatusHistogram` JSDoc for the
|
|
70
|
+
* tenant-filter and windowHours contract.
|
|
71
|
+
*
|
|
72
|
+
* Tenant-filter note: this method intentionally does NOT call
|
|
73
|
+
* `assertTenantId`. The write methods on this repo (`insertDelivery`)
|
|
74
|
+
* treat `tenantId === undefined` as a misconfiguration and fail fast.
|
|
75
|
+
* Reads are different — `undefined` is the supported "cross-tenant
|
|
76
|
+
* admin view" mode that OBS-5 uses to render a framework-wide health
|
|
77
|
+
* panel. Callers that need strict tenant scoping pass an explicit
|
|
78
|
+
* string or `null`.
|
|
79
|
+
*
|
|
80
|
+
* Cast note: `count(*)::int` is applied in SQL so the node-pg driver
|
|
81
|
+
* returns a `number` instead of the default `bigint → string` for
|
|
82
|
+
* `count(*)`. Don't relax this cast — consumers (and the protocol)
|
|
83
|
+
* type the result as `number`.
|
|
84
|
+
*/
|
|
85
|
+
async getStatusHistogram(windowHours, tenantId) {
|
|
86
|
+
if (!Number.isFinite(windowHours) || windowHours <= 0) {
|
|
87
|
+
throw new RangeError("windowHours must be positive");
|
|
88
|
+
}
|
|
89
|
+
const cutoff = sql`now() - make_interval(hours => ${windowHours})`;
|
|
90
|
+
const conditions = [gte(bridgeDelivery.attemptedAt, cutoff)];
|
|
91
|
+
if (tenantId === null) {
|
|
92
|
+
conditions.push(isNull(bridgeDelivery.tenantId));
|
|
93
|
+
} else if (typeof tenantId === "string") {
|
|
94
|
+
conditions.push(eq(bridgeDelivery.tenantId, tenantId));
|
|
95
|
+
}
|
|
96
|
+
const rows = await this.db.select({
|
|
97
|
+
status: bridgeDelivery.status,
|
|
98
|
+
count: sql`count(*)::int`
|
|
99
|
+
}).from(bridgeDelivery).where(and(...conditions)).groupBy(bridgeDelivery.status);
|
|
100
|
+
const histogram = {
|
|
101
|
+
pending: 0,
|
|
102
|
+
delivered: 0,
|
|
103
|
+
skipped: 0,
|
|
104
|
+
failed: 0
|
|
105
|
+
};
|
|
106
|
+
for (const row of rows) {
|
|
107
|
+
histogram[row.status] = Number(row.count);
|
|
108
|
+
}
|
|
109
|
+
return histogram;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
DrizzleBridgeDeliveryRepo = __decorateClass([
|
|
113
|
+
Injectable(),
|
|
114
|
+
__decorateParam(0, Inject(DRIZZLE)),
|
|
115
|
+
__decorateParam(1, Optional()),
|
|
116
|
+
__decorateParam(1, Inject(BRIDGE_MULTI_TENANT))
|
|
117
|
+
], DrizzleBridgeDeliveryRepo);
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
DrizzleBridgeDeliveryRepo
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=chunk-K2I6XIK5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/bridge/bridge-delivery.drizzle-backend.ts"],"sourcesContent":["/**\n * DrizzleBridgeDeliveryRepo — Postgres implementation of `IJobBridge`\n * (BRIDGE-4, ADR-023 Phase 2).\n *\n * Behavioral twin of `MemoryBridgeDeliveryRepo` (BRIDGE-3). The key\n * difference is `insertDelivery`: where the memory backend throws\n * `UniqueConstraintError` on a duplicate `(event_id, trigger_id)`, the\n * Drizzle backend uses `INSERT … ON CONFLICT (event_id, trigger_id) DO\n * NOTHING` and surfaces the dedup as a silent no-op. This matches the\n * BRIDGE-4 spec recommendation — a thrown error inside the per-event tx\n * would abort sibling triggers, which is exactly the failure mode the\n * facade's Case B pre-write was designed to prevent.\n *\n * Tests that need to assert \"the constraint fired\" use `findDelivery` to\n * confirm the existing row is the facade-eager pre-write (or the prior\n * drain attempt's row), not the one this call tried to insert. The\n * `UniqueConstraintError` branch from BRIDGE-3 is the memory-backend\n * fidelity path; the Drizzle backend models the same idempotency through\n * SQL semantics rather than a thrown error.\n *\n * The other four methods (`findDelivery`, `findDeliveryById`,\n * `mark{Delivered,Skipped,Failed}`) are straightforward\n * `SELECT … LIMIT 1` / `UPDATE … WHERE id = ?` queries.\n */\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { eq, and, gte, isNull, sql } from 'drizzle-orm';\n\nimport { DRIZZLE } from '../../constants/tokens';\nimport type { DrizzleClient } from '../../types/drizzle';\nimport type { DrizzleTransaction } from '../events/event-bus.protocol';\n\nimport { bridgeDelivery } from './bridge-delivery.schema';\nimport type { BridgeDeliveryRecord } from './bridge-delivery.schema';\nimport type {\n BridgeDeliveryInsert,\n IJobBridge,\n StatusHistogram,\n} from './bridge.protocol';\nimport { assertTenantId } from './assert-tenant-id';\nimport { BRIDGE_MULTI_TENANT } from './bridge.tokens';\n\n@Injectable()\nexport class DrizzleBridgeDeliveryRepo implements IJobBridge {\n constructor(\n @Inject(DRIZZLE) private readonly db: DrizzleClient,\n /**\n * Site (c) of the three ADR-023 §Multi-tenancy enforcement sites.\n * `@Optional()` so unit tests / non-bridge mounts that don't provide\n * the token still construct the repo cleanly; defaults to `false`,\n * which makes `assertTenantId` a no-op.\n */\n @Optional()\n @Inject(BRIDGE_MULTI_TENANT)\n private readonly multiTenant: boolean = false,\n ) {}\n\n async insertDelivery(\n row: BridgeDeliveryInsert,\n tx?: DrizzleTransaction,\n ): Promise<void> {\n // Multi-tenancy gate — last-line defense. Even if callers skipped\n // sites (a) `EventFlowService.publishAndStart` and (b)\n // `BridgeDeliveryHandler.run`, a direct repo call still fails fast\n // BEFORE any SQL is issued.\n assertTenantId(\n 'DrizzleBridgeDeliveryRepo.insertDelivery',\n this.multiTenant,\n row.tenantId,\n );\n const client = (tx ?? this.db) as DrizzleClient;\n // ON CONFLICT DO NOTHING — surfaces dedup as silent no-op so the\n // per-event tx stays atomic across sibling triggers. RETURNING is\n // omitted here: the public IJobBridge contract is `Promise<void>`,\n // and the drain hook (BRIDGE-4) uses its own\n // `tx.insert(...).onConflictDoNothing().returning({id})` pattern\n // when it needs the rowcount discriminator. See class-level JSDoc.\n await client\n .insert(bridgeDelivery)\n .values(row)\n .onConflictDoNothing({\n target: [bridgeDelivery.eventId, bridgeDelivery.triggerId],\n });\n }\n\n async findDelivery(\n eventId: string,\n triggerId: string,\n ): Promise<BridgeDeliveryRecord | null> {\n const rows = await this.db\n .select()\n .from(bridgeDelivery)\n .where(\n and(\n eq(bridgeDelivery.eventId, eventId),\n eq(bridgeDelivery.triggerId, triggerId),\n ),\n )\n .limit(1);\n return (rows[0] as BridgeDeliveryRecord | undefined) ?? null;\n }\n\n async findDeliveryById(id: string): Promise<BridgeDeliveryRecord | null> {\n const rows = await this.db\n .select()\n .from(bridgeDelivery)\n .where(eq(bridgeDelivery.id, id))\n .limit(1);\n return (rows[0] as BridgeDeliveryRecord | undefined) ?? null;\n }\n\n async markDelivered(\n id: string,\n userRunId: string,\n tx?: DrizzleTransaction,\n ): Promise<void> {\n const client = (tx ?? this.db) as DrizzleClient;\n await client\n .update(bridgeDelivery)\n .set({\n status: 'delivered',\n userRunId,\n deliveredAt: new Date(),\n })\n .where(eq(bridgeDelivery.id, id));\n }\n\n async markSkipped(\n id: string,\n reason: string,\n tx?: DrizzleTransaction,\n ): Promise<void> {\n const client = (tx ?? this.db) as DrizzleClient;\n await client\n .update(bridgeDelivery)\n .set({ status: 'skipped', skipReason: reason })\n .where(eq(bridgeDelivery.id, id));\n }\n\n async markFailed(\n id: string,\n error: Record<string, unknown>,\n tx?: DrizzleTransaction,\n ): Promise<void> {\n const client = (tx ?? this.db) as DrizzleClient;\n await client\n .update(bridgeDelivery)\n .set({ status: 'failed', error })\n .where(eq(bridgeDelivery.id, id));\n }\n\n /**\n * Observability read — see `IJobBridge.getStatusHistogram` JSDoc for the\n * tenant-filter and windowHours contract.\n *\n * Tenant-filter note: this method intentionally does NOT call\n * `assertTenantId`. The write methods on this repo (`insertDelivery`)\n * treat `tenantId === undefined` as a misconfiguration and fail fast.\n * Reads are different — `undefined` is the supported \"cross-tenant\n * admin view\" mode that OBS-5 uses to render a framework-wide health\n * panel. Callers that need strict tenant scoping pass an explicit\n * string or `null`.\n *\n * Cast note: `count(*)::int` is applied in SQL so the node-pg driver\n * returns a `number` instead of the default `bigint → string` for\n * `count(*)`. Don't relax this cast — consumers (and the protocol)\n * type the result as `number`.\n */\n async getStatusHistogram(\n windowHours: number,\n tenantId?: string | null,\n ): Promise<StatusHistogram> {\n if (!Number.isFinite(windowHours) || windowHours <= 0) {\n throw new RangeError('windowHours must be positive');\n }\n\n const cutoff = sql<Date>`now() - make_interval(hours => ${windowHours})`;\n\n const conditions = [gte(bridgeDelivery.attemptedAt, cutoff)];\n if (tenantId === null) {\n conditions.push(isNull(bridgeDelivery.tenantId));\n } else if (typeof tenantId === 'string') {\n conditions.push(eq(bridgeDelivery.tenantId, tenantId));\n }\n // tenantId === undefined → no tenant filter (cross-tenant view).\n\n const rows = await this.db\n .select({\n status: bridgeDelivery.status,\n count: sql<number>`count(*)::int`,\n })\n .from(bridgeDelivery)\n .where(and(...conditions))\n .groupBy(bridgeDelivery.status);\n\n const histogram: StatusHistogram = {\n pending: 0,\n delivered: 0,\n skipped: 0,\n failed: 0,\n };\n for (const row of rows) {\n // row.status is typed as the enum union; narrow is safe because the\n // enum values match StatusHistogram keys 1:1 (BRIDGE-1 schema).\n histogram[row.status as keyof StatusHistogram] = Number(row.count);\n }\n return histogram;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-KVOWSC5S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// runtime/base-classes/lifecycle-events.ts
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
var SYSTEM_FIELDS = /* @__PURE__ */ new Set([
|
|
4
|
+
"id",
|
|
5
|
+
"createdAt",
|
|
6
|
+
"updatedAt",
|
|
7
|
+
"deletedAt"
|
|
8
|
+
]);
|
|
9
|
+
function entitySnapshot(entity) {
|
|
10
|
+
const snap = {};
|
|
11
|
+
for (const [key, value] of Object.entries(entity)) {
|
|
12
|
+
if (!SYSTEM_FIELDS.has(key)) {
|
|
13
|
+
snap[key] = value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return snap;
|
|
17
|
+
}
|
|
18
|
+
function diffSnapshots(before, after) {
|
|
19
|
+
const changes = [];
|
|
20
|
+
const allKeys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
21
|
+
for (const key of allKeys) {
|
|
22
|
+
if (SYSTEM_FIELDS.has(key)) continue;
|
|
23
|
+
const oldVal = before[key];
|
|
24
|
+
const newVal = after[key];
|
|
25
|
+
if (oldVal !== newVal && JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
|
26
|
+
changes.push({ field: key, oldValue: oldVal, newValue: newVal });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return changes;
|
|
30
|
+
}
|
|
31
|
+
function buildLifecycleEvent(entityName, action, entityId, snapshot) {
|
|
32
|
+
return {
|
|
33
|
+
id: randomUUID(),
|
|
34
|
+
type: `${entityName}.${action}`,
|
|
35
|
+
aggregateId: entityId,
|
|
36
|
+
aggregateType: entityName,
|
|
37
|
+
payload: snapshot ? { snapshot } : {},
|
|
38
|
+
occurredAt: /* @__PURE__ */ new Date(),
|
|
39
|
+
metadata: { category: "lifecycle" }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function buildChangeEvents(entityName, entityId, changes) {
|
|
43
|
+
return changes.map((c) => ({
|
|
44
|
+
id: randomUUID(),
|
|
45
|
+
type: `${entityName}.field_changed`,
|
|
46
|
+
aggregateId: entityId,
|
|
47
|
+
aggregateType: entityName,
|
|
48
|
+
payload: {
|
|
49
|
+
fieldName: c.field,
|
|
50
|
+
oldValue: c.oldValue,
|
|
51
|
+
newValue: c.newValue
|
|
52
|
+
},
|
|
53
|
+
occurredAt: /* @__PURE__ */ new Date(),
|
|
54
|
+
metadata: { category: "change" }
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
async function emitSafely(eventBus, events) {
|
|
58
|
+
if (!eventBus || events.length === 0) return;
|
|
59
|
+
try {
|
|
60
|
+
if (events.length === 1) {
|
|
61
|
+
const only = events[0];
|
|
62
|
+
if (!only) return;
|
|
63
|
+
await eventBus.publish(only);
|
|
64
|
+
} else {
|
|
65
|
+
await eventBus.publishMany(events);
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
console.warn(`[lifecycle-events] failed to emit ${events.length} event(s)`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
entitySnapshot,
|
|
74
|
+
diffSnapshots,
|
|
75
|
+
buildLifecycleEvent,
|
|
76
|
+
buildChangeEvents,
|
|
77
|
+
emitSafely
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-KYR3B3OW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/base-classes/lifecycle-events.ts"],"sourcesContent":["/**\n * Lifecycle event emission for BaseService.\n *\n * Ported from pattern-stack/atoms/patterns/services/base.py — the Python\n * BaseService emits LIFECYCLE and CHANGE events on every CRUD operation.\n * This module provides the same capability for the TypeScript codegen stack.\n *\n * Design:\n * - Fire-and-forget: event emission never fails the CRUD operation.\n * - IEventBus is optional: if no EVENT_BUS is injected, emission is silently\n * skipped. This means base classes work in projects that haven't installed\n * the events subsystem.\n * - LIFECYCLE events carry an entity snapshot in payload.\n * - CHANGE events carry per-field old/new diffs.\n * - Controlled per-entity via `emitLifecycleEvents` flag (default: true).\n *\n * @deprecated EVT-7 — Lifecycle events are untyped and emit outside of the\n * CRUD transaction. New work should declare an `emits:` block on the entity\n * and publish typed domain events from use-cases via TYPED_EVENT_BUS inside\n * the same Drizzle transaction. See `docs/specs/EVT-7.md`. This helper is\n * retained for BaseService backward compatibility until all entities have\n * migrated to typed emits.\n */\n\nimport { randomUUID } from 'crypto';\nimport type { IEventBus, DomainEvent } from '../subsystems/events/event-bus.protocol';\n\n// ============================================================================\n// Event categories (subset of pattern-stack's EventCategory)\n// ============================================================================\n\nexport type EventCategory = 'lifecycle' | 'change';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** System fields excluded from entity snapshots and change diffs. */\nconst SYSTEM_FIELDS = new Set([\n\t'id',\n\t'createdAt',\n\t'updatedAt',\n\t'deletedAt',\n]);\n\n/**\n * Snapshot an entity's field values, excluding system fields.\n * Mirrors pattern-stack's `_get_entity_snapshot()`.\n */\nexport function entitySnapshot(entity: Record<string, unknown>): Record<string, unknown> {\n\tconst snap: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(entity)) {\n\t\tif (!SYSTEM_FIELDS.has(key)) {\n\t\t\tsnap[key] = value;\n\t\t}\n\t}\n\treturn snap;\n}\n\n/**\n * Diff two entity snapshots, returning per-field old/new pairs.\n * Only includes fields that actually changed.\n */\nexport function diffSnapshots(\n\tbefore: Record<string, unknown>,\n\tafter: Record<string, unknown>,\n): Array<{ field: string; oldValue: unknown; newValue: unknown }> {\n\tconst changes: Array<{ field: string; oldValue: unknown; newValue: unknown }> = [];\n\tconst allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n\tfor (const key of allKeys) {\n\t\tif (SYSTEM_FIELDS.has(key)) continue;\n\t\tconst oldVal = before[key];\n\t\tconst newVal = after[key];\n\t\t// Simple equality — good enough for primitives and nulls.\n\t\t// For deep objects, JSON.stringify comparison.\n\t\tif (oldVal !== newVal && JSON.stringify(oldVal) !== JSON.stringify(newVal)) {\n\t\t\tchanges.push({ field: key, oldValue: oldVal, newValue: newVal });\n\t\t}\n\t}\n\n\treturn changes;\n}\n\n// ============================================================================\n// Event builders\n// ============================================================================\n\nexport function buildLifecycleEvent(\n\tentityName: string,\n\taction: 'created' | 'updated' | 'deleted',\n\tentityId: string,\n\tsnapshot?: Record<string, unknown>,\n): DomainEvent {\n\treturn {\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.${action}`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: snapshot ? { snapshot } : {},\n\t\toccurredAt: new Date(),\n\t\tmetadata: { category: 'lifecycle' as EventCategory },\n\t};\n}\n\nexport function buildChangeEvents(\n\tentityName: string,\n\tentityId: string,\n\tchanges: Array<{ field: string; oldValue: unknown; newValue: unknown }>,\n): DomainEvent[] {\n\treturn changes.map((c) => ({\n\t\tid: randomUUID(),\n\t\ttype: `${entityName}.field_changed`,\n\t\taggregateId: entityId,\n\t\taggregateType: entityName,\n\t\tpayload: {\n\t\t\tfieldName: c.field,\n\t\t\toldValue: c.oldValue,\n\t\t\tnewValue: c.newValue,\n\t\t},\n\t\toccurredAt: new Date(),\n\t\tmetadata: { category: 'change' as EventCategory },\n\t}));\n}\n\n// ============================================================================\n// Emission helper (fire-and-forget)\n// ============================================================================\n\n/**\n * Emit events to the bus, swallowing errors.\n * Mirrors pattern-stack's `_emit_lifecycle_event()` try/except.\n */\nexport async function emitSafely(\n\teventBus: IEventBus | undefined,\n\tevents: DomainEvent[],\n): Promise<void> {\n\tif (!eventBus || events.length === 0) return;\n\ttry {\n\t\tif (events.length === 1) {\n\t\t\tconst only = events[0];\n\t\t\tif (!only) return;\n\t\t\tawait eventBus.publish(only);\n\t\t} else {\n\t\t\tawait eventBus.publishMany(events);\n\t\t}\n\t} catch {\n\t\t// Log but never fail the CRUD operation.\n\t\t// In production, this would use a structured logger.\n\t\tconsole.warn(`[lifecycle-events] failed to emit ${events.length} event(s)`);\n\t}\n}\n"],"mappings":";AAwBA,SAAS,kBAAkB;AAc3B,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAMM,SAAS,eAAe,QAA0D;AACxF,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,QAAI,CAAC,cAAc,IAAI,GAAG,GAAG;AAC5B,WAAK,GAAG,IAAI;AAAA,IACb;AAAA,EACD;AACA,SAAO;AACR;AAMO,SAAS,cACf,QACA,OACiE;AACjE,QAAM,UAA0E,CAAC;AACjF,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC;AAEvE,aAAW,OAAO,SAAS;AAC1B,QAAI,cAAc,IAAI,GAAG,EAAG;AAC5B,UAAM,SAAS,OAAO,GAAG;AACzB,UAAM,SAAS,MAAM,GAAG;AAGxB,QAAI,WAAW,UAAU,KAAK,UAAU,MAAM,MAAM,KAAK,UAAU,MAAM,GAAG;AAC3E,cAAQ,KAAK,EAAE,OAAO,KAAK,UAAU,QAAQ,UAAU,OAAO,CAAC;AAAA,IAChE;AAAA,EACD;AAEA,SAAO;AACR;AAMO,SAAS,oBACf,YACA,QACA,UACA,UACc;AACd,SAAO;AAAA,IACN,IAAI,WAAW;AAAA,IACf,MAAM,GAAG,UAAU,IAAI,MAAM;AAAA,IAC7B,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,IACpC,YAAY,oBAAI,KAAK;AAAA,IACrB,UAAU,EAAE,UAAU,YAA6B;AAAA,EACpD;AACD;AAEO,SAAS,kBACf,YACA,UACA,SACgB;AAChB,SAAO,QAAQ,IAAI,CAAC,OAAO;AAAA,IAC1B,IAAI,WAAW;AAAA,IACf,MAAM,GAAG,UAAU;AAAA,IACnB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,SAAS;AAAA,MACR,WAAW,EAAE;AAAA,MACb,UAAU,EAAE;AAAA,MACZ,UAAU,EAAE;AAAA,IACb;AAAA,IACA,YAAY,oBAAI,KAAK;AAAA,IACrB,UAAU,EAAE,UAAU,SAA0B;AAAA,EACjD,EAAE;AACH;AAUA,eAAsB,WACrB,UACA,QACgB;AAChB,MAAI,CAAC,YAAY,OAAO,WAAW,EAAG;AACtC,MAAI;AACH,QAAI,OAAO,WAAW,GAAG;AACxB,YAAM,OAAO,OAAO,CAAC;AACrB,UAAI,CAAC,KAAM;AACX,YAAM,SAAS,QAAQ,IAAI;AAAA,IAC5B,OAAO;AACN,YAAM,SAAS,YAAY,MAAM;AAAA,IAClC;AAAA,EACD,QAAQ;AAGP,YAAQ,KAAK,qCAAqC,OAAO,MAAM,WAAW;AAAA,EAC3E;AACD;","names":[]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// runtime/subsystems/jobs/job-run-keyset-cursor.ts
|
|
2
|
+
var DEFAULT_LIST_LIMIT = 50;
|
|
3
|
+
var MAX_LIST_LIMIT = 200;
|
|
4
|
+
function clampLimit(limit) {
|
|
5
|
+
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
6
|
+
return DEFAULT_LIST_LIMIT;
|
|
7
|
+
}
|
|
8
|
+
const floored = Math.floor(limit);
|
|
9
|
+
if (floored < 1) return 1;
|
|
10
|
+
if (floored > MAX_LIST_LIMIT) return MAX_LIST_LIMIT;
|
|
11
|
+
return floored;
|
|
12
|
+
}
|
|
13
|
+
function encodeKeysetCursor(keyset) {
|
|
14
|
+
const tuple = [keyset.createdAt.toISOString(), keyset.id];
|
|
15
|
+
return Buffer.from(JSON.stringify(tuple), "utf8").toString("base64url");
|
|
16
|
+
}
|
|
17
|
+
function decodeKeysetCursor(cursor) {
|
|
18
|
+
try {
|
|
19
|
+
const json = Buffer.from(cursor, "base64url").toString("utf8");
|
|
20
|
+
const parsed = JSON.parse(json);
|
|
21
|
+
if (!Array.isArray(parsed) || parsed.length !== 2) return null;
|
|
22
|
+
const [iso, id] = parsed;
|
|
23
|
+
if (typeof iso !== "string" || typeof id !== "string") return null;
|
|
24
|
+
const createdAt = new Date(iso);
|
|
25
|
+
if (Number.isNaN(createdAt.getTime())) return null;
|
|
26
|
+
return { createdAt, id };
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function toJobRunSummary(r) {
|
|
32
|
+
return {
|
|
33
|
+
runId: r.id,
|
|
34
|
+
rootRunId: r.rootRunId,
|
|
35
|
+
parentRunId: r.parentRunId,
|
|
36
|
+
triggerSource: r.triggerSource,
|
|
37
|
+
triggerRef: r.triggerRef,
|
|
38
|
+
jobType: r.jobType,
|
|
39
|
+
pool: r.pool,
|
|
40
|
+
status: r.status,
|
|
41
|
+
scopeEntityType: r.scopeEntityType,
|
|
42
|
+
scopeEntityId: r.scopeEntityId,
|
|
43
|
+
tenantId: r.tenantId,
|
|
44
|
+
attempts: r.attempts,
|
|
45
|
+
errorMessage: r.error?.message ?? null,
|
|
46
|
+
runAt: r.runAt,
|
|
47
|
+
startedAt: r.startedAt,
|
|
48
|
+
finishedAt: r.finishedAt,
|
|
49
|
+
createdAt: r.createdAt
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
DEFAULT_LIST_LIMIT,
|
|
55
|
+
MAX_LIST_LIMIT,
|
|
56
|
+
clampLimit,
|
|
57
|
+
encodeKeysetCursor,
|
|
58
|
+
decodeKeysetCursor,
|
|
59
|
+
toJobRunSummary
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=chunk-L3LZWWSX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/jobs/job-run-keyset-cursor.ts"],"sourcesContent":["/**\n * Keyset (seek) cursor codec for `IJobRunService.listJobRuns` (OBS-LIST-1).\n *\n * The list is ordered `created_at DESC, id DESC`. The cursor encodes the\n * `(createdAt, id)` of the last row on the previous page so the next page\n * can seek with `WHERE (created_at, id) < (cursorCreatedAt, cursorId)`\n * rather than an `OFFSET`. Keyset pagination stays O(log n) on deep pages\n * and is stable as new rows arrive at the head.\n *\n * The cursor is opaque to consumers: a base64url-encoded JSON tuple. Shape\n * is an implementation detail — never parse it outside this module.\n *\n * Also hosts `toJobRunSummary`, the single `JobRunRow → JobRunSummary`\n * projection shared by both backends so the narrow shape stays in sync.\n */\nimport type { JobRunRow } from './job-orchestration.schema';\nimport type { JobRunSummary } from './job-run-service.protocol';\n\nexport interface JobRunKeyset {\n /** `created_at` of the last row on the previous page. */\n createdAt: Date;\n /** `id` (UUID) tie-break of the last row on the previous page. */\n id: string;\n}\n\n/** Default page size when `limit` is omitted. */\nexport const DEFAULT_LIST_LIMIT = 50;\n/** Hard upper bound on page size to keep a single read bounded. */\nexport const MAX_LIST_LIMIT = 200;\n\n/** Clamp a caller-supplied `limit` into `[1, MAX_LIST_LIMIT]`. */\nexport function clampLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit)) {\n return DEFAULT_LIST_LIMIT;\n }\n const floored = Math.floor(limit);\n if (floored < 1) return 1;\n if (floored > MAX_LIST_LIMIT) return MAX_LIST_LIMIT;\n return floored;\n}\n\nexport function encodeKeysetCursor(keyset: JobRunKeyset): string {\n const tuple = [keyset.createdAt.toISOString(), keyset.id];\n return Buffer.from(JSON.stringify(tuple), 'utf8').toString('base64url');\n}\n\n/**\n * Decode an opaque cursor back into its `(createdAt, id)` keyset. Returns\n * `null` for a malformed cursor so callers can treat garbage input as\n * \"start from the beginning\" rather than throwing on user-supplied data.\n */\nexport function decodeKeysetCursor(cursor: string): JobRunKeyset | null {\n try {\n const json = Buffer.from(cursor, 'base64url').toString('utf8');\n const parsed = JSON.parse(json) as unknown;\n if (!Array.isArray(parsed) || parsed.length !== 2) return null;\n const [iso, id] = parsed;\n if (typeof iso !== 'string' || typeof id !== 'string') return null;\n const createdAt = new Date(iso);\n if (Number.isNaN(createdAt.getTime())) return null;\n return { createdAt, id };\n } catch {\n return null;\n }\n}\n\n/**\n * Project a raw `job_run` row into the narrow `JobRunSummary` shape exposed\n * by `listJobRuns`. `errorMessage` is pulled from the jsonb `error.message`.\n */\nexport function toJobRunSummary(r: JobRunRow): JobRunSummary {\n return {\n runId: r.id,\n rootRunId: r.rootRunId,\n parentRunId: r.parentRunId,\n triggerSource: r.triggerSource,\n triggerRef: r.triggerRef,\n jobType: r.jobType,\n pool: r.pool,\n status: r.status,\n scopeEntityType: r.scopeEntityType,\n scopeEntityId: r.scopeEntityId,\n tenantId: r.tenantId,\n attempts: r.attempts,\n errorMessage: r.error?.message ?? null,\n runAt: r.runAt,\n startedAt: r.startedAt,\n finishedAt: r.finishedAt,\n createdAt: r.createdAt,\n };\n}\n"],"mappings":";AA0BO,IAAM,qBAAqB;AAE3B,IAAM,iBAAiB;AAGvB,SAAS,WAAW,OAAmC;AAC5D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG;AACxD,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,MAAM,KAAK;AAChC,MAAI,UAAU,EAAG,QAAO;AACxB,MAAI,UAAU,eAAgB,QAAO;AACrC,SAAO;AACT;AAEO,SAAS,mBAAmB,QAA8B;AAC/D,QAAM,QAAQ,CAAC,OAAO,UAAU,YAAY,GAAG,OAAO,EAAE;AACxD,SAAO,OAAO,KAAK,KAAK,UAAU,KAAK,GAAG,MAAM,EAAE,SAAS,WAAW;AACxE;AAOO,SAAS,mBAAmB,QAAqC;AACtE,MAAI;AACF,UAAM,OAAO,OAAO,KAAK,QAAQ,WAAW,EAAE,SAAS,MAAM;AAC7D,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,EAAG,QAAO;AAC1D,UAAM,CAAC,KAAK,EAAE,IAAI;AAClB,QAAI,OAAO,QAAQ,YAAY,OAAO,OAAO,SAAU,QAAO;AAC9D,UAAM,YAAY,IAAI,KAAK,GAAG;AAC9B,QAAI,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG,QAAO;AAC9C,WAAO,EAAE,WAAW,GAAG;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,gBAAgB,GAA6B;AAC3D,SAAO;AAAA,IACL,OAAO,EAAE;AAAA,IACT,WAAW,EAAE;AAAA,IACb,aAAa,EAAE;AAAA,IACf,eAAe,EAAE;AAAA,IACjB,YAAY,EAAE;AAAA,IACd,SAAS,EAAE;AAAA,IACX,MAAM,EAAE;AAAA,IACR,QAAQ,EAAE;AAAA,IACV,iBAAiB,EAAE;AAAA,IACnB,eAAe,EAAE;AAAA,IACjB,UAAU,EAAE;AAAA,IACZ,UAAU,EAAE;AAAA,IACZ,cAAc,EAAE,OAAO,WAAW;AAAA,IAClC,OAAO,EAAE;AAAA,IACT,WAAW,EAAE;AAAA,IACb,YAAY,EAAE;AAAA,IACd,WAAW,EAAE;AAAA,EACf;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-L4SDDEEU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tokenKey
|
|
3
|
+
} from "./chunk-GYGNEQSC.js";
|
|
4
|
+
|
|
5
|
+
// runtime/subsystems/cache/cache.tokens.ts
|
|
6
|
+
var CACHE = Symbol.for(tokenKey("cache", "cache"));
|
|
7
|
+
var CACHE_DEFAULT_TTL = Symbol.for(tokenKey("cache", "default-ttl"));
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
CACHE,
|
|
11
|
+
CACHE_DEFAULT_TTL
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=chunk-L6FTY45T.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/cache/cache.tokens.ts"],"sourcesContent":["/**\n * Injection token for the cache service.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(CACHE) private readonly cache: ICacheService) {}\n * ```\n *\n * Services may also inject CACHE for reads (get, has) per ADR-003.\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 CACHE = Symbol.for(tokenKey('cache', 'cache'));\n\n/**\n * Injection token for the default TTL (in seconds) passed from CacheModule.forRoot().\n * Optional — omit for no-expiry behavior.\n */\nexport const CACHE_DEFAULT_TTL = Symbol.for(tokenKey('cache', 'default-ttl'));\n"],"mappings":";;;;;AAeO,IAAM,QAAQ,OAAO,IAAI,SAAS,SAAS,OAAO,CAAC;AAMnD,IAAM,oBAAoB,OAAO,IAAI,SAAS,SAAS,aAAa,CAAC;","names":[]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BRIDGE_DELIVERY_JOB_TYPE
|
|
3
|
+
} from "./chunk-YTN6BKWA.js";
|
|
4
|
+
import {
|
|
5
|
+
bridgeDelivery
|
|
6
|
+
} from "./chunk-2TVVBC53.js";
|
|
7
|
+
import {
|
|
8
|
+
BRIDGE_REGISTRY
|
|
9
|
+
} from "./chunk-4LH67P4U.js";
|
|
10
|
+
import {
|
|
11
|
+
jobRuns
|
|
12
|
+
} from "./chunk-OKXZ63IA.js";
|
|
13
|
+
import {
|
|
14
|
+
__decorateClass,
|
|
15
|
+
__decorateParam
|
|
16
|
+
} from "./chunk-2E224ZSN.js";
|
|
17
|
+
|
|
18
|
+
// runtime/subsystems/bridge/bridge-outbox-drain-hook.ts
|
|
19
|
+
import { Inject, Injectable, Logger, Optional } from "@nestjs/common";
|
|
20
|
+
import { randomUUID } from "crypto";
|
|
21
|
+
import { eq } from "drizzle-orm";
|
|
22
|
+
var POOL_BY_DIRECTION = {
|
|
23
|
+
inbound: "events_inbound",
|
|
24
|
+
change: "events_change",
|
|
25
|
+
outbound: "events_outbound"
|
|
26
|
+
};
|
|
27
|
+
var BridgeOutboxDrainHook = class {
|
|
28
|
+
constructor(registry = {}) {
|
|
29
|
+
this.registry = registry;
|
|
30
|
+
}
|
|
31
|
+
registry;
|
|
32
|
+
logger = new Logger(BridgeOutboxDrainHook.name);
|
|
33
|
+
warnedNullDirection = false;
|
|
34
|
+
warnedAuditTypes = /* @__PURE__ */ new Set();
|
|
35
|
+
async processEvent(event, tx) {
|
|
36
|
+
if (event.metadata?.["tier"] === "audit") {
|
|
37
|
+
this.warnAuditBlockedOnce(event);
|
|
38
|
+
return {
|
|
39
|
+
delivered: 0,
|
|
40
|
+
dedupSkips: 0,
|
|
41
|
+
triggerCount: 0,
|
|
42
|
+
auditBlocked: 1
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const triggers = this.lookupTriggers(event.type);
|
|
46
|
+
if (triggers.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
delivered: 0,
|
|
49
|
+
dedupSkips: 0,
|
|
50
|
+
triggerCount: 0,
|
|
51
|
+
auditBlocked: 0
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const direction = event.metadata?.["direction"] ?? null;
|
|
55
|
+
const tenantId = event.metadata?.["tenantId"] ?? null;
|
|
56
|
+
const wrapperPool = direction ? POOL_BY_DIRECTION[direction] : void 0;
|
|
57
|
+
if (!wrapperPool) {
|
|
58
|
+
if (!this.warnedNullDirection) {
|
|
59
|
+
this.warnedNullDirection = true;
|
|
60
|
+
this.logger.warn(
|
|
61
|
+
`Skipping bridge fanout for events with null/unknown direction. event.id=${event.id} event.type=${event.type} direction=${String(direction)}. The wrapper pool is derived from direction (events_<direction>); publishers must use TypedEventBus.publish() so direction is stamped on the outbox row.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
delivered: 0,
|
|
66
|
+
dedupSkips: 0,
|
|
67
|
+
triggerCount: triggers.length,
|
|
68
|
+
auditBlocked: 0
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
let delivered = 0;
|
|
72
|
+
let dedupSkips = 0;
|
|
73
|
+
const client = tx;
|
|
74
|
+
for (const trigger of triggers) {
|
|
75
|
+
const deliveryId = randomUUID();
|
|
76
|
+
const wrapperRunId = randomUUID();
|
|
77
|
+
await tx.insert(jobRuns).values({
|
|
78
|
+
id: wrapperRunId,
|
|
79
|
+
jobType: BRIDGE_DELIVERY_JOB_TYPE,
|
|
80
|
+
jobVersion: 1,
|
|
81
|
+
rootRunId: wrapperRunId,
|
|
82
|
+
pool: wrapperPool,
|
|
83
|
+
status: "pending",
|
|
84
|
+
input: { deliveryId },
|
|
85
|
+
triggerSource: "event",
|
|
86
|
+
triggerRef: event.id,
|
|
87
|
+
tenantId
|
|
88
|
+
});
|
|
89
|
+
const inserted = await tx.insert(bridgeDelivery).values({
|
|
90
|
+
id: deliveryId,
|
|
91
|
+
eventId: event.id,
|
|
92
|
+
triggerId: trigger.triggerId,
|
|
93
|
+
wrapperRunId,
|
|
94
|
+
status: "pending",
|
|
95
|
+
tenantId
|
|
96
|
+
}).onConflictDoNothing({
|
|
97
|
+
target: [bridgeDelivery.eventId, bridgeDelivery.triggerId]
|
|
98
|
+
}).returning({ id: bridgeDelivery.id });
|
|
99
|
+
if (inserted.length === 0) {
|
|
100
|
+
await tx.delete(jobRuns).where(eq(jobRuns.id, wrapperRunId));
|
|
101
|
+
dedupSkips++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
delivered++;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
delivered,
|
|
108
|
+
dedupSkips,
|
|
109
|
+
triggerCount: triggers.length,
|
|
110
|
+
auditBlocked: 0
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
warnAuditBlockedOnce(event) {
|
|
114
|
+
if (this.warnedAuditTypes.has(event.type)) return;
|
|
115
|
+
this.warnedAuditTypes.add(event.type);
|
|
116
|
+
this.logger.warn(
|
|
117
|
+
`Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). Registry says this event is not bridge-eligible; a bridge_trigger row exists out-of-band. Investigate registry/runtime drift.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
lookupTriggers(eventType) {
|
|
121
|
+
const candidates = this.registry[eventType];
|
|
122
|
+
return candidates ?? [];
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
BridgeOutboxDrainHook = __decorateClass([
|
|
126
|
+
Injectable(),
|
|
127
|
+
__decorateParam(0, Optional()),
|
|
128
|
+
__decorateParam(0, Inject(BRIDGE_REGISTRY))
|
|
129
|
+
], BridgeOutboxDrainHook);
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
BridgeOutboxDrainHook
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=chunk-L7BNNRGI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../runtime/subsystems/bridge/bridge-outbox-drain-hook.ts"],"sourcesContent":["/**\n * BridgeOutboxDrainHook — drains-time bridge fanout writer (BRIDGE-4,\n * ADR-023 Phase 2).\n *\n * Implements `IBridgeOutboxDrainHook`. Called by `DrizzleEventBus`'s\n * modified `processBatch` once per drained event, INSIDE the per-event\n * transaction. For every trigger registered against the event's type in\n * the codegen-emitted `bridgeRegistry`, writes:\n *\n * 1. `bridge_delivery` ledger row — `INSERT … ON CONFLICT (event_id,\n * trigger_id) DO NOTHING RETURNING id`. Empty result ⇒ Case B\n * facade-eager pre-write OR drain-replay collision; skip wrapper\n * insert for that trigger; sibling triggers still fire.\n * 2. `job_run` wrapper row — `type='@framework/bridge_delivery'`,\n * `pool='events_<direction>'`, `input={ deliveryId }`,\n * `trigger_source='event'`, `trigger_ref=event.id`. The wrapper is\n * what the framework `BridgeDeliveryHandler` (BRIDGE-5) eventually\n * claims via the worker that polls the corresponding reserved pool.\n *\n * Null `event.metadata.direction` is tolerated: the hook logs a one-line\n * warning per event and returns zeros without writing rows. The drain's\n * `processed_at` stamp + subscriber dispatch still fire normally.\n * Direction is null only for events published via the legacy\n * `IEventBus.publish(...)` path (`TypedEventBus.publish` always sets it);\n * such events are out of scope for bridge fanout.\n *\n * The wrapper insert generates its own `id` via Drizzle's `defaultRandom`\n * — we don't `RETURNING id` because nobody needs it at drain time;\n * `BridgeDeliveryHandler` later looks up the wrapper via the\n * `bridge_delivery.wrapper_run_id` link if needed. This keeps the drain\n * one-round-trip-per-trigger.\n */\nimport { Inject, Injectable, Logger, Optional } from '@nestjs/common';\nimport { randomUUID } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\n\nimport type { DomainEvent, DrizzleTransaction } from '../events/event-bus.protocol';\nimport { bridgeDelivery } from './bridge-delivery.schema';\nimport { jobRuns } from '../jobs/job-orchestration.schema';\n\nimport { BRIDGE_REGISTRY } from './bridge.tokens';\nimport type {\n BridgeOutboxDrainResult,\n BridgeRegistry,\n BridgeTriggerEntry,\n IBridgeOutboxDrainHook,\n} from './bridge.protocol';\nimport { BRIDGE_DELIVERY_JOB_TYPE } from './bridge-delivery-handler';\nimport type { EventTypeName } from '../events/event-registry';\n\n/** Reserved pools the wrapper rows route into; ADR-022 / ADR-024. */\nconst POOL_BY_DIRECTION: Record<string, string> = {\n inbound: 'events_inbound',\n change: 'events_change',\n outbound: 'events_outbound',\n};\n\n@Injectable()\nexport class BridgeOutboxDrainHook implements IBridgeOutboxDrainHook {\n private readonly logger = new Logger(BridgeOutboxDrainHook.name);\n private warnedNullDirection = false;\n private readonly warnedAuditTypes = new Set<string>();\n\n constructor(\n @Optional()\n @Inject(BRIDGE_REGISTRY)\n private readonly registry: BridgeRegistry = {},\n ) {}\n\n async processEvent(\n event: DomainEvent,\n tx: DrizzleTransaction,\n ): Promise<BridgeOutboxDrainResult> {\n // Audit-tier guard (defense-in-depth — AUDIT-4). Audit events are not\n // bridge-eligible: the codegen-side validator (AUDIT-2) blocks the\n // registry from listing them as triggers. Reaching this branch means\n // registry/runtime drift — an out-of-band `bridge_trigger` insert, or\n // version skew during deploy. Refuse fanout, surface drift via WARN.\n if (event.metadata?.['tier'] === 'audit') {\n this.warnAuditBlockedOnce(event);\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 1,\n };\n }\n\n const triggers = this.lookupTriggers(event.type);\n if (triggers.length === 0) {\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: 0,\n auditBlocked: 0,\n };\n }\n\n const direction =\n (event.metadata?.['direction'] as string | undefined) ?? null;\n const tenantId =\n (event.metadata?.['tenantId'] as string | null | undefined) ?? null;\n const wrapperPool = direction ? POOL_BY_DIRECTION[direction] : undefined;\n\n if (!wrapperPool) {\n // Null direction (or an unrecognised one — defensive). Bridge\n // fanout requires a routed wrapper pool; without one we can't\n // spawn. Log once per process so misconfiguration surfaces.\n if (!this.warnedNullDirection) {\n this.warnedNullDirection = true;\n this.logger.warn(\n `Skipping bridge fanout for events with null/unknown direction. ` +\n `event.id=${event.id} event.type=${event.type} ` +\n `direction=${String(direction)}. The wrapper pool is derived ` +\n `from direction (events_<direction>); publishers must use ` +\n `TypedEventBus.publish() so direction is stamped on the ` +\n `outbox row.`,\n );\n }\n return {\n delivered: 0,\n dedupSkips: 0,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n let delivered = 0;\n let dedupSkips = 0;\n const client = tx as unknown as {\n insert: (table: unknown) => {\n values: (v: unknown) => {\n onConflictDoNothing: (opts: unknown) => {\n returning: (cols: unknown) => Promise<{ id: string }[]>;\n };\n } & {\n // wrapper insert path — no ON CONFLICT\n // (typed loosely via the same helper return shape)\n };\n };\n };\n\n for (const trigger of triggers) {\n const deliveryId = randomUUID();\n const wrapperRunId = randomUUID();\n\n // FK ORDER (BRIDGE / 0.15.2): `bridge_delivery.wrapper_run_id` REFERENCES\n // `job_run(id)` is a plain (non-deferrable) FK, so the referenced\n // wrapper `job_run` MUST exist before the delivery row that points at it\n // is inserted — otherwise Postgres rejects the delivery insert\n // immediately. (The codegen unit tests mock `tx`, so they never\n // exercised this ordering against a real FK; package-mode bridge\n // deliveries are the first to do so.) We therefore insert the wrapper\n // run FIRST, then the delivery. Idempotency is unchanged: the delivery\n // keeps its `ON CONFLICT (event_id, trigger_id) DO NOTHING RETURNING`,\n // and when the delivery conflicts (outbox replay or facade-eager Case B)\n // we DELETE the just-inserted orphan wrapper run in the same tx, so a\n // skipped delivery leaves no stray `job_run` for a worker to claim.\n\n // 1. Wrapper job_run insert. We carry the deliveryId into the wrapper\n // input so BridgeDeliveryHandler.run(ctx) can locate the row via\n // repo.findDeliveryById(ctx.input.deliveryId).\n await (tx as unknown as { insert: typeof client.insert })\n .insert(jobRuns)\n .values({\n id: wrapperRunId,\n jobType: BRIDGE_DELIVERY_JOB_TYPE,\n jobVersion: 1,\n rootRunId: wrapperRunId,\n pool: wrapperPool,\n status: 'pending',\n input: { deliveryId },\n triggerSource: 'event',\n triggerRef: event.id,\n tenantId,\n });\n\n // 2. bridge_delivery insert with ON CONFLICT DO NOTHING + RETURNING.\n const inserted = await (tx as unknown as {\n insert: typeof client.insert;\n })\n .insert(bridgeDelivery)\n .values({\n id: deliveryId,\n eventId: event.id,\n triggerId: trigger.triggerId,\n wrapperRunId,\n status: 'pending',\n tenantId,\n })\n .onConflictDoNothing({\n target: [bridgeDelivery.eventId, bridgeDelivery.triggerId],\n })\n .returning({ id: bridgeDelivery.id });\n\n if (inserted.length === 0) {\n // Case B (facade pre-wrote `delivered`) or drain replay — the delivery\n // already exists, so this trigger is a no-op. Remove the orphan wrapper\n // run we speculatively inserted above so no worker claims it. Sibling\n // triggers still fire.\n await (tx as unknown as {\n delete: (table: unknown) => {\n where: (cond: unknown) => Promise<unknown>;\n };\n })\n .delete(jobRuns)\n .where(eq(jobRuns.id, wrapperRunId));\n dedupSkips++;\n continue;\n }\n\n delivered++;\n }\n\n return {\n delivered,\n dedupSkips,\n triggerCount: triggers.length,\n auditBlocked: 0,\n };\n }\n\n private warnAuditBlockedOnce(event: DomainEvent): void {\n if (this.warnedAuditTypes.has(event.type)) return;\n this.warnedAuditTypes.add(event.type);\n this.logger.warn(\n `Bridge guard blocked audit-tier event '${event.type}' (event.id=${event.id}). ` +\n `Registry says this event is not bridge-eligible; a bridge_trigger row exists ` +\n `out-of-band. Investigate registry/runtime drift.`,\n );\n }\n\n private lookupTriggers(\n eventType: string,\n ): BridgeTriggerEntry[] {\n const candidates = this.registry[eventType as EventTypeName];\n return (candidates ?? []) as BridgeTriggerEntry[];\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// runtime/subsystems/integration/incremental-read.ts
|
|
2
|
+
async function mapConcurrent(ids, fn, limit) {
|
|
3
|
+
const out = /* @__PURE__ */ new Map();
|
|
4
|
+
if (ids.length === 0) return out;
|
|
5
|
+
const width = Math.max(1, Math.min(limit, ids.length));
|
|
6
|
+
let next = 0;
|
|
7
|
+
const worker = async () => {
|
|
8
|
+
while (next < ids.length) {
|
|
9
|
+
const idx = next++;
|
|
10
|
+
const id = ids[idx];
|
|
11
|
+
out.set(id, await fn(id));
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
await Promise.all(Array.from({ length: width }, worker));
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
var IncrementalReadBase = class {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the vendor takes the request predicate server-side. Declared, not
|
|
20
|
+
* enforced here — surfaced into the emission manifest (R3) so the falsifier
|
|
21
|
+
* suite (R4) can record which adapters filter post-hydrate. `false` is the
|
|
22
|
+
* honest floor (e.g. Gmail without `q=`), handled via `matchesRecord`.
|
|
23
|
+
*/
|
|
24
|
+
filterPushdown = false;
|
|
25
|
+
/** Max concurrent in-flight calls for a `mapConcurrent`-built `hydrate`. */
|
|
26
|
+
hydrateConcurrency = 10;
|
|
27
|
+
/** `Change<T>.source` provenance stamped by `listChanges`. */
|
|
28
|
+
changeSource = "poll";
|
|
29
|
+
/**
|
|
30
|
+
* Whether this source's cursor strategy is divisible (RFC-0003 §3). When
|
|
31
|
+
* `true` (default — sortable watermarks like `systemModstamp`/`timestamp`/
|
|
32
|
+
* `replayId`), `listChanges` emits each record's per-ref cursor, so the
|
|
33
|
+
* orchestrator may checkpoint mid-walk and a crash resumes from the last
|
|
34
|
+
* delivered ref.
|
|
35
|
+
*
|
|
36
|
+
* When `false` (atomic opaque tokens — Gmail `historyId`, Calendar
|
|
37
|
+
* `syncToken`), `listChanges` WITHHOLDS per-ref cursors and emits the
|
|
38
|
+
* end-of-walk token only on the final record, so the orchestrator's
|
|
39
|
+
* persist-last-yielded lifecycle can never persist an unresumable mid-walk
|
|
40
|
+
* token. The cost is blast-radius: an interrupted atomic run resumes
|
|
41
|
+
* all-or-nothing from the prior persisted token. For atomic *backfills* that
|
|
42
|
+
* radius is the whole enumerate walk — bound it with `ReadRequest.pageSize`
|
|
43
|
+
* (smaller pages ⇒ shorter walks per run). Per-page atomic checkpointing is a
|
|
44
|
+
* future refinement; R2 gates at end-of-walk.
|
|
45
|
+
*
|
|
46
|
+
* Codegen (R3) sets this from the strategy kind via `isDivisibleCursor`.
|
|
47
|
+
*/
|
|
48
|
+
cursorDivisible = true;
|
|
49
|
+
// ---- Optional filter hooks — exactly one is live per `filterPushdown` ----
|
|
50
|
+
/** Pre-hydrate predicate over the cheap ref (preferred — avoids hydration). */
|
|
51
|
+
matchesRef(_ref, _filter) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** Post-hydrate predicate over the canonical record (the no-pushdown floor). */
|
|
55
|
+
matchesRecord(_record, _filter) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the filter for a subscription when adapting to `listChanges`
|
|
60
|
+
* (which has no filter argument). Defaults to none; codegen wiring (R3)
|
|
61
|
+
* overrides this to thread `DetectionConfig.filters`.
|
|
62
|
+
*/
|
|
63
|
+
filterFor(_subscription) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
// ---- PROVIDED by the base ----
|
|
67
|
+
/**
|
|
68
|
+
* Stream canonical records for a request. Filter is applied BEFORE hydrate
|
|
69
|
+
* (structural: a kept ref is hydrated, a rejected one never is), so an
|
|
70
|
+
* adapter cannot hydrate-then-discard. A hydrate miss (deleted mid-run) is
|
|
71
|
+
* skipped, never fabricated.
|
|
72
|
+
*/
|
|
73
|
+
async *read(req, ctx) {
|
|
74
|
+
for await (const refPage of this.enumerate(req.mode, req.filter, req.pageSize, ctx)) {
|
|
75
|
+
const kept = refPage.filter((ref) => this.matchesRef(ref, req.filter));
|
|
76
|
+
if (kept.length === 0) continue;
|
|
77
|
+
const raws = await this.hydrate(
|
|
78
|
+
kept.map((ref) => ref.externalId),
|
|
79
|
+
ctx
|
|
80
|
+
);
|
|
81
|
+
for (const ref of kept) {
|
|
82
|
+
const raw = raws.get(ref.externalId);
|
|
83
|
+
if (raw === void 0 || raw === null) continue;
|
|
84
|
+
const record = this.toCanonical(raw);
|
|
85
|
+
if (record !== null && this.matchesRecord(record, req.filter)) {
|
|
86
|
+
yield { externalId: ref.externalId, record, raw, cursor: ref.cursor };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* `RandomRead<T>` — single-record read, provided for free as
|
|
93
|
+
* `toCanonical ∘ hydrate([id])`. Reuses the adapter's batched fetch + miss
|
|
94
|
+
* tolerance; returns `null` for a missing or undecodable record.
|
|
95
|
+
*/
|
|
96
|
+
async get(id, ctx) {
|
|
97
|
+
const raws = await this.hydrate([id], ctx);
|
|
98
|
+
const raw = raws.get(id);
|
|
99
|
+
if (raw === void 0 || raw === null) return null;
|
|
100
|
+
return this.toCanonical(raw);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* `IChangeSource<T>` adaptation. Maps the orchestrator's by-value cursor to a
|
|
104
|
+
* `ReadMode` (`null` → `full` backfill, else `delta`), streams `read()`, and
|
|
105
|
+
* stamps each `SourcedRecord` into a `Change<T>`. All records surface as
|
|
106
|
+
* `'updated'`; the orchestrator's diff stage classifies create-vs-update and
|
|
107
|
+
* deletes arrive as tombstone refs (`toCanonical` may flag them).
|
|
108
|
+
*
|
|
109
|
+
* Cursor emission honors `cursorDivisible` (RFC-0003 §3). Divisible: each
|
|
110
|
+
* record carries its own per-ref cursor. Atomic: per-ref cursors are withheld
|
|
111
|
+
* (`undefined`, which the orchestrator skips persisting) and the end-of-walk
|
|
112
|
+
* token rides only on the final record — so a mid-walk crash never persists
|
|
113
|
+
* an unresumable token. If an atomic run yields no surviving records, no
|
|
114
|
+
* cursor is persisted and the next run re-reads the same (empty) delta — a
|
|
115
|
+
* bounded inefficiency, never data loss.
|
|
116
|
+
*/
|
|
117
|
+
async *listChanges(subscription, cursor) {
|
|
118
|
+
const mode = cursor === null || cursor === void 0 ? { kind: "full" } : { kind: "delta", cursor };
|
|
119
|
+
const filter = this.filterFor(subscription);
|
|
120
|
+
const stream = this.read({ mode, filter }, { subscription });
|
|
121
|
+
if (this.cursorDivisible) {
|
|
122
|
+
for await (const sourced of stream) {
|
|
123
|
+
yield this.toChange(sourced, sourced.cursor);
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
let prev = null;
|
|
128
|
+
for await (const sourced of stream) {
|
|
129
|
+
if (prev !== null) yield this.toChange(prev, void 0);
|
|
130
|
+
prev = sourced;
|
|
131
|
+
}
|
|
132
|
+
if (prev !== null) yield this.toChange(prev, prev.cursor);
|
|
133
|
+
}
|
|
134
|
+
/** Stamp a `SourcedRecord` into a `Change<T>` with an explicit emitted cursor. */
|
|
135
|
+
toChange(sourced, cursor) {
|
|
136
|
+
return {
|
|
137
|
+
externalId: sourced.externalId,
|
|
138
|
+
operation: "updated",
|
|
139
|
+
record: sourced.record,
|
|
140
|
+
cursor,
|
|
141
|
+
source: this.changeSource
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export {
|
|
147
|
+
mapConcurrent,
|
|
148
|
+
IncrementalReadBase
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=chunk-LG57S2SC.js.map
|