@knpkv/control-center 0.1.0
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/LICENSE +21 -0
- package/README.md +309 -0
- package/dist/client/.vite/manifest.json +452 -0
- package/dist/client/assets/ActiveWorkPage-Bvji6Tys.js +2 -0
- package/dist/client/assets/ActiveWorkPage-Bvji6Tys.js.map +1 -0
- package/dist/client/assets/ActiveWorkPage-CxNa23uW.css +1 -0
- package/dist/client/assets/AgentPage-Bom41la2.js +3 -0
- package/dist/client/assets/AgentPage-Bom41la2.js.map +1 -0
- package/dist/client/assets/AgentPage-f6WXQA21.css +1 -0
- package/dist/client/assets/AtlassianOAuthCallbackPage-Cqqgj2o3.css +1 -0
- package/dist/client/assets/AtlassianOAuthCallbackPage-dr-B9-DD.js +2 -0
- package/dist/client/assets/AtlassianOAuthCallbackPage-dr-B9-DD.js.map +1 -0
- package/dist/client/assets/AuthorizedSharePage-C-P-PNfm.js +2 -0
- package/dist/client/assets/AuthorizedSharePage-C-P-PNfm.js.map +1 -0
- package/dist/client/assets/AuthorizedSharePage-DzE_yvHI.css +1 -0
- package/dist/client/assets/BrowserCrypto-BPiuCuW-.js +2 -0
- package/dist/client/assets/BrowserCrypto-BPiuCuW-.js.map +1 -0
- package/dist/client/assets/BrowserSessionHydrator-C8F_LGhg.js +2 -0
- package/dist/client/assets/BrowserSessionHydrator-C8F_LGhg.js.map +1 -0
- package/dist/client/assets/CommandSearch-D6iFcdvj.js +2 -0
- package/dist/client/assets/CommandSearch-D6iFcdvj.js.map +1 -0
- package/dist/client/assets/CommandSearch-Df36xGJc.css +1 -0
- package/dist/client/assets/Dialog-DwSIPb-B-DVn37afM.js +42 -0
- package/dist/client/assets/Dialog-DwSIPb-B-DVn37afM.js.map +1 -0
- package/dist/client/assets/ItemsPage-DsQCbQ11.css +1 -0
- package/dist/client/assets/ItemsPage-x39U11an.js +2 -0
- package/dist/client/assets/ItemsPage-x39U11an.js.map +1 -0
- package/dist/client/assets/PairPage-D5vlz4OG.js +2 -0
- package/dist/client/assets/PairPage-D5vlz4OG.js.map +1 -0
- package/dist/client/assets/PortfolioOverview-DSUabOmm.js +2 -0
- package/dist/client/assets/PortfolioOverview-DSUabOmm.js.map +1 -0
- package/dist/client/assets/PortfolioOverview-nrb6Ebbh.css +1 -0
- package/dist/client/assets/ReleaseRoute-DyDm5s85.js +2 -0
- package/dist/client/assets/ReleaseRoute-DyDm5s85.js.map +1 -0
- package/dist/client/assets/ReleaseRoute-R3GdFaGc.css +1 -0
- package/dist/client/assets/ReleaseWorkset-6gGnZPS8.css +1 -0
- package/dist/client/assets/ReleaseWorkset-BhGacsgb.js +2 -0
- package/dist/client/assets/ReleaseWorkset-BhGacsgb.js.map +1 -0
- package/dist/client/assets/ServicesPage-CoMVH2Si.js +2 -0
- package/dist/client/assets/ServicesPage-CoMVH2Si.js.map +1 -0
- package/dist/client/assets/ServicesPage-D76DN13E.css +1 -0
- package/dist/client/assets/TimelinePage-38jhMz_L.css +1 -0
- package/dist/client/assets/TimelinePage-D8Fj_351.js +2 -0
- package/dist/client/assets/TimelinePage-D8Fj_351.js.map +1 -0
- package/dist/client/assets/WorkspaceEntityLink-BRifdJHn.js +2 -0
- package/dist/client/assets/WorkspaceEntityLink-BRifdJHn.js.map +1 -0
- package/dist/client/assets/WorkspaceEntityRoute-BwpujSqk.css +1 -0
- package/dist/client/assets/WorkspaceEntityRoute-DPci8Q8I.js +30 -0
- package/dist/client/assets/WorkspaceEntityRoute-DPci8Q8I.js.map +1 -0
- package/dist/client/assets/WorkspaceReleaseLayout-CMg2-6IQ.css +1 -0
- package/dist/client/assets/WorkspaceReleaseLayout-DDLdY0rU.js +2 -0
- package/dist/client/assets/WorkspaceReleaseLayout-DDLdY0rU.js.map +1 -0
- package/dist/client/assets/authenticatedMutationClient-D5yD0rch.js +2 -0
- package/dist/client/assets/authenticatedMutationClient-D5yD0rch.js.map +1 -0
- package/dist/client/assets/authorizedShareTransport-Dyj53kJf.js +2 -0
- package/dist/client/assets/authorizedShareTransport-Dyj53kJf.js.map +1 -0
- package/dist/client/assets/client-OmvShYdC.js +12 -0
- package/dist/client/assets/client-OmvShYdC.js.map +1 -0
- package/dist/client/assets/connectionTestTransport-c25QXx7A.js +2 -0
- package/dist/client/assets/connectionTestTransport-c25QXx7A.js.map +1 -0
- package/dist/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/client/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
- package/dist/client/assets/index-CkslINEH.css +1 -0
- package/dist/client/assets/index-DLoOV6Hp.js +11 -0
- package/dist/client/assets/index-DLoOV6Hp.js.map +1 -0
- package/dist/client/assets/jsx-runtime-n5LQ9ujS.js +2 -0
- package/dist/client/assets/jsx-runtime-n5LQ9ujS.js.map +1 -0
- package/dist/client/assets/patterns-DEbg7R-A-Cw0A2uKS.js +2 -0
- package/dist/client/assets/patterns-DEbg7R-A-Cw0A2uKS.js.map +1 -0
- package/dist/client/assets/presentPortfolio-CkRqd_zz.js +2 -0
- package/dist/client/assets/presentPortfolio-CkRqd_zz.js.map +1 -0
- package/dist/client/assets/presentWorkspaceItems-BU__8LcC.js +2 -0
- package/dist/client/assets/presentWorkspaceItems-BU__8LcC.js.map +1 -0
- package/dist/client/assets/releasePaths-s-fSbIM-.js +2 -0
- package/dist/client/assets/releasePaths-s-fSbIM-.js.map +1 -0
- package/dist/client/assets/releaseRoutes-DSWkTh-E.js +2 -0
- package/dist/client/assets/releaseRoutes-DSWkTh-E.js.map +1 -0
- package/dist/client/assets/serviceOnboarding-B9pvdyWf.js +2 -0
- package/dist/client/assets/serviceOnboarding-B9pvdyWf.js.map +1 -0
- package/dist/client/assets/useCompactReleasePreview-Ch3XxgJU.js +2 -0
- package/dist/client/assets/useCompactReleasePreview-Ch3XxgJU.js.map +1 -0
- package/dist/client/assets/useWorkspaceItems-D0FuHGto.js +2 -0
- package/dist/client/assets/useWorkspaceItems-D0FuHGto.js.map +1 -0
- package/dist/client/assets/workspaceEntityPaths-xAl2jRFm.js +2 -0
- package/dist/client/assets/workspaceEntityPaths-xAl2jRFm.js.map +1 -0
- package/dist/client/assets/workspaceEntityRoutes-CRcfSq7c.js +2 -0
- package/dist/client/assets/workspaceEntityRoutes-CRcfSq7c.js.map +1 -0
- package/dist/client/build-graph.json +1465 -0
- package/dist/client/index.html +17 -0
- package/dist/server/api/agent.d.ts +652 -0
- package/dist/server/api/agent.d.ts.map +1 -0
- package/dist/server/api/client.d.ts +17 -0
- package/dist/server/api/client.d.ts.map +1 -0
- package/dist/server/api/controlCenterApi.d.ts +16 -0
- package/dist/server/api/controlCenterApi.d.ts.map +1 -0
- package/dist/server/api/deliveryGraph.d.ts +8714 -0
- package/dist/server/api/deliveryGraph.d.ts.map +1 -0
- package/dist/server/api/errors.d.ts +87 -0
- package/dist/server/api/errors.d.ts.map +1 -0
- package/dist/server/api/index.d.ts +14 -0
- package/dist/server/api/index.d.ts.map +1 -0
- package/dist/server/api/index.js +12 -0
- package/dist/server/api/index.js.map +1 -0
- package/dist/server/api/liveEvents.d.ts +1120 -0
- package/dist/server/api/liveEvents.d.ts.map +1 -0
- package/dist/server/api/media.d.ts +30 -0
- package/dist/server/api/media.d.ts.map +1 -0
- package/dist/server/api/plugins.d.ts +1853 -0
- package/dist/server/api/plugins.d.ts.map +1 -0
- package/dist/server/api/portfolio.d.ts +742 -0
- package/dist/server/api/portfolio.d.ts.map +1 -0
- package/dist/server/api/session.d.ts +204 -0
- package/dist/server/api/session.d.ts.map +1 -0
- package/dist/server/api/shares.d.ts +422 -0
- package/dist/server/api/shares.d.ts.map +1 -0
- package/dist/server/api/timeline.d.ts +86 -0
- package/dist/server/api/timeline.d.ts.map +1 -0
- package/dist/server/api/wire.d.ts +4 -0
- package/dist/server/api/wire.d.ts.map +1 -0
- package/dist/server/assets/BindConfig-BjK10BEb.js +15440 -0
- package/dist/server/assets/BindConfig-BjK10BEb.js.map +1 -0
- package/dist/server/assets/controlCenterApi-tZPvRPRH.js +1430 -0
- package/dist/server/assets/controlCenterApi-tZPvRPRH.js.map +1 -0
- package/dist/server/assets/domainEvent-x7yeq-gU.js +2130 -0
- package/dist/server/assets/domainEvent-x7yeq-gU.js.map +1 -0
- package/dist/server/assets/firstPartyServices-Y41P8uke.js +49 -0
- package/dist/server/assets/firstPartyServices-Y41P8uke.js.map +1 -0
- package/dist/server/assets/manualPluginSynchronization-C0aHB4UM.js +1805 -0
- package/dist/server/assets/manualPluginSynchronization-C0aHB4UM.js.map +1 -0
- package/dist/server/assets/portfolioInvalidation-Ds9Xm4_P.js +15463 -0
- package/dist/server/assets/portfolioInvalidation-Ds9Xm4_P.js.map +1 -0
- package/dist/server/assets/readiness-CzU3vjYQ.js +1012 -0
- package/dist/server/assets/readiness-CzU3vjYQ.js.map +1 -0
- package/dist/server/build-graph.json +3948 -0
- package/dist/server/domain/actors.d.ts +147 -0
- package/dist/server/domain/actors.d.ts.map +1 -0
- package/dist/server/domain/authorizedShare.d.ts +24 -0
- package/dist/server/domain/authorizedShare.d.ts.map +1 -0
- package/dist/server/domain/deliveryGraph.d.ts +848 -0
- package/dist/server/domain/deliveryGraph.d.ts.map +1 -0
- package/dist/server/domain/domainEvent.d.ts +50 -0
- package/dist/server/domain/domainEvent.d.ts.map +1 -0
- package/dist/server/domain/firstPartyServices.d.ts +60 -0
- package/dist/server/domain/firstPartyServices.d.ts.map +1 -0
- package/dist/server/domain/freshness.d.ts +367 -0
- package/dist/server/domain/freshness.d.ts.map +1 -0
- package/dist/server/domain/governedAction/bindings.d.ts +264 -0
- package/dist/server/domain/governedAction/bindings.d.ts.map +1 -0
- package/dist/server/domain/governedAction/index.d.ts +6 -0
- package/dist/server/domain/governedAction/index.d.ts.map +1 -0
- package/dist/server/domain/governedAction/lifecycle.d.ts +71 -0
- package/dist/server/domain/governedAction/lifecycle.d.ts.map +1 -0
- package/dist/server/domain/governedAction/model.d.ts +357 -0
- package/dist/server/domain/governedAction/model.d.ts.map +1 -0
- package/dist/server/domain/governedAction/stateMachine.d.ts +450 -0
- package/dist/server/domain/governedAction/stateMachine.d.ts.map +1 -0
- package/dist/server/domain/identifiers.d.ts +110 -0
- package/dist/server/domain/identifiers.d.ts.map +1 -0
- package/dist/server/domain/index.d.ts +26 -0
- package/dist/server/domain/index.d.ts.map +1 -0
- package/dist/server/domain/index.js +52 -0
- package/dist/server/domain/index.js.map +1 -0
- package/dist/server/domain/normalizedIssue.d.ts +223 -0
- package/dist/server/domain/normalizedIssue.d.ts.map +1 -0
- package/dist/server/domain/plugins/actions.d.ts +246 -0
- package/dist/server/domain/plugins/actions.d.ts.map +1 -0
- package/dist/server/domain/plugins/bounds.d.ts +12 -0
- package/dist/server/domain/plugins/bounds.d.ts.map +1 -0
- package/dist/server/domain/plugins/descriptor.d.ts +205 -0
- package/dist/server/domain/plugins/descriptor.d.ts.map +1 -0
- package/dist/server/domain/plugins/discovery.d.ts +39 -0
- package/dist/server/domain/plugins/discovery.d.ts.map +1 -0
- package/dist/server/domain/plugins/events.d.ts +232 -0
- package/dist/server/domain/plugins/events.d.ts.map +1 -0
- package/dist/server/domain/plugins/index.d.ts +11 -0
- package/dist/server/domain/plugins/index.d.ts.map +1 -0
- package/dist/server/domain/readiness/evaluate.d.ts +4 -0
- package/dist/server/domain/readiness/evaluate.d.ts.map +1 -0
- package/dist/server/domain/readiness/index.d.ts +7 -0
- package/dist/server/domain/readiness/index.d.ts.map +1 -0
- package/dist/server/domain/readiness/material.d.ts +114 -0
- package/dist/server/domain/readiness/material.d.ts.map +1 -0
- package/dist/server/domain/readiness/model.d.ts +1736 -0
- package/dist/server/domain/readiness/model.d.ts.map +1 -0
- package/dist/server/domain/readiness/policy.d.ts +73 -0
- package/dist/server/domain/readiness/policy.d.ts.map +1 -0
- package/dist/server/domain/readiness/rollup.d.ts +6 -0
- package/dist/server/domain/readiness/rollup.d.ts.map +1 -0
- package/dist/server/domain/relationshipRepair.d.ts +97 -0
- package/dist/server/domain/relationshipRepair.d.ts.map +1 -0
- package/dist/server/domain/release.d.ts +191 -0
- package/dist/server/domain/release.d.ts.map +1 -0
- package/dist/server/domain/releaseRelay.d.ts +44 -0
- package/dist/server/domain/releaseRelay.d.ts.map +1 -0
- package/dist/server/domain/sourceRevision.d.ts +39 -0
- package/dist/server/domain/sourceRevision.d.ts.map +1 -0
- package/dist/server/domain/timeline.d.ts +105 -0
- package/dist/server/domain/timeline.d.ts.map +1 -0
- package/dist/server/domain/utcTimestamp.d.ts +9 -0
- package/dist/server/domain/utcTimestamp.d.ts.map +1 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +7 -0
- package/dist/server/server/DataRootProtocol.d.ts +80 -0
- package/dist/server/server/DataRootProtocol.d.ts.map +1 -0
- package/dist/server/server/agent/AgentJobWorker.d.ts +48 -0
- package/dist/server/server/agent/AgentJobWorker.d.ts.map +1 -0
- package/dist/server/server/agent/AgentRuntimeRegistry.d.ts +17 -0
- package/dist/server/server/agent/AgentRuntimeRegistry.d.ts.map +1 -0
- package/dist/server/server/agent/index.d.ts +4 -0
- package/dist/server/server/agent/index.d.ts.map +1 -0
- package/dist/server/server/api/ApiConfiguration.d.ts +24 -0
- package/dist/server/server/api/ApiConfiguration.d.ts.map +1 -0
- package/dist/server/server/api/ApiMiddleware.d.ts +14 -0
- package/dist/server/server/api/ApiMiddleware.d.ts.map +1 -0
- package/dist/server/server/api/ApplicationServices.d.ts +320 -0
- package/dist/server/server/api/ApplicationServices.d.ts.map +1 -0
- package/dist/server/server/api/ControlCenterApiServer.d.ts +11 -0
- package/dist/server/server/api/ControlCenterApiServer.d.ts.map +1 -0
- package/dist/server/server/api/ErrorMapping.d.ts +29 -0
- package/dist/server/server/api/ErrorMapping.d.ts.map +1 -0
- package/dist/server/server/api/Handlers.d.ts +24 -0
- package/dist/server/server/api/Handlers.d.ts.map +1 -0
- package/dist/server/server/api/LiveStreamAdmission.d.ts +34 -0
- package/dist/server/server/api/LiveStreamAdmission.d.ts.map +1 -0
- package/dist/server/server/api/RequestBoundary.d.ts +17 -0
- package/dist/server/server/api/RequestBoundary.d.ts.map +1 -0
- package/dist/server/server/api/RequestContext.d.ts +38 -0
- package/dist/server/server/api/RequestContext.d.ts.map +1 -0
- package/dist/server/server/api/RequestLimits.d.ts +79 -0
- package/dist/server/server/api/RequestLimits.d.ts.map +1 -0
- package/dist/server/server/api/index.d.ts +9 -0
- package/dist/server/server/api/index.d.ts.map +1 -0
- package/dist/server/server/application/authorizedShares.d.ts +29 -0
- package/dist/server/server/application/authorizedShares.d.ts.map +1 -0
- package/dist/server/server/application/awsResourceDiscovery.d.ts +18 -0
- package/dist/server/server/application/awsResourceDiscovery.d.ts.map +1 -0
- package/dist/server/server/application/connectionOwnership.d.ts +50 -0
- package/dist/server/server/application/connectionOwnership.d.ts.map +1 -0
- package/dist/server/server/application/deliveryGraphInspection.d.ts +59 -0
- package/dist/server/server/application/deliveryGraphInspection.d.ts.map +1 -0
- package/dist/server/server/application/errors.d.ts +10 -0
- package/dist/server/server/application/errors.d.ts.map +1 -0
- package/dist/server/server/application/fakeReleaseNormalization.d.ts +152 -0
- package/dist/server/server/application/fakeReleaseNormalization.d.ts.map +1 -0
- package/dist/server/server/application/index.d.ts +17 -0
- package/dist/server/server/application/index.d.ts.map +1 -0
- package/dist/server/server/application/liveEvents.d.ts +22 -0
- package/dist/server/server/application/liveEvents.d.ts.map +1 -0
- package/dist/server/server/application/manualPluginSynchronization.d.ts +41 -0
- package/dist/server/server/application/manualPluginSynchronization.d.ts.map +1 -0
- package/dist/server/server/application/mediaReads.d.ts +14 -0
- package/dist/server/server/application/mediaReads.d.ts.map +1 -0
- package/dist/server/server/application/normalizedPluginPageMaterialization.d.ts +109 -0
- package/dist/server/server/application/normalizedPluginPageMaterialization.d.ts.map +1 -0
- package/dist/server/server/application/pluginAdministration.d.ts +1318 -0
- package/dist/server/server/application/pluginAdministration.d.ts.map +1 -0
- package/dist/server/server/application/pluginSynchronizationAuthority.d.ts +22 -0
- package/dist/server/server/application/pluginSynchronizationAuthority.d.ts.map +1 -0
- package/dist/server/server/application/portfolioInvalidation.d.ts +35 -0
- package/dist/server/server/application/portfolioInvalidation.d.ts.map +1 -0
- package/dist/server/server/application/portfolioSnapshots.d.ts +12 -0
- package/dist/server/server/application/portfolioSnapshots.d.ts.map +1 -0
- package/dist/server/server/application/readinessDigests.d.ts +3 -0
- package/dist/server/server/application/readinessDigests.d.ts.map +1 -0
- package/dist/server/server/application/relationshipInference.d.ts +57 -0
- package/dist/server/server/application/relationshipInference.d.ts.map +1 -0
- package/dist/server/server/application/relationshipInferenceMaterialization.d.ts +26 -0
- package/dist/server/server/application/relationshipInferenceMaterialization.d.ts.map +1 -0
- package/dist/server/server/application/relationshipRepairProposals.d.ts +41 -0
- package/dist/server/server/application/relationshipRepairProposals.d.ts.map +1 -0
- package/dist/server/server/application/releaseAgent.d.ts +30 -0
- package/dist/server/server/application/releaseAgent.d.ts.map +1 -0
- package/dist/server/server/application/releaseAgentJobs.d.ts +26 -0
- package/dist/server/server/application/releaseAgentJobs.d.ts.map +1 -0
- package/dist/server/server/application/releaseSynchronization.d.ts +55 -0
- package/dist/server/server/application/releaseSynchronization.d.ts.map +1 -0
- package/dist/server/server/application/timelineExportAudits.d.ts +22 -0
- package/dist/server/server/application/timelineExportAudits.d.ts.map +1 -0
- package/dist/server/server/application/timelineExports.d.ts +46 -0
- package/dist/server/server/application/timelineExports.d.ts.map +1 -0
- package/dist/server/server/application/timelineReads.d.ts +29 -0
- package/dist/server/server/application/timelineReads.d.ts.map +1 -0
- package/dist/server/server/auth/Auth.d.ts +169 -0
- package/dist/server/server/auth/Auth.d.ts.map +1 -0
- package/dist/server/server/auth/AuthRepository.d.ts +160 -0
- package/dist/server/server/auth/AuthRepository.d.ts.map +1 -0
- package/dist/server/server/auth/TerminalRecovery.d.ts +35 -0
- package/dist/server/server/auth/TerminalRecovery.d.ts.map +1 -0
- package/dist/server/server/auth/errors.d.ts +31 -0
- package/dist/server/server/auth/errors.d.ts.map +1 -0
- package/dist/server/server/auth/index.d.ts +5 -0
- package/dist/server/server/auth/index.d.ts.map +1 -0
- package/dist/server/server/auth/models.d.ts +63 -0
- package/dist/server/server/auth/models.d.ts.map +1 -0
- package/dist/server/server/cli.d.ts +3 -0
- package/dist/server/server/cli.d.ts.map +1 -0
- package/dist/server/server/cli.js +669 -0
- package/dist/server/server/cli.js.map +1 -0
- package/dist/server/server/cliArguments.d.ts +21 -0
- package/dist/server/server/cliArguments.d.ts.map +1 -0
- package/dist/server/server/cliConfiguration.d.ts +20 -0
- package/dist/server/server/cliConfiguration.d.ts.map +1 -0
- package/dist/server/server/governance/governedActionAuthority.d.ts +54 -0
- package/dist/server/server/governance/governedActionAuthority.d.ts.map +1 -0
- package/dist/server/server/governance/governedActionDigests.d.ts +1348 -0
- package/dist/server/server/governance/governedActionDigests.d.ts.map +1 -0
- package/dist/server/server/governance/internal/GovernedActionExecutionEngine.d.ts +55 -0
- package/dist/server/server/governance/internal/GovernedActionExecutionEngine.d.ts.map +1 -0
- package/dist/server/server/governance/internal/GovernedActionExecutionStore.d.ts +116 -0
- package/dist/server/server/governance/internal/GovernedActionExecutionStore.d.ts.map +1 -0
- package/dist/server/server/governance/internal/GovernedActionPolicyEvaluator.d.ts +120 -0
- package/dist/server/server/governance/internal/GovernedActionPolicyEvaluator.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/begin.d.ts +17 -0
- package/dist/server/server/governance/internal/execution-store/begin.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/current-evidence.d.ts +33 -0
- package/dist/server/server/governance/internal/execution-store/current-evidence.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/current-session.d.ts +29 -0
- package/dist/server/server/governance/internal/execution-store/current-session.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/current-target.d.ts +28 -0
- package/dist/server/server/governance/internal/execution-store/current-target.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/dispatch-inbox.d.ts +20 -0
- package/dist/server/server/governance/internal/execution-store/dispatch-inbox.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/dispatch-outcome.d.ts +78 -0
- package/dist/server/server/governance/internal/execution-store/dispatch-outcome.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/inspect.d.ts +17 -0
- package/dist/server/server/governance/internal/execution-store/inspect.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/live.d.ts +6 -0
- package/dist/server/server/governance/internal/execution-store/live.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/preparation.d.ts +42 -0
- package/dist/server/server/governance/internal/execution-store/preparation.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/provider-outcome-fold.d.ts +33 -0
- package/dist/server/server/governance/internal/execution-store/provider-outcome-fold.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-inbox.d.ts +20 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-inbox.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-locator.d.ts +5 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-locator.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-outcome.d.ts +123 -0
- package/dist/server/server/governance/internal/execution-store/reconciliation-outcome.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/record-blocked.d.ts +13 -0
- package/dist/server/server/governance/internal/execution-store/record-blocked.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/record-dispatch.d.ts +12 -0
- package/dist/server/server/governance/internal/execution-store/record-dispatch.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/record-reconciliation.d.ts +12 -0
- package/dist/server/server/governance/internal/execution-store/record-reconciliation.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/record-recovery-unavailable.d.ts +11 -0
- package/dist/server/server/governance/internal/execution-store/record-recovery-unavailable.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/record-unknown.d.ts +11 -0
- package/dist/server/server/governance/internal/execution-store/record-unknown.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/recovery-candidates.d.ts +12 -0
- package/dist/server/server/governance/internal/execution-store/recovery-candidates.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/recovery-claim-expiry.d.ts +9 -0
- package/dist/server/server/governance/internal/execution-store/recovery-claim-expiry.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/recovery-claim.d.ts +465 -0
- package/dist/server/server/governance/internal/execution-store/recovery-claim.d.ts.map +1 -0
- package/dist/server/server/governance/internal/execution-store/tokens.d.ts +52 -0
- package/dist/server/server/governance/internal/execution-store/tokens.d.ts.map +1 -0
- package/dist/server/server/http/StaticApplication.d.ts +8 -0
- package/dist/server/server/http/StaticApplication.d.ts.map +1 -0
- package/dist/server/server/http/index.d.ts +4 -0
- package/dist/server/server/http/index.d.ts.map +1 -0
- package/dist/server/server/http/security/HttpLimits.d.ts +22 -0
- package/dist/server/server/http/security/HttpLimits.d.ts.map +1 -0
- package/dist/server/server/http/security/RequestPolicy.d.ts +26 -0
- package/dist/server/server/http/security/RequestPolicy.d.ts.map +1 -0
- package/dist/server/server/http/security/RichDocument.d.ts +154 -0
- package/dist/server/server/http/security/RichDocument.d.ts.map +1 -0
- package/dist/server/server/http/security/SecurityHeaders.d.ts +7 -0
- package/dist/server/server/http/security/SecurityHeaders.d.ts.map +1 -0
- package/dist/server/server/http/security/StaticAssetStore.d.ts +43 -0
- package/dist/server/server/http/security/StaticAssetStore.d.ts.map +1 -0
- package/dist/server/server/http/security/UrlPolicy.d.ts +30 -0
- package/dist/server/server/http/security/UrlPolicy.d.ts.map +1 -0
- package/dist/server/server/http/security/index.d.ts +8 -0
- package/dist/server/server/http/security/index.d.ts.map +1 -0
- package/dist/server/server/index.d.ts +18 -0
- package/dist/server/server/index.d.ts.map +1 -0
- package/dist/server/server/index.js +583 -0
- package/dist/server/server/index.js.map +1 -0
- package/dist/server/server/observability.d.ts +13 -0
- package/dist/server/server/observability.d.ts.map +1 -0
- package/dist/server/server/persistence/ContentStore.d.ts +86 -0
- package/dist/server/server/persistence/ContentStore.d.ts.map +1 -0
- package/dist/server/server/persistence/Database.d.ts +26 -0
- package/dist/server/server/persistence/Database.d.ts.map +1 -0
- package/dist/server/server/persistence/Persistence.d.ts +7042 -0
- package/dist/server/server/persistence/Persistence.d.ts.map +1 -0
- package/dist/server/server/persistence/PersistenceConfig.d.ts +27 -0
- package/dist/server/server/persistence/PersistenceConfig.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/BackupArchive.d.ts +32 -0
- package/dist/server/server/persistence/backup/BackupArchive.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/BackupArchiveCore.d.ts +23 -0
- package/dist/server/server/persistence/backup/BackupArchiveCore.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/BackupManifest.d.ts +136 -0
- package/dist/server/server/persistence/backup/BackupManifest.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/DatabaseSnapshot.d.ts +53 -0
- package/dist/server/server/persistence/backup/DatabaseSnapshot.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/errors.d.ts +53 -0
- package/dist/server/server/persistence/backup/errors.d.ts.map +1 -0
- package/dist/server/server/persistence/backup/index.d.ts +4 -0
- package/dist/server/server/persistence/backup/index.d.ts.map +1 -0
- package/dist/server/server/persistence/errors.d.ts +99 -0
- package/dist/server/server/persistence/errors.d.ts.map +1 -0
- package/dist/server/server/persistence/governedActionReconciliationLocator.d.ts +14 -0
- package/dist/server/server/persistence/governedActionReconciliationLocator.d.ts.map +1 -0
- package/dist/server/server/persistence/index.d.ts +11 -0
- package/dist/server/server/persistence/index.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobDigest.d.ts +6 -0
- package/dist/server/server/persistence/object-store/BlobDigest.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobPath.d.ts +12 -0
- package/dist/server/server/persistence/object-store/BlobPath.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobPublisher.d.ts +8 -0
- package/dist/server/server/persistence/object-store/BlobPublisher.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobRef.d.ts +16 -0
- package/dist/server/server/persistence/object-store/BlobRef.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobStore.d.ts +37 -0
- package/dist/server/server/persistence/object-store/BlobStore.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobStoreError.d.ts +57 -0
- package/dist/server/server/persistence/object-store/BlobStoreError.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/BlobStoreTypes.d.ts +28 -0
- package/dist/server/server/persistence/object-store/BlobStoreTypes.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/OpenedBlob.d.ts +21 -0
- package/dist/server/server/persistence/object-store/OpenedBlob.d.ts.map +1 -0
- package/dist/server/server/persistence/object-store/PinnedDirectory.d.ts +21 -0
- package/dist/server/server/persistence/object-store/PinnedDirectory.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/agentJobModels.d.ts +142 -0
- package/dist/server/server/persistence/repositories/agentJobModels.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/agentJobRepository.d.ts +134 -0
- package/dist/server/server/persistence/repositories/agentJobRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/authorizedShareRepository.d.ts +92 -0
- package/dist/server/server/persistence/repositories/authorizedShareRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/contentBlobMetadataRepository.d.ts +67 -0
- package/dist/server/server/persistence/repositories/contentBlobMetadataRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts +2989 -0
- package/dist/server/server/persistence/repositories/delivery-graph/contract.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts +566 -0
- package/dist/server/server/persistence/repositories/delivery-graph/decode.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/integrity.d.ts +16 -0
- package/dist/server/server/persistence/repositories/delivery-graph/integrity.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/quarantine.d.ts +22 -0
- package/dist/server/server/persistence/repositories/delivery-graph/quarantine.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts +2147 -0
- package/dist/server/server/persistence/repositories/delivery-graph/read.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/release-slice.d.ts +16 -0
- package/dist/server/server/persistence/repositories/delivery-graph/release-slice.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts +683 -0
- package/dist/server/server/persistence/repositories/delivery-graph/rows.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts +946 -0
- package/dist/server/server/persistence/repositories/delivery-graph/write.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts +2121 -0
- package/dist/server/server/persistence/repositories/deliveryGraphRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/domainEventModels.d.ts +89 -0
- package/dist/server/server/persistence/repositories/domainEventModels.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/domainEventRepository.d.ts +85 -0
- package/dist/server/server/persistence/repositories/domainEventRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/entityRepository.d.ts +134 -0
- package/dist/server/server/persistence/repositories/entityRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/codec.d.ts +1478 -0
- package/dist/server/server/persistence/repositories/governed-action/codec.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/contract.d.ts +858 -0
- package/dist/server/server/persistence/repositories/governed-action/contract.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/quarantine.d.ts +22 -0
- package/dist/server/server/persistence/repositories/governed-action/quarantine.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/read.d.ts +452 -0
- package/dist/server/server/persistence/repositories/governed-action/read.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/rows.d.ts +115 -0
- package/dist/server/server/persistence/repositories/governed-action/rows.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/transaction.d.ts +457 -0
- package/dist/server/server/persistence/repositories/governed-action/transaction.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/write-preparation.d.ts +518 -0
- package/dist/server/server/persistence/repositories/governed-action/write-preparation.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/write-replay.d.ts +702 -0
- package/dist/server/server/persistence/repositories/governed-action/write-replay.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governed-action/write.d.ts +618 -0
- package/dist/server/server/persistence/repositories/governed-action/write.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/governedActionRepository.d.ts +467 -0
- package/dist/server/server/persistence/repositories/governedActionRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/index.d.ts +26 -0
- package/dist/server/server/persistence/repositories/index.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/internal.d.ts +38 -0
- package/dist/server/server/persistence/repositories/internal.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/models.d.ts +420 -0
- package/dist/server/server/persistence/repositories/models.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/peopleRepository.d.ts +407 -0
- package/dist/server/server/persistence/repositories/peopleRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/persistedRowQuarantine.d.ts +20 -0
- package/dist/server/server/persistence/repositories/persistedRowQuarantine.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/pluginConfigurationModels.d.ts +76 -0
- package/dist/server/server/persistence/repositories/pluginConfigurationModels.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/pluginConfigurationRepository.d.ts +179 -0
- package/dist/server/server/persistence/repositories/pluginConfigurationRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/pluginConnectionRepository.d.ts +123 -0
- package/dist/server/server/persistence/repositories/pluginConnectionRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/pluginRuntimeModels.d.ts +195 -0
- package/dist/server/server/persistence/repositories/pluginRuntimeModels.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/pluginRuntimeRepository.d.ts +431 -0
- package/dist/server/server/persistence/repositories/pluginRuntimeRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/providerAccountRepository.d.ts +150 -0
- package/dist/server/server/persistence/repositories/providerAccountRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/quarantineRepository.d.ts +42 -0
- package/dist/server/server/persistence/repositories/quarantineRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/assessments.d.ts +2679 -0
- package/dist/server/server/persistence/repositories/readiness/assessments.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/codec.d.ts +1368 -0
- package/dist/server/server/persistence/repositories/readiness/codec.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/contract.d.ts +3315 -0
- package/dist/server/server/persistence/repositories/readiness/contract.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/materialization.d.ts +459 -0
- package/dist/server/server/persistence/repositories/readiness/materialization.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/quarantine.d.ts +22 -0
- package/dist/server/server/persistence/repositories/readiness/quarantine.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/queue.d.ts +112 -0
- package/dist/server/server/persistence/repositories/readiness/queue.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/rows.d.ts +169 -0
- package/dist/server/server/persistence/repositories/readiness/rows.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readiness/rules.d.ts +85 -0
- package/dist/server/server/persistence/repositories/readiness/rules.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/readinessRepository.d.ts +1722 -0
- package/dist/server/server/persistence/repositories/readinessRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/relationshipRepairProposalRepository.d.ts +294 -0
- package/dist/server/server/persistence/repositories/relationshipRepairProposalRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/releaseRepository.d.ts +1062 -0
- package/dist/server/server/persistence/repositories/releaseRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/timelineExportAuditRepository.d.ts +39 -0
- package/dist/server/server/persistence/repositories/timelineExportAuditRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/timelineRepository.d.ts +84 -0
- package/dist/server/server/persistence/repositories/timelineRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/repositories/workspaceRepository.d.ts +52 -0
- package/dist/server/server/persistence/repositories/workspaceRepository.d.ts.map +1 -0
- package/dist/server/server/persistence/schema.d.ts +17 -0
- package/dist/server/server/persistence/schema.d.ts.map +1 -0
- package/dist/server/server/persistence/schemas.d.ts +14 -0
- package/dist/server/server/persistence/schemas.d.ts.map +1 -0
- package/dist/server/server/plugins/AtlassianBasicAuth.d.ts +2 -0
- package/dist/server/server/plugins/AtlassianBasicAuth.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginCapabilityCodecs.d.ts +357 -0
- package/dist/server/server/plugins/PluginCapabilityCodecs.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginConnection.d.ts +28 -0
- package/dist/server/server/plugins/PluginConnection.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginConnectionMap.d.ts +22 -0
- package/dist/server/server/plugins/PluginConnectionMap.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginDefinition.d.ts +9 -0
- package/dist/server/server/plugins/PluginDefinition.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginDefinitionV1.d.ts +11 -0
- package/dist/server/server/plugins/PluginDefinitionV1.d.ts.map +1 -0
- package/dist/server/server/plugins/PluginExecutor.d.ts +14 -0
- package/dist/server/server/plugins/PluginExecutor.d.ts.map +1 -0
- package/dist/server/server/plugins/atlassian/AtlassianOAuthGrants.d.ts +35 -0
- package/dist/server/server/plugins/atlassian/AtlassianOAuthGrants.d.ts.map +1 -0
- package/dist/server/server/plugins/atlassian/AtlassianProfiles.d.ts +39 -0
- package/dist/server/server/plugins/atlassian/AtlassianProfiles.d.ts.map +1 -0
- package/dist/server/server/plugins/catalog/firstPartyServiceCatalog.d.ts +13 -0
- package/dist/server/server/plugins/catalog/firstPartyServiceCatalog.d.ts.map +1 -0
- package/dist/server/server/plugins/clockify/ClockifyReadPlugin.d.ts +78 -0
- package/dist/server/server/plugins/clockify/ClockifyReadPlugin.d.ts.map +1 -0
- package/dist/server/server/plugins/clockify/ClockifyReadProvider.d.ts +2 -0
- package/dist/server/server/plugins/clockify/ClockifyReadProvider.d.ts.map +1 -0
- package/dist/server/server/plugins/clockify/ClockifyTimeEntryNormalization.d.ts +2 -0
- package/dist/server/server/plugins/clockify/ClockifyTimeEntryNormalization.d.ts.map +1 -0
- package/dist/server/server/plugins/clockify/index.d.ts +3 -0
- package/dist/server/server/plugins/clockify/index.d.ts.map +1 -0
- package/dist/server/server/plugins/codecommit/CodeCommitPluginDefinition.d.ts +4 -0
- package/dist/server/server/plugins/codecommit/CodeCommitPluginDefinition.d.ts.map +1 -0
- package/dist/server/server/plugins/codecommit/index.d.ts +3 -0
- package/dist/server/server/plugins/codecommit/index.d.ts.map +1 -0
- package/dist/server/server/plugins/codepipeline/CodePipelinePluginDefinition.d.ts +4 -0
- package/dist/server/server/plugins/codepipeline/CodePipelinePluginDefinition.d.ts.map +1 -0
- package/dist/server/server/plugins/codepipeline/CodePipelineReadClient.d.ts +2 -0
- package/dist/server/server/plugins/codepipeline/CodePipelineReadClient.d.ts.map +1 -0
- package/dist/server/server/plugins/codepipeline/CodePipelineReadProvider.d.ts +2 -0
- package/dist/server/server/plugins/codepipeline/CodePipelineReadProvider.d.ts.map +1 -0
- package/dist/server/server/plugins/codepipeline/index.d.ts +3 -0
- package/dist/server/server/plugins/codepipeline/index.d.ts.map +1 -0
- package/dist/server/server/plugins/confluence/ConfluencePageAdapter.d.ts +2 -0
- package/dist/server/server/plugins/confluence/ConfluencePageAdapter.d.ts.map +1 -0
- package/dist/server/server/plugins/confluence/ConfluencePageClient.d.ts +2 -0
- package/dist/server/server/plugins/confluence/ConfluencePageClient.d.ts.map +1 -0
- package/dist/server/server/plugins/confluence/ConfluencePagePluginDefinition.d.ts +44 -0
- package/dist/server/server/plugins/confluence/ConfluencePagePluginDefinition.d.ts.map +1 -0
- package/dist/server/server/plugins/confluence/ConfluencePageSchemas.d.ts +2 -0
- package/dist/server/server/plugins/confluence/ConfluencePageSchemas.d.ts.map +1 -0
- package/dist/server/server/plugins/confluence/SafeConfluenceMarkdown.d.ts +2 -0
- package/dist/server/server/plugins/confluence/SafeConfluenceMarkdown.d.ts.map +1 -0
- package/dist/server/server/plugins/failures.d.ts +79 -0
- package/dist/server/server/plugins/failures.d.ts.map +1 -0
- package/dist/server/server/plugins/fake/FakePluginDefinition.d.ts +17 -0
- package/dist/server/server/plugins/fake/FakePluginDefinition.d.ts.map +1 -0
- package/dist/server/server/plugins/fake/FakePluginProbe.d.ts +40 -0
- package/dist/server/server/plugins/fake/FakePluginProbe.d.ts.map +1 -0
- package/dist/server/server/plugins/fake/FakePluginScenario.d.ts +46 -0
- package/dist/server/server/plugins/fake/FakePluginScenario.d.ts.map +1 -0
- package/dist/server/server/plugins/firstPartySynchronization.d.ts +7 -0
- package/dist/server/server/plugins/firstPartySynchronization.d.ts.map +1 -0
- package/dist/server/server/plugins/index.d.ts +21 -0
- package/dist/server/server/plugins/index.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/AuthorizedPluginExecutor.d.ts +8 -0
- package/dist/server/server/plugins/internal/AuthorizedPluginExecutor.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/AuthorizedPluginExecutorMap.d.ts +27 -0
- package/dist/server/server/plugins/internal/AuthorizedPluginExecutorMap.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/FirstPartyPluginRuntimeRegistry.d.ts +2 -0
- package/dist/server/server/plugins/internal/FirstPartyPluginRuntimeRegistry.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntime.d.ts +13 -0
- package/dist/server/server/plugins/internal/PluginRuntime.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthority.d.ts +154 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthority.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthorityRepository.d.ts +131 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthorityRepository.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthoritySource.d.ts +23 -0
- package/dist/server/server/plugins/internal/PluginRuntimeAuthoritySource.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntimeMap.d.ts +23 -0
- package/dist/server/server/plugins/internal/PluginRuntimeMap.d.ts.map +1 -0
- package/dist/server/server/plugins/internal/PluginRuntimeRegistry.d.ts +21 -0
- package/dist/server/server/plugins/internal/PluginRuntimeRegistry.d.ts.map +1 -0
- package/dist/server/server/plugins/jira/JiraIssueNormalization.d.ts +2 -0
- package/dist/server/server/plugins/jira/JiraIssueNormalization.d.ts.map +1 -0
- package/dist/server/server/plugins/jira/JiraReadPlugin.d.ts +74 -0
- package/dist/server/server/plugins/jira/JiraReadPlugin.d.ts.map +1 -0
- package/dist/server/server/plugins/jira/JiraReadProvider.d.ts +7 -0
- package/dist/server/server/plugins/jira/JiraReadProvider.d.ts.map +1 -0
- package/dist/server/server/plugins/jira/index.d.ts +3 -0
- package/dist/server/server/plugins/jira/index.d.ts.map +1 -0
- package/dist/server/server/plugins/negotiation.d.ts +75 -0
- package/dist/server/server/plugins/negotiation.d.ts.map +1 -0
- package/dist/server/server/plugins/retryPolicy.d.ts +28 -0
- package/dist/server/server/plugins/retryPolicy.d.ts.map +1 -0
- package/dist/server/server/readinessDigests.d.ts +103 -0
- package/dist/server/server/readinessDigests.d.ts.map +1 -0
- package/dist/server/server/runtime/Bootstrap.d.ts +39 -0
- package/dist/server/server/runtime/Bootstrap.d.ts.map +1 -0
- package/dist/server/server/runtime/ControlCenterServer.d.ts +57 -0
- package/dist/server/server/runtime/ControlCenterServer.d.ts.map +1 -0
- package/dist/server/server/runtime/DatabaseDrain.d.ts +6 -0
- package/dist/server/server/runtime/DatabaseDrain.d.ts.map +1 -0
- package/dist/server/server/runtime/DomainEventWakeups.d.ts +22 -0
- package/dist/server/server/runtime/DomainEventWakeups.d.ts.map +1 -0
- package/dist/server/server/runtime/FirstPartyPluginRuntime.d.ts +2 -0
- package/dist/server/server/runtime/FirstPartyPluginRuntime.d.ts.map +1 -0
- package/dist/server/server/runtime/GovernedActionExecutionStartup.d.ts +35 -0
- package/dist/server/server/runtime/GovernedActionExecutionStartup.d.ts.map +1 -0
- package/dist/server/server/runtime/NodeTransport.d.ts +57 -0
- package/dist/server/server/runtime/NodeTransport.d.ts.map +1 -0
- package/dist/server/server/runtime/ReleaseSynchronizationStartup.d.ts +44 -0
- package/dist/server/server/runtime/ReleaseSynchronizationStartup.d.ts.map +1 -0
- package/dist/server/server/runtime/RequestUrlBoundary.d.ts +4 -0
- package/dist/server/server/runtime/RequestUrlBoundary.d.ts.map +1 -0
- package/dist/server/server/runtime/ServerLifecycle.d.ts +74 -0
- package/dist/server/server/runtime/ServerLifecycle.d.ts.map +1 -0
- package/dist/server/server/runtime/index.d.ts +9 -0
- package/dist/server/server/runtime/index.d.ts.map +1 -0
- package/dist/server/server/secrets/SecretRef.d.ts +6 -0
- package/dist/server/server/secrets/SecretRef.d.ts.map +1 -0
- package/dist/server/server/secrets/SecretStore.d.ts +39 -0
- package/dist/server/server/secrets/SecretStore.d.ts.map +1 -0
- package/dist/server/server/secrets/SecretStoreError.d.ts +41 -0
- package/dist/server/server/secrets/SecretStoreError.d.ts.map +1 -0
- package/dist/server/server/secrets/index.d.ts +5 -0
- package/dist/server/server/secrets/index.d.ts.map +1 -0
- package/dist/server/server/security/BindConfig.d.ts +51 -0
- package/dist/server/server/security/BindConfig.d.ts.map +1 -0
- package/dist/server/server/security/RequestSecurity.d.ts +84 -0
- package/dist/server/server/security/RequestSecurity.d.ts.map +1 -0
- package/dist/server/server/security/index.d.ts +3 -0
- package/dist/server/server/security/index.d.ts.map +1 -0
- package/package.json +101 -0
|
@@ -0,0 +1,1805 @@
|
|
|
1
|
+
import { Cr as EntityId, Dr as EvidenceId, Er as EvidenceClaimId, F as EvidenceValue, Fr as PersonId, H as RelationshipKind, Hr as ReleaseId, It as deriveReleaseRelay, N as EvidencePredicate, Nr as GraphNodeId, R as LedgerRevision, Vt as Person, dr as PluginHealth, mt as NegotiatedPluginDescriptorV1, pr as NormalizationSchemaVersion, qt as derivePersonInitials, rt as NormalizedIssueAttributes, vr as VendorImmutableId, wr as EnvironmentId, xt as Release, zr as RelationshipId } from "./domainEvent-x7yeq-gU.js";
|
|
2
|
+
import { Ct as PluginCheckpointV1, jt as PluginSyncRequestV1 } from "./readiness-CzU3vjYQ.js";
|
|
3
|
+
import { Kn as PersistenceOperationError, L as Persistence, Ot as DeliveryGraphWriteBatch, Q as PluginMalformedResponseFailure, S as ApplicationInvalidRequest, T as ApplicationServiceUnavailable, Z as PluginConflictFailure, i as supportsFirstPartySynchronization, it as pluginFailureClass, n as DomainEventWakeups, r as firstPartySyncStreamKey, st as PluginStreamKey, t as appendPortfolioInvalidation, v as PluginConnection, w as ApplicationResourceNotFound } from "./portfolioInvalidation-Ds9Xm4_P.js";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import * as DateTime from "effect/DateTime";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Result from "effect/Result";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Encoding from "effect/Encoding";
|
|
10
|
+
import * as Option from "effect/Option";
|
|
11
|
+
import * as Predicate from "effect/Predicate";
|
|
12
|
+
import * as Stream from "effect/Stream";
|
|
13
|
+
import * as Crypto from "effect/Crypto";
|
|
14
|
+
import * as Clock from "effect/Clock";
|
|
15
|
+
//#region src/server/application/pluginSynchronizationAuthority.ts
|
|
16
|
+
var conflict = () => new PluginConflictFailure({
|
|
17
|
+
operation: "manual-sync",
|
|
18
|
+
diagnosticCode: "manual-sync-runtime-authority-changed"
|
|
19
|
+
});
|
|
20
|
+
var authorityFor = Effect.fn("PluginSynchronizationAuthority.forConnection")(function* (persistence, connection) {
|
|
21
|
+
const configuration = yield* persistence.pluginConfigurations.get(connection.workspaceId, connection.pluginConnectionId);
|
|
22
|
+
return {
|
|
23
|
+
workspaceId: connection.workspaceId,
|
|
24
|
+
pluginConnectionId: connection.pluginConnectionId,
|
|
25
|
+
providerId: connection.providerId,
|
|
26
|
+
connectionRevision: connection.revision,
|
|
27
|
+
configurationRevision: Option.isSome(configuration) ? configuration.value.revision : null
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
/** Capture connection and configuration revisions in one durable read transaction. */
|
|
31
|
+
var capturePluginSynchronizationAuthority = Effect.fn("PluginSynchronizationAuthority.capture")(function* (persistence, workspaceId, pluginConnectionId) {
|
|
32
|
+
return yield* persistence.transact(Effect.gen(function* () {
|
|
33
|
+
const connection = yield* persistence.pluginConnections.get(workspaceId, pluginConnectionId);
|
|
34
|
+
return {
|
|
35
|
+
connection,
|
|
36
|
+
authority: yield* authorityFor(persistence, connection)
|
|
37
|
+
};
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
/** Reject a write transaction when its runtime no longer owns current connection authority. */
|
|
41
|
+
var verifyPluginSynchronizationAuthority = Effect.fn("PluginSynchronizationAuthority.verify")(function* (persistence, expected) {
|
|
42
|
+
const connection = yield* persistence.pluginConnections.get(expected.workspaceId, expected.pluginConnectionId).pipe(Effect.catchTag("RecordNotFoundError", () => conflict()));
|
|
43
|
+
const current = yield* authorityFor(persistence, connection);
|
|
44
|
+
if (!connection.isEnabled || current.providerId !== expected.providerId || current.connectionRevision !== expected.connectionRevision || current.configurationRevision !== expected.configurationRevision) return yield* conflict();
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/server/application/relationshipInference.ts
|
|
48
|
+
var MAXIMUM_INFERENCE_CANDIDATES = 2e3;
|
|
49
|
+
var addCandidate = (accumulator, candidate) => {
|
|
50
|
+
if (accumulator.candidates.length >= MAXIMUM_INFERENCE_CANDIDATES) {
|
|
51
|
+
accumulator.truncated = true;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
accumulator.candidates.push(candidate);
|
|
55
|
+
};
|
|
56
|
+
var OWNED_RULE_IDS = /* @__PURE__ */ new Set([
|
|
57
|
+
"codepipeline-trigger-revision-v1",
|
|
58
|
+
"confluence-jira-link-v1",
|
|
59
|
+
"confluence-release-link-v1",
|
|
60
|
+
"jira-key-in-clockify-description-v1",
|
|
61
|
+
"jira-key-in-confluence-metadata-v1",
|
|
62
|
+
"jira-key-in-pull-request-metadata-v1",
|
|
63
|
+
"release-in-confluence-metadata-v1"
|
|
64
|
+
]);
|
|
65
|
+
var present = (entity) => entity.projection.entityState === "present";
|
|
66
|
+
var resolved = (kind, nodeId) => ({
|
|
67
|
+
_tag: "resolved",
|
|
68
|
+
kind,
|
|
69
|
+
nodeId
|
|
70
|
+
});
|
|
71
|
+
var missing = (kind, missingKey, identityKey) => ({
|
|
72
|
+
_tag: "missing",
|
|
73
|
+
identityKey,
|
|
74
|
+
kind,
|
|
75
|
+
missingKey
|
|
76
|
+
});
|
|
77
|
+
var currentRelationship = (relationship) => relationship.lifecycle._tag !== "missing" && relationship.lifecycle._tag !== "rejected" && relationship.lifecycle._tag !== "superseded";
|
|
78
|
+
var currentExternalRelationship = (relationship) => currentRelationship(relationship) && !(relationship.lifecycle._tag === "inferred" && relationship.provenance._tag === "rule" && OWNED_RULE_IDS.has(relationship.provenance.ruleId));
|
|
79
|
+
var currentOwnedRelationship = (relationship) => currentRelationship(relationship) && relationship.lifecycle._tag === "inferred" && relationship.provenance._tag === "rule" && OWNED_RULE_IDS.has(relationship.provenance.ruleId);
|
|
80
|
+
var currentInferenceRelationship = (relationship) => relationship.lifecycle._tag !== "rejected" && relationship.lifecycle._tag !== "superseded" && relationship.provenance._tag === "rule" && (relationship.provenance.ruleId === "delivery-gap-v1" || OWNED_RULE_IDS.has(relationship.provenance.ruleId));
|
|
81
|
+
var relationshipInRelease = (relationship, releaseId) => relationship.scope?._tag === "release" && relationship.scope.releaseId === releaseId;
|
|
82
|
+
var containsToken = (text, token) => {
|
|
83
|
+
const normalizedText = text.toUpperCase();
|
|
84
|
+
const normalizedToken = token.toUpperCase();
|
|
85
|
+
let offset = normalizedText.indexOf(normalizedToken);
|
|
86
|
+
while (offset >= 0) {
|
|
87
|
+
const before = normalizedText[offset - 1];
|
|
88
|
+
const after = normalizedText[offset + normalizedToken.length];
|
|
89
|
+
const boundary = (character) => character === void 0 || !/[A-Z0-9]/u.test(character);
|
|
90
|
+
if (boundary(before) && boundary(after)) return true;
|
|
91
|
+
offset = normalizedText.indexOf(normalizedToken, offset + normalizedToken.length);
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
};
|
|
95
|
+
var containsReleaseVersion = (text, version) => {
|
|
96
|
+
const normalizedText = text.toUpperCase();
|
|
97
|
+
const normalizedVersion = version.toUpperCase();
|
|
98
|
+
let offset = normalizedText.indexOf(normalizedVersion);
|
|
99
|
+
while (offset >= 0) {
|
|
100
|
+
const before = normalizedText[offset - 1];
|
|
101
|
+
const after = normalizedText[offset + normalizedVersion.length];
|
|
102
|
+
const boundary = (character) => character === void 0 || !/[A-Z0-9._+-]/u.test(character);
|
|
103
|
+
if (boundary(before) && boundary(after)) return true;
|
|
104
|
+
offset = normalizedText.indexOf(normalizedVersion, offset + normalizedVersion.length);
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
var metadata = (entity) => {
|
|
109
|
+
const details = entity.projection.details;
|
|
110
|
+
return details._tag === "pull-request" ? [
|
|
111
|
+
entity.projection.title,
|
|
112
|
+
entity.projection.displayKey,
|
|
113
|
+
details.sourceBranch,
|
|
114
|
+
details.targetBranch
|
|
115
|
+
].join("\n") : [entity.projection.title, entity.projection.displayKey].join("\n");
|
|
116
|
+
};
|
|
117
|
+
var observationKey = (...entities) => entities.map(({ projection }) => `${projection.entityId}@${String(projection.projectionRevision)}`).sort().join("+");
|
|
118
|
+
var inferred = (input) => ({
|
|
119
|
+
...input,
|
|
120
|
+
lifecycle: "inferred"
|
|
121
|
+
});
|
|
122
|
+
var gap = (input) => ({
|
|
123
|
+
...input,
|
|
124
|
+
confidence: null,
|
|
125
|
+
evidenceEntityId: null,
|
|
126
|
+
lifecycle: "missing",
|
|
127
|
+
observationKey: input.identityKey,
|
|
128
|
+
ruleId: "delivery-gap-v1"
|
|
129
|
+
});
|
|
130
|
+
var candidateIdentity = (kind, releaseId, source, target) => `relationship:${kind}:${releaseId}:${source}:${target}`;
|
|
131
|
+
var issueGapIdentity = (releaseId, issueNodeId) => `gap:implements:${releaseId}:${issueNodeId}`;
|
|
132
|
+
var pipelineGapIdentity = (releaseId, pullRequestNodeId) => `gap:delivered-by:${releaseId}:${pullRequestNodeId}`;
|
|
133
|
+
var candidateGapKey = (candidate) => {
|
|
134
|
+
if (candidate.lifecycle !== "missing") return null;
|
|
135
|
+
if (candidate.kind === "implements" && candidate.target._tag === "resolved") return `${candidate.kind}:${candidate.releaseId}:${candidate.target.nodeId}`;
|
|
136
|
+
if (candidate.kind === "delivered-by" && candidate.source._tag === "resolved") return `${candidate.kind}:${candidate.releaseId}:${candidate.source.nodeId}`;
|
|
137
|
+
return null;
|
|
138
|
+
};
|
|
139
|
+
var relationshipGapKey = (relationship) => {
|
|
140
|
+
if (relationship.lifecycle._tag !== "missing" || relationship.provenance._tag !== "rule" || relationship.provenance.ruleId !== "delivery-gap-v1" || relationship.scope?._tag !== "release") return null;
|
|
141
|
+
if (relationship.kind === "implements") return `${relationship.kind}:${relationship.scope.releaseId}:${relationship.targetNodeId}`;
|
|
142
|
+
if (relationship.kind === "delivered-by") return `${relationship.kind}:${relationship.scope.releaseId}:${relationship.sourceNodeId}`;
|
|
143
|
+
return null;
|
|
144
|
+
};
|
|
145
|
+
var hasRelationship = (relationships, releaseId, kind, sourceNodeId, targetNodeId) => relationships.some((relationship) => currentExternalRelationship(relationship) && relationshipInRelease(relationship, releaseId) && relationship.kind === kind && (sourceNodeId === null || relationship.sourceNodeId === sourceNodeId) && (targetNodeId === null || relationship.targetNodeId === targetNodeId));
|
|
146
|
+
var addIssueAndTimeCandidates = (entities, accumulator) => {
|
|
147
|
+
const issues = entities.filter((entity) => entity.projection.details._tag === "issue");
|
|
148
|
+
const timeEntries = entities.filter((entity) => entity.projection.details._tag === "time-entry");
|
|
149
|
+
for (const timeEntry of timeEntries) for (const issue of issues) {
|
|
150
|
+
const details = issue.projection.details;
|
|
151
|
+
if (details._tag !== "issue" || !containsToken(metadata(timeEntry), details.key)) continue;
|
|
152
|
+
for (const releaseId of issue.releaseIds) addCandidate(accumulator, inferred({
|
|
153
|
+
confidence: {
|
|
154
|
+
score: .95,
|
|
155
|
+
rationale: `The Clockify description contains Jira key ${details.key}.`
|
|
156
|
+
},
|
|
157
|
+
evidenceEntityId: timeEntry.projection.entityId,
|
|
158
|
+
identityKey: candidateIdentity("tracks-time-for", releaseId, timeEntry.nodeId, issue.nodeId),
|
|
159
|
+
kind: "tracks-time-for",
|
|
160
|
+
observationKey: observationKey(timeEntry, issue),
|
|
161
|
+
releaseId,
|
|
162
|
+
ruleId: "jira-key-in-clockify-description-v1",
|
|
163
|
+
source: resolved("time-entry", timeEntry.nodeId),
|
|
164
|
+
target: resolved("issue", issue.nodeId)
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
var addDocumentationCandidates = (entities, releases, accumulator) => {
|
|
169
|
+
const issues = entities.filter((entity) => entity.projection.details._tag === "issue");
|
|
170
|
+
const releaseVersionCounts = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const release of releases) {
|
|
172
|
+
const version = release.version.toUpperCase();
|
|
173
|
+
releaseVersionCounts.set(version, (releaseVersionCounts.get(version) ?? 0) + 1);
|
|
174
|
+
}
|
|
175
|
+
const pages = entities.filter((entity) => entity.projection.details._tag === "page" && entity.projection.details.status === "current");
|
|
176
|
+
for (const page of pages) {
|
|
177
|
+
const pageDetails = page.projection.details;
|
|
178
|
+
if (pageDetails._tag !== "page") continue;
|
|
179
|
+
const pageMetadata = metadata(page);
|
|
180
|
+
for (const issue of issues) {
|
|
181
|
+
const details = issue.projection.details;
|
|
182
|
+
if (details._tag !== "issue") continue;
|
|
183
|
+
const explicitLink = pageDetails.linkedIssueKeys?.some((key) => key.toUpperCase() === details.key.toUpperCase()) ?? false;
|
|
184
|
+
if (!explicitLink && !containsToken(pageMetadata, details.key)) continue;
|
|
185
|
+
for (const releaseId of issue.releaseIds) addCandidate(accumulator, inferred({
|
|
186
|
+
confidence: {
|
|
187
|
+
score: explicitLink ? .97 : .9,
|
|
188
|
+
rationale: explicitLink ? `Confluence metadata links Jira key ${details.key}.` : `Confluence page metadata contains Jira key ${details.key}.`
|
|
189
|
+
},
|
|
190
|
+
evidenceEntityId: page.projection.entityId,
|
|
191
|
+
identityKey: candidateIdentity("documented-by", releaseId, issue.nodeId, page.nodeId),
|
|
192
|
+
kind: "documented-by",
|
|
193
|
+
observationKey: observationKey(page, issue),
|
|
194
|
+
releaseId,
|
|
195
|
+
ruleId: explicitLink ? "confluence-jira-link-v1" : "jira-key-in-confluence-metadata-v1",
|
|
196
|
+
source: resolved("issue", issue.nodeId),
|
|
197
|
+
target: resolved("page", page.nodeId)
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
for (const release of releases) {
|
|
201
|
+
if ((releaseVersionCounts.get(release.version.toUpperCase()) ?? 0) > 1) continue;
|
|
202
|
+
const explicitLink = pageDetails.linkedReleaseVersions?.some((version) => version.toUpperCase() === release.version.toUpperCase()) ?? false;
|
|
203
|
+
if (!explicitLink && !containsReleaseVersion(pageMetadata, release.version)) continue;
|
|
204
|
+
addCandidate(accumulator, inferred({
|
|
205
|
+
confidence: {
|
|
206
|
+
score: explicitLink ? .96 : .88,
|
|
207
|
+
rationale: explicitLink ? `Confluence metadata links release ${release.version}.` : `Confluence page metadata contains release ${release.version}.`
|
|
208
|
+
},
|
|
209
|
+
evidenceEntityId: page.projection.entityId,
|
|
210
|
+
identityKey: candidateIdentity("documented-by", release.releaseId, release.nodeId, page.nodeId),
|
|
211
|
+
kind: "documented-by",
|
|
212
|
+
observationKey: observationKey(page),
|
|
213
|
+
releaseId: release.releaseId,
|
|
214
|
+
ruleId: explicitLink ? "confluence-release-link-v1" : "release-in-confluence-metadata-v1",
|
|
215
|
+
source: resolved("release", release.nodeId),
|
|
216
|
+
target: resolved("page", page.nodeId)
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Infer a deterministic relationship set from current canonical facts. Rules
|
|
223
|
+
* only propose `inferred` or `missing`; confirmation remains governed.
|
|
224
|
+
*/
|
|
225
|
+
var deriveRelationshipInference = (input) => {
|
|
226
|
+
const entities = input.entities.filter(present).map((entity) => ({
|
|
227
|
+
...entity,
|
|
228
|
+
releaseIds: entity.releaseIds.filter((releaseId) => {
|
|
229
|
+
const touchesEntity = (relationship) => relationshipInRelease(relationship, releaseId) && (relationship.sourceNodeId === entity.nodeId || relationship.targetNodeId === entity.nodeId);
|
|
230
|
+
return !input.relationships.some((relationship) => currentInferenceRelationship(relationship) && touchesEntity(relationship)) || input.relationships.some((relationship) => currentExternalRelationship(relationship) && touchesEntity(relationship));
|
|
231
|
+
})
|
|
232
|
+
}));
|
|
233
|
+
const issues = entities.filter((entity) => entity.projection.details._tag === "issue");
|
|
234
|
+
const pullRequests = entities.filter((entity) => entity.projection.details._tag === "pull-request");
|
|
235
|
+
const pipelines = entities.filter((entity) => entity.projection.details._tag === "pipeline-execution");
|
|
236
|
+
const accumulator = {
|
|
237
|
+
candidates: [],
|
|
238
|
+
truncated: false
|
|
239
|
+
};
|
|
240
|
+
const obsoleteGaps = /* @__PURE__ */ new Set();
|
|
241
|
+
const inferredIssueLinks = /* @__PURE__ */ new Set();
|
|
242
|
+
const pullRequestReleases = /* @__PURE__ */ new Map();
|
|
243
|
+
for (const pullRequest of pullRequests) {
|
|
244
|
+
if (pullRequest.projection.details._tag !== "pull-request") continue;
|
|
245
|
+
const releaseIds = new Set(pullRequest.releaseIds.filter((releaseId) => {
|
|
246
|
+
const touchesPullRequest = (relationship) => relationshipInRelease(relationship, releaseId) && (relationship.sourceNodeId === pullRequest.nodeId || relationship.targetNodeId === pullRequest.nodeId);
|
|
247
|
+
return !input.relationships.some((relationship) => currentOwnedRelationship(relationship) && touchesPullRequest(relationship)) || input.relationships.some((relationship) => currentExternalRelationship(relationship) && touchesPullRequest(relationship));
|
|
248
|
+
}));
|
|
249
|
+
for (const issue of issues) {
|
|
250
|
+
const issueDetails = issue.projection.details;
|
|
251
|
+
if (issueDetails._tag !== "issue" || !containsToken(metadata(pullRequest), issueDetails.key)) continue;
|
|
252
|
+
for (const releaseId of issue.releaseIds) {
|
|
253
|
+
const identityKey = candidateIdentity("implements", releaseId, pullRequest.nodeId, issue.nodeId);
|
|
254
|
+
if (!(input.rejectedCandidateIdentityKeys?.has(identityKey) ?? false)) {
|
|
255
|
+
releaseIds.add(releaseId);
|
|
256
|
+
inferredIssueLinks.add(`${releaseId}:${issue.nodeId}`);
|
|
257
|
+
obsoleteGaps.add(issueGapIdentity(releaseId, issue.nodeId));
|
|
258
|
+
}
|
|
259
|
+
addCandidate(accumulator, inferred({
|
|
260
|
+
confidence: {
|
|
261
|
+
score: containsToken(pullRequest.projection.title, issueDetails.key) ? .98 : .94,
|
|
262
|
+
rationale: `The immutable pull-request metadata contains Jira key ${issueDetails.key}.`
|
|
263
|
+
},
|
|
264
|
+
evidenceEntityId: pullRequest.projection.entityId,
|
|
265
|
+
identityKey,
|
|
266
|
+
kind: "implements",
|
|
267
|
+
observationKey: observationKey(pullRequest, issue),
|
|
268
|
+
releaseId,
|
|
269
|
+
ruleId: "jira-key-in-pull-request-metadata-v1",
|
|
270
|
+
source: resolved("pull-request", pullRequest.nodeId),
|
|
271
|
+
target: resolved("issue", issue.nodeId)
|
|
272
|
+
}));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
for (const relationship of input.relationships) if (currentExternalRelationship(relationship) && relationship.kind === "implements" && relationship.sourceNodeId === pullRequest.nodeId && relationship.scope?._tag === "release") releaseIds.add(relationship.scope.releaseId);
|
|
276
|
+
pullRequestReleases.set(pullRequest.nodeId, releaseIds);
|
|
277
|
+
}
|
|
278
|
+
for (const issue of issues) for (const releaseId of issue.releaseIds) {
|
|
279
|
+
const identityKey = issueGapIdentity(releaseId, issue.nodeId);
|
|
280
|
+
if (inferredIssueLinks.has(`${releaseId}:${issue.nodeId}`) || hasRelationship(input.relationships, releaseId, "implements", null, issue.nodeId)) obsoleteGaps.add(identityKey);
|
|
281
|
+
else {
|
|
282
|
+
const details = issue.projection.details;
|
|
283
|
+
if (details._tag !== "issue") continue;
|
|
284
|
+
addCandidate(accumulator, gap({
|
|
285
|
+
identityKey,
|
|
286
|
+
kind: "implements",
|
|
287
|
+
releaseId,
|
|
288
|
+
source: missing("pull-request", `${details.key}:pull-request`, issue.nodeId),
|
|
289
|
+
target: resolved("issue", issue.nodeId)
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const inferredPipelineLinks = /* @__PURE__ */ new Set();
|
|
294
|
+
for (const pullRequest of pullRequests) {
|
|
295
|
+
const pullRequestDetails = pullRequest.projection.details;
|
|
296
|
+
if (pullRequestDetails._tag !== "pull-request") continue;
|
|
297
|
+
for (const pipeline of pipelines) {
|
|
298
|
+
const pipelineDetails = pipeline.projection.details;
|
|
299
|
+
if (pipelineDetails._tag !== "pipeline-execution" || pipelineDetails.triggerRevision !== pullRequestDetails.headRevision) continue;
|
|
300
|
+
for (const releaseId of pullRequestReleases.get(pullRequest.nodeId) ?? []) {
|
|
301
|
+
const identityKey = candidateIdentity("delivered-by", releaseId, pullRequest.nodeId, pipeline.nodeId);
|
|
302
|
+
if (!(input.rejectedCandidateIdentityKeys?.has(identityKey) ?? false)) {
|
|
303
|
+
inferredPipelineLinks.add(`${releaseId}:${pullRequest.nodeId}`);
|
|
304
|
+
obsoleteGaps.add(pipelineGapIdentity(releaseId, pullRequest.nodeId));
|
|
305
|
+
}
|
|
306
|
+
addCandidate(accumulator, inferred({
|
|
307
|
+
confidence: {
|
|
308
|
+
score: .99,
|
|
309
|
+
rationale: `The pipeline trigger revision exactly matches pull-request head ${pullRequestDetails.headRevision}.`
|
|
310
|
+
},
|
|
311
|
+
evidenceEntityId: pipeline.projection.entityId,
|
|
312
|
+
identityKey,
|
|
313
|
+
kind: "delivered-by",
|
|
314
|
+
observationKey: observationKey(pullRequest, pipeline),
|
|
315
|
+
releaseId,
|
|
316
|
+
ruleId: "codepipeline-trigger-revision-v1",
|
|
317
|
+
source: resolved("pull-request", pullRequest.nodeId),
|
|
318
|
+
target: resolved("pipeline-execution", pipeline.nodeId)
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
for (const pullRequest of pullRequests) for (const releaseId of pullRequestReleases.get(pullRequest.nodeId) ?? []) {
|
|
324
|
+
const identityKey = pipelineGapIdentity(releaseId, pullRequest.nodeId);
|
|
325
|
+
if (inferredPipelineLinks.has(`${releaseId}:${pullRequest.nodeId}`) || hasRelationship(input.relationships, releaseId, "delivered-by", pullRequest.nodeId, null) || hasRelationship(input.relationships, releaseId, "verified-by", pullRequest.nodeId, null)) obsoleteGaps.add(identityKey);
|
|
326
|
+
else addCandidate(accumulator, gap({
|
|
327
|
+
identityKey,
|
|
328
|
+
kind: "delivered-by",
|
|
329
|
+
releaseId,
|
|
330
|
+
source: resolved("pull-request", pullRequest.nodeId),
|
|
331
|
+
target: missing("pipeline-execution", `${pullRequest.projection.displayKey}:pipeline-execution`, pullRequest.nodeId)
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
addIssueAndTimeCandidates(entities, accumulator);
|
|
335
|
+
addDocumentationCandidates(entities, input.releases, accumulator);
|
|
336
|
+
const unique = new Map(accumulator.candidates.map((candidate) => [candidate.identityKey, candidate]));
|
|
337
|
+
const candidateEdges = new Set([...unique.values()].flatMap((candidate) => candidate.lifecycle === "inferred" && candidate.source._tag === "resolved" && candidate.target._tag === "resolved" ? [`${candidate.kind}:${candidate.releaseId}:${candidate.source.nodeId}:${candidate.target.nodeId}`] : []));
|
|
338
|
+
const candidateGaps = new Set([...unique.values()].flatMap((candidate) => {
|
|
339
|
+
const key = candidateGapKey(candidate);
|
|
340
|
+
return key === null ? [] : [key];
|
|
341
|
+
}));
|
|
342
|
+
const obsoleteRelationshipIds = input.relationships.flatMap((relationship) => {
|
|
343
|
+
const gapKey = relationshipGapKey(relationship);
|
|
344
|
+
const obsoleteInference = relationship.lifecycle._tag === "inferred" && relationship.provenance._tag === "rule" && OWNED_RULE_IDS.has(relationship.provenance.ruleId) && relationship.scope?._tag === "release" && !candidateEdges.has(`${relationship.kind}:${relationship.scope.releaseId}:${relationship.sourceNodeId}:${relationship.targetNodeId}`);
|
|
345
|
+
const obsoleteGap = gapKey !== null && !candidateGaps.has(gapKey);
|
|
346
|
+
return obsoleteInference || obsoleteGap ? [relationship.relationshipId] : [];
|
|
347
|
+
});
|
|
348
|
+
return {
|
|
349
|
+
candidates: [...unique.values()].sort((left, right) => left.identityKey.localeCompare(right.identityKey)),
|
|
350
|
+
obsoleteGapIdentityKeys: [...obsoleteGaps].sort(),
|
|
351
|
+
obsoleteRelationshipIds: [...new Set(obsoleteRelationshipIds)].sort(),
|
|
352
|
+
truncated: accumulator.truncated
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/server/application/relationshipInferenceMaterialization.ts
|
|
357
|
+
var MAXIMUM_INFERENCE_ENTITIES = 500;
|
|
358
|
+
var MAXIMUM_INFERENCE_RELEASES = 50;
|
|
359
|
+
var MAXIMUM_INFERENCE_RELATIONSHIPS = 2e3;
|
|
360
|
+
var COMPONENT = "relationship-inference";
|
|
361
|
+
var readRelationship = Effect.fn("RelationshipInferenceMaterialization.readRelationship")(function* (persistence, workspaceId, relationshipId) {
|
|
362
|
+
const result = yield* persistence.deliveryGraph.read(workspaceId, {
|
|
363
|
+
_tag: "relationship",
|
|
364
|
+
relationshipId,
|
|
365
|
+
revision: null
|
|
366
|
+
}).pipe(Effect.result);
|
|
367
|
+
if (Result.isFailure(result)) {
|
|
368
|
+
if (result.failure._tag === "RecordNotFoundError") return null;
|
|
369
|
+
return yield* result.failure;
|
|
370
|
+
}
|
|
371
|
+
return result.success._tag === "relationship" ? result.success.value : null;
|
|
372
|
+
});
|
|
373
|
+
var nodeExists = Effect.fn("RelationshipInferenceMaterialization.nodeExists")(function* (persistence, workspaceId, nodeId) {
|
|
374
|
+
const result = yield* persistence.deliveryGraph.read(workspaceId, {
|
|
375
|
+
_tag: "node",
|
|
376
|
+
nodeId
|
|
377
|
+
}).pipe(Effect.result);
|
|
378
|
+
if (Result.isSuccess(result)) return true;
|
|
379
|
+
if (result.failure._tag === "RecordNotFoundError") return false;
|
|
380
|
+
return yield* result.failure;
|
|
381
|
+
});
|
|
382
|
+
var writeGraph$1 = Effect.fn("RelationshipInferenceMaterialization.writeGraph")(function* (persistence, workspaceId, batch) {
|
|
383
|
+
const encoded = yield* Schema.encodeEffect(DeliveryGraphWriteBatch)(batch).pipe(Effect.mapError(() => new PersistenceOperationError({ operation: "relationship-inference.encode" })));
|
|
384
|
+
return yield* persistence.deliveryGraph.write(workspaceId, encoded);
|
|
385
|
+
});
|
|
386
|
+
var relationshipIdentity = (workspaceId, identityKey) => `${workspaceId}\u0000relationship-inference\u0000relationship\u0000${identityKey}`;
|
|
387
|
+
var missingNodeIdentity = (workspaceId, endpointKind, missingKey) => `${workspaceId}\u0000relationship-inference\u0000missing-node\u0000${endpointKind}\u0000${missingKey}`;
|
|
388
|
+
var evidenceIdentity = (workspaceId, identityKey, observationKey, kind) => `${workspaceId}\u0000relationship-inference\u0000evidence-${kind}\u0000${identityKey}\u0000${observationKey}`;
|
|
389
|
+
var entityNodeIdentity = (workspaceId, entity) => {
|
|
390
|
+
const source = entity.sourceRevision;
|
|
391
|
+
return `${workspaceId}\u0000${source.pluginConnectionId}\u0000${source.providerId}\u0000entity-node\u0000${source.vendorImmutableId}`;
|
|
392
|
+
};
|
|
393
|
+
var releaseNodeIdentity = (workspaceId, pluginConnectionId, providerId, vendorImmutableId) => `${workspaceId}\u0000${pluginConnectionId}\u0000${providerId}\u0000release-node\u0000${vendorImmutableId}`;
|
|
394
|
+
var relationshipIdFor = (identity, workspaceId, identityKey) => identity(relationshipIdentity(workspaceId, identityKey)).pipe(Effect.map(RelationshipId.make));
|
|
395
|
+
var endpointNode = (identity, scope, endpoint) => endpoint._tag === "resolved" ? Effect.succeed({
|
|
396
|
+
node: null,
|
|
397
|
+
nodeId: endpoint.nodeId
|
|
398
|
+
}) : identity(missingNodeIdentity(scope.workspaceId, endpoint.kind, endpoint.identityKey)).pipe(Effect.map((value) => {
|
|
399
|
+
const nodeId = GraphNodeId.make(value);
|
|
400
|
+
return {
|
|
401
|
+
nodeId,
|
|
402
|
+
node: {
|
|
403
|
+
workspaceId: scope.workspaceId,
|
|
404
|
+
nodeId,
|
|
405
|
+
endpointKind: endpoint.kind,
|
|
406
|
+
resolution: {
|
|
407
|
+
_tag: "missing",
|
|
408
|
+
expectedKind: "entity",
|
|
409
|
+
expectedEntityKind: endpoint.kind,
|
|
410
|
+
missingKey: endpoint.missingKey
|
|
411
|
+
},
|
|
412
|
+
createdAt: scope.committedAt
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}));
|
|
416
|
+
var evidenceFor = Effect.fn("RelationshipInferenceMaterialization.evidenceFor")(function* (persistence, identity, scope, candidate, sourceNodeId, targetNodeId, entity) {
|
|
417
|
+
const evidenceId = EvidenceId.make(yield* identity(evidenceIdentity(scope.workspaceId, candidate.identityKey, candidate.observationKey, "item")));
|
|
418
|
+
const evidenceClaimId = EvidenceClaimId.make(yield* identity(evidenceIdentity(scope.workspaceId, candidate.identityKey, candidate.observationKey, "claim")));
|
|
419
|
+
const source = entity.sourceRevision;
|
|
420
|
+
const sourceStreamKey = yield* Schema.decodeUnknownEffect(PluginStreamKey)(firstPartySyncStreamKey(source.providerId)).pipe(Effect.mapError(() => new PersistenceOperationError({ operation: "relationship-inference.source-stream" })));
|
|
421
|
+
const pluginHealth = yield* persistence.pluginRuntime.getLastSuccessfulHealth(scope.workspaceId, source.pluginConnectionId, sourceStreamKey);
|
|
422
|
+
if (pluginHealth === null) return yield* new PersistenceOperationError({ operation: "relationship-inference.source-health" });
|
|
423
|
+
const sourceAgeSeconds = Math.max(0, (DateTime.toEpochMillis(scope.committedAt) - DateTime.toEpochMillis(source.lastObservedAt)) / 1e3);
|
|
424
|
+
return {
|
|
425
|
+
item: {
|
|
426
|
+
workspaceId: scope.workspaceId,
|
|
427
|
+
evidenceId,
|
|
428
|
+
schemaVersion: 1,
|
|
429
|
+
attribution: {
|
|
430
|
+
_tag: "system",
|
|
431
|
+
component: COMPONENT
|
|
432
|
+
},
|
|
433
|
+
verifier: {
|
|
434
|
+
_tag: "system",
|
|
435
|
+
component: COMPONENT
|
|
436
|
+
},
|
|
437
|
+
observedAt: source.lastObservedAt,
|
|
438
|
+
recordedAt: scope.committedAt,
|
|
439
|
+
validUntil: null,
|
|
440
|
+
freshness: {
|
|
441
|
+
_tag: "current",
|
|
442
|
+
evaluatedAt: scope.committedAt,
|
|
443
|
+
pluginHealth,
|
|
444
|
+
provenance: {
|
|
445
|
+
_tag: "provider",
|
|
446
|
+
sourceRevision: source
|
|
447
|
+
},
|
|
448
|
+
sourceObservedAt: source.lastObservedAt,
|
|
449
|
+
staleAfterSeconds: Math.max(1, Math.ceil(sourceAgeSeconds) + 86400),
|
|
450
|
+
synchronizedAt: source.synchronizedAt
|
|
451
|
+
},
|
|
452
|
+
retention: {
|
|
453
|
+
classification: "evidence",
|
|
454
|
+
retainUntil: null,
|
|
455
|
+
legalHold: false
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
claim: {
|
|
459
|
+
workspaceId: scope.workspaceId,
|
|
460
|
+
evidenceClaimId,
|
|
461
|
+
evidenceId,
|
|
462
|
+
subjectNodeId: sourceNodeId,
|
|
463
|
+
predicate: "relationship-observed",
|
|
464
|
+
value: {
|
|
465
|
+
_tag: "reference",
|
|
466
|
+
targetNodeId
|
|
467
|
+
},
|
|
468
|
+
recordedAt: scope.committedAt,
|
|
469
|
+
supersedesEvidenceClaimId: null
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
var unchanged = (previous, candidate, sourceNodeId, targetNodeId, claimId) => previous !== null && previous.kind === candidate.kind && previous.sourceNodeId === sourceNodeId && previous.targetNodeId === targetNodeId && previous.scope?._tag === "release" && previous.scope.releaseId === candidate.releaseId && previous.lifecycle._tag === candidate.lifecycle && (claimId === null || previous.evidenceClaimIds.includes(claimId));
|
|
474
|
+
var protectedByDecision = (previous) => previous?.lifecycle._tag === "governed" || previous?.lifecycle._tag === "verified" || previous?.lifecycle._tag === "rejected";
|
|
475
|
+
var materializeCandidate = Effect.fn("RelationshipInferenceMaterialization.materializeCandidate")(function* (persistence, identity, scope, candidate, entityById) {
|
|
476
|
+
const relationshipId = yield* relationshipIdFor(identity, scope.workspaceId, candidate.identityKey);
|
|
477
|
+
const previous = yield* readRelationship(persistence, scope.workspaceId, relationshipId);
|
|
478
|
+
if (protectedByDecision(previous)) return {
|
|
479
|
+
evidenceClaimCount: 0,
|
|
480
|
+
evidenceItemCount: 0,
|
|
481
|
+
nodeCount: 0,
|
|
482
|
+
relationshipCount: 0,
|
|
483
|
+
skippedDueToBounds: false
|
|
484
|
+
};
|
|
485
|
+
const source = yield* endpointNode(identity, scope, candidate.source);
|
|
486
|
+
const target = yield* endpointNode(identity, scope, candidate.target);
|
|
487
|
+
const evidenceEntity = candidate.evidenceEntityId === null ? null : entityById.get(candidate.evidenceEntityId) ?? null;
|
|
488
|
+
const evidence = evidenceEntity === null ? null : yield* evidenceFor(persistence, identity, scope, candidate, source.nodeId, target.nodeId, evidenceEntity);
|
|
489
|
+
if (unchanged(previous, candidate, source.nodeId, target.nodeId, evidence?.claim.evidenceClaimId ?? null)) return {
|
|
490
|
+
evidenceClaimCount: 0,
|
|
491
|
+
evidenceItemCount: 0,
|
|
492
|
+
nodeCount: 0,
|
|
493
|
+
relationshipCount: 0,
|
|
494
|
+
skippedDueToBounds: false
|
|
495
|
+
};
|
|
496
|
+
const nodes = [];
|
|
497
|
+
if (source.node !== null && !(yield* nodeExists(persistence, scope.workspaceId, source.nodeId))) nodes.push(source.node);
|
|
498
|
+
if (target.node !== null && !(yield* nodeExists(persistence, scope.workspaceId, target.nodeId))) nodes.push(target.node);
|
|
499
|
+
const confidence = candidate.confidence === null ? {
|
|
500
|
+
_tag: "unknown",
|
|
501
|
+
rationale: "No matching provider evidence is currently synchronized."
|
|
502
|
+
} : {
|
|
503
|
+
_tag: "inferred",
|
|
504
|
+
...candidate.confidence
|
|
505
|
+
};
|
|
506
|
+
const relationship = {
|
|
507
|
+
workspaceId: scope.workspaceId,
|
|
508
|
+
relationshipId,
|
|
509
|
+
relationshipSchemaVersion: 1,
|
|
510
|
+
revision: LedgerRevision.make((previous?.revision ?? 0) + 1),
|
|
511
|
+
supersedesRevision: previous?.revision ?? null,
|
|
512
|
+
kind: candidate.kind,
|
|
513
|
+
sourceNodeId: source.nodeId,
|
|
514
|
+
sourceNodeKind: candidate.source.kind,
|
|
515
|
+
targetNodeId: target.nodeId,
|
|
516
|
+
targetNodeKind: candidate.target.kind,
|
|
517
|
+
scope: {
|
|
518
|
+
_tag: "release",
|
|
519
|
+
releaseId: candidate.releaseId
|
|
520
|
+
},
|
|
521
|
+
lifecycle: candidate.lifecycle === "missing" ? {
|
|
522
|
+
_tag: "missing",
|
|
523
|
+
effectiveAt: scope.committedAt,
|
|
524
|
+
reason: "No synchronized provider evidence currently resolves this required delivery link."
|
|
525
|
+
} : {
|
|
526
|
+
_tag: "inferred",
|
|
527
|
+
effectiveAt: scope.committedAt
|
|
528
|
+
},
|
|
529
|
+
confidence,
|
|
530
|
+
provenance: {
|
|
531
|
+
_tag: "rule",
|
|
532
|
+
ruleId: candidate.ruleId,
|
|
533
|
+
ruleVersion: 1,
|
|
534
|
+
rationale: candidate.confidence?.rationale ?? "Required delivery link has no synchronized match."
|
|
535
|
+
},
|
|
536
|
+
recordedBy: {
|
|
537
|
+
_tag: "system",
|
|
538
|
+
component: COMPONENT
|
|
539
|
+
},
|
|
540
|
+
evidenceClaimIds: evidence === null ? [] : [evidence.claim.evidenceClaimId],
|
|
541
|
+
recordedAt: scope.committedAt
|
|
542
|
+
};
|
|
543
|
+
return {
|
|
544
|
+
...yield* writeGraph$1(persistence, scope.workspaceId, {
|
|
545
|
+
entityProjections: [],
|
|
546
|
+
nodes,
|
|
547
|
+
evidenceItems: evidence === null ? [] : [evidence.item],
|
|
548
|
+
evidenceClaims: evidence === null ? [] : [evidence.claim],
|
|
549
|
+
relationships: [relationship]
|
|
550
|
+
}),
|
|
551
|
+
skippedDueToBounds: false
|
|
552
|
+
};
|
|
553
|
+
});
|
|
554
|
+
var supersedeObsoleteGap = Effect.fn("RelationshipInferenceMaterialization.supersedeObsoleteGap")(function* (persistence, identity, scope, identityKey) {
|
|
555
|
+
const relationshipId = yield* relationshipIdFor(identity, scope.workspaceId, identityKey);
|
|
556
|
+
const previous = yield* readRelationship(persistence, scope.workspaceId, relationshipId);
|
|
557
|
+
if (previous?.lifecycle._tag !== "missing") return 0;
|
|
558
|
+
const relationship = {
|
|
559
|
+
...previous,
|
|
560
|
+
revision: LedgerRevision.make(previous.revision + 1),
|
|
561
|
+
supersedesRevision: previous.revision,
|
|
562
|
+
lifecycle: {
|
|
563
|
+
_tag: "superseded",
|
|
564
|
+
effectiveAt: scope.committedAt,
|
|
565
|
+
reason: "New synchronized evidence resolved the previously missing link."
|
|
566
|
+
},
|
|
567
|
+
recordedAt: scope.committedAt
|
|
568
|
+
};
|
|
569
|
+
return (yield* writeGraph$1(persistence, scope.workspaceId, {
|
|
570
|
+
entityProjections: [],
|
|
571
|
+
nodes: [],
|
|
572
|
+
evidenceItems: [],
|
|
573
|
+
evidenceClaims: [],
|
|
574
|
+
relationships: [relationship]
|
|
575
|
+
})).relationshipCount;
|
|
576
|
+
});
|
|
577
|
+
var supersedeObsoleteRelationship = Effect.fn("RelationshipInferenceMaterialization.supersedeObsoleteRelationship")(function* (persistence, scope, relationshipId, reason) {
|
|
578
|
+
const previous = yield* readRelationship(persistence, scope.workspaceId, relationshipId);
|
|
579
|
+
if (previous?.lifecycle._tag !== "inferred" && previous?.lifecycle._tag !== "missing") return 0;
|
|
580
|
+
const relationship = {
|
|
581
|
+
...previous,
|
|
582
|
+
revision: LedgerRevision.make(previous.revision + 1),
|
|
583
|
+
supersedesRevision: previous.revision,
|
|
584
|
+
lifecycle: {
|
|
585
|
+
_tag: "superseded",
|
|
586
|
+
effectiveAt: scope.committedAt,
|
|
587
|
+
reason: reason ?? (previous.lifecycle._tag === "missing" ? "The entity is no longer in the release scope that required this missing link." : "Current synchronized metadata no longer supports this inferred link.")
|
|
588
|
+
},
|
|
589
|
+
recordedAt: scope.committedAt
|
|
590
|
+
};
|
|
591
|
+
return (yield* writeGraph$1(persistence, scope.workspaceId, {
|
|
592
|
+
entityProjections: [],
|
|
593
|
+
nodes: [],
|
|
594
|
+
evidenceItems: [],
|
|
595
|
+
evidenceClaims: [],
|
|
596
|
+
relationships: [relationship]
|
|
597
|
+
})).relationshipCount;
|
|
598
|
+
});
|
|
599
|
+
var emptyReceipt = (skippedDueToBounds) => ({
|
|
600
|
+
evidenceClaimCount: 0,
|
|
601
|
+
evidenceItemCount: 0,
|
|
602
|
+
nodeCount: 0,
|
|
603
|
+
relationshipCount: 0,
|
|
604
|
+
skippedDueToBounds
|
|
605
|
+
});
|
|
606
|
+
var retireInferenceForReleases = Effect.fn("RelationshipInferenceMaterialization.retireInferenceForReleases")(function* (persistence, scope, releaseIds, reason) {
|
|
607
|
+
const reads = yield* Effect.forEach(releaseIds ?? [null], (releaseId) => persistence.deliveryGraph.read(scope.workspaceId, {
|
|
608
|
+
_tag: "componentRelationships",
|
|
609
|
+
releaseId,
|
|
610
|
+
component: COMPONENT,
|
|
611
|
+
limit: MAXIMUM_INFERENCE_RELATIONSHIPS
|
|
612
|
+
}));
|
|
613
|
+
if (reads.some((read) => read._tag !== "componentRelationships" || read.value.truncated)) return emptyReceipt(true);
|
|
614
|
+
const relationshipIds = new Set(reads.flatMap((read) => read._tag === "componentRelationships" ? read.value.relationships.map(({ relationshipId }) => relationshipId) : []));
|
|
615
|
+
let relationshipCount = 0;
|
|
616
|
+
for (const relationshipId of relationshipIds) relationshipCount += yield* supersedeObsoleteRelationship(persistence, scope, relationshipId, reason);
|
|
617
|
+
return {
|
|
618
|
+
...emptyReceipt(true),
|
|
619
|
+
relationshipCount
|
|
620
|
+
};
|
|
621
|
+
});
|
|
622
|
+
var retireInferenceAtEntityBound = Effect.fn("RelationshipInferenceMaterialization.retireInferenceAtEntityBound")(function* (persistence, scope) {
|
|
623
|
+
return yield* retireInferenceForReleases(persistence, scope, null, "Inference inputs exceeded the bounded workspace snapshot, so this relationship can no longer be proven.");
|
|
624
|
+
});
|
|
625
|
+
/** Persist current rule candidates after a normalized page has committed. */
|
|
626
|
+
var materializeRelationshipInference = Effect.fn("RelationshipInferenceMaterialization.reconcile")(function* (persistence, identity, scope) {
|
|
627
|
+
const projectionResult = yield* persistence.deliveryGraph.read(scope.workspaceId, {
|
|
628
|
+
_tag: "workspaceEntityProjections",
|
|
629
|
+
owner: null,
|
|
630
|
+
query: null,
|
|
631
|
+
service: null,
|
|
632
|
+
status: null,
|
|
633
|
+
type: null,
|
|
634
|
+
limit: MAXIMUM_INFERENCE_ENTITIES
|
|
635
|
+
});
|
|
636
|
+
if (projectionResult._tag !== "workspaceEntityProjections") return emptyReceipt(true);
|
|
637
|
+
if (projectionResult.value.truncated) return yield* retireInferenceAtEntityBound(persistence, scope);
|
|
638
|
+
const records = yield* Effect.forEach(projectionResult.value.items, ({ projection }) => persistence.entities.get(scope.workspaceId, projection.entityId), { concurrency: 10 });
|
|
639
|
+
const entityById = new Map(records.map((record) => [record.entityId, record]));
|
|
640
|
+
const entities = [];
|
|
641
|
+
for (const item of projectionResult.value.items) {
|
|
642
|
+
const entity = entityById.get(item.projection.entityId);
|
|
643
|
+
if (entity === void 0) continue;
|
|
644
|
+
entities.push({
|
|
645
|
+
projection: item.projection,
|
|
646
|
+
releaseIds: item.releaseIds,
|
|
647
|
+
nodeId: GraphNodeId.make(yield* identity(entityNodeIdentity(scope.workspaceId, entity)))
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
const releases = yield* persistence.releases.list(scope.workspaceId, 51);
|
|
651
|
+
if (releases.length > MAXIMUM_INFERENCE_RELEASES) return yield* retireInferenceAtEntityBound(persistence, scope);
|
|
652
|
+
const inferenceReleases = [];
|
|
653
|
+
for (const { release } of releases) {
|
|
654
|
+
const candidates = yield* Effect.forEach(release.sourceRevisions, (source) => Effect.gen(function* () {
|
|
655
|
+
const nodeId = GraphNodeId.make(yield* identity(releaseNodeIdentity(scope.workspaceId, source.pluginConnectionId, source.providerId, source.vendorImmutableId)));
|
|
656
|
+
return {
|
|
657
|
+
exists: yield* nodeExists(persistence, scope.workspaceId, nodeId),
|
|
658
|
+
nodeId
|
|
659
|
+
};
|
|
660
|
+
}));
|
|
661
|
+
const selected = candidates.find(({ exists }) => exists) ?? candidates[0];
|
|
662
|
+
if (selected === void 0) continue;
|
|
663
|
+
inferenceReleases.push({
|
|
664
|
+
inferenceRelease: {
|
|
665
|
+
nodeId: selected.nodeId,
|
|
666
|
+
releaseId: release.id,
|
|
667
|
+
version: release.version
|
|
668
|
+
},
|
|
669
|
+
node: selected.exists ? null : {
|
|
670
|
+
workspaceId: scope.workspaceId,
|
|
671
|
+
nodeId: selected.nodeId,
|
|
672
|
+
endpointKind: "release",
|
|
673
|
+
resolution: {
|
|
674
|
+
_tag: "resolved",
|
|
675
|
+
target: {
|
|
676
|
+
_tag: "release",
|
|
677
|
+
releaseId: release.id
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
createdAt: scope.committedAt
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
const releaseIds = releases.map(({ release }) => release.id);
|
|
685
|
+
const slices = yield* Effect.forEach(releaseIds, (releaseId) => persistence.deliveryGraph.read(scope.workspaceId, {
|
|
686
|
+
_tag: "releaseSlice",
|
|
687
|
+
releaseId,
|
|
688
|
+
environmentId: null,
|
|
689
|
+
limit: MAXIMUM_INFERENCE_ENTITIES
|
|
690
|
+
}));
|
|
691
|
+
const truncatedReleaseIds = slices.flatMap((slice, index) => {
|
|
692
|
+
const releaseId = releaseIds[index];
|
|
693
|
+
return releaseId !== void 0 && (slice._tag !== "releaseSlice" || slice.value.truncated) ? [releaseId] : [];
|
|
694
|
+
});
|
|
695
|
+
if (truncatedReleaseIds.length > 0) return yield* retireInferenceForReleases(persistence, scope, truncatedReleaseIds, "The bounded release relationship snapshot was incomplete, so this inference can no longer be proven.");
|
|
696
|
+
const relationships = slices.flatMap((slice) => slice._tag === "releaseSlice" ? slice.value.relationships : []);
|
|
697
|
+
const inferenceInput = {
|
|
698
|
+
entities,
|
|
699
|
+
releases: inferenceReleases.map(({ inferenceRelease }) => inferenceRelease),
|
|
700
|
+
relationships
|
|
701
|
+
};
|
|
702
|
+
const initialInference = deriveRelationshipInference(inferenceInput);
|
|
703
|
+
const rejectedCandidateIdentityKeys = /* @__PURE__ */ new Set();
|
|
704
|
+
for (const candidate of initialInference.candidates) {
|
|
705
|
+
if (candidate.lifecycle !== "inferred") continue;
|
|
706
|
+
const relationshipId = yield* relationshipIdFor(identity, scope.workspaceId, candidate.identityKey);
|
|
707
|
+
if ((yield* readRelationship(persistence, scope.workspaceId, relationshipId))?.lifecycle._tag === "rejected") rejectedCandidateIdentityKeys.add(candidate.identityKey);
|
|
708
|
+
}
|
|
709
|
+
const inference = rejectedCandidateIdentityKeys.size === 0 ? initialInference : deriveRelationshipInference({
|
|
710
|
+
...inferenceInput,
|
|
711
|
+
rejectedCandidateIdentityKeys
|
|
712
|
+
});
|
|
713
|
+
if (inference.truncated) return yield* retireInferenceAtEntityBound(persistence, scope);
|
|
714
|
+
let receipt = emptyReceipt(false);
|
|
715
|
+
const missingReleaseNodes = inferenceReleases.flatMap(({ node }) => node === null ? [] : [node]);
|
|
716
|
+
if (missingReleaseNodes.length > 0) {
|
|
717
|
+
const current = yield* writeGraph$1(persistence, scope.workspaceId, {
|
|
718
|
+
entityProjections: [],
|
|
719
|
+
nodes: missingReleaseNodes,
|
|
720
|
+
evidenceItems: [],
|
|
721
|
+
evidenceClaims: [],
|
|
722
|
+
relationships: []
|
|
723
|
+
});
|
|
724
|
+
receipt = {
|
|
725
|
+
...receipt,
|
|
726
|
+
nodeCount: current.nodeCount
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
for (const candidate of inference.candidates) {
|
|
730
|
+
const current = yield* materializeCandidate(persistence, identity, scope, candidate, entityById);
|
|
731
|
+
receipt = {
|
|
732
|
+
evidenceClaimCount: receipt.evidenceClaimCount + current.evidenceClaimCount,
|
|
733
|
+
evidenceItemCount: receipt.evidenceItemCount + current.evidenceItemCount,
|
|
734
|
+
nodeCount: receipt.nodeCount + current.nodeCount,
|
|
735
|
+
relationshipCount: receipt.relationshipCount + current.relationshipCount,
|
|
736
|
+
skippedDueToBounds: false
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
for (const identityKey of inference.obsoleteGapIdentityKeys) receipt = {
|
|
740
|
+
...receipt,
|
|
741
|
+
relationshipCount: receipt.relationshipCount + (yield* supersedeObsoleteGap(persistence, identity, scope, identityKey))
|
|
742
|
+
};
|
|
743
|
+
for (const relationshipId of inference.obsoleteRelationshipIds) receipt = {
|
|
744
|
+
...receipt,
|
|
745
|
+
relationshipCount: receipt.relationshipCount + (yield* supersedeObsoleteRelationship(persistence, scope, relationshipId))
|
|
746
|
+
};
|
|
747
|
+
return receipt;
|
|
748
|
+
});
|
|
749
|
+
//#endregion
|
|
750
|
+
//#region src/server/application/normalizedPluginPageMaterialization.ts
|
|
751
|
+
var OptionalText = Schema.optionalKey(Schema.NullOr(Schema.String));
|
|
752
|
+
var NamedText = Schema.Union([Schema.String, Schema.Struct({ name: Schema.optionalKey(Schema.NullOr(Schema.String)) })]);
|
|
753
|
+
var EntityAttributes = Schema.Struct({
|
|
754
|
+
key: OptionalText,
|
|
755
|
+
status: Schema.optionalKey(Schema.NullOr(NamedText)),
|
|
756
|
+
priority: Schema.optionalKey(Schema.NullOr(NamedText)),
|
|
757
|
+
estimatePoints: Schema.optionalKey(Schema.NullOr(Schema.Number)),
|
|
758
|
+
repository: OptionalText,
|
|
759
|
+
sourceBranch: OptionalText,
|
|
760
|
+
targetBranch: OptionalText,
|
|
761
|
+
headRevision: OptionalText,
|
|
762
|
+
reviewState: OptionalText,
|
|
763
|
+
spaceKey: OptionalText,
|
|
764
|
+
spaceId: OptionalText,
|
|
765
|
+
currentVersion: Schema.optionalKey(Schema.NullOr(Schema.Number)),
|
|
766
|
+
linkedIssueKeys: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
767
|
+
linkedReleaseVersions: Schema.optionalKey(Schema.Array(Schema.String)),
|
|
768
|
+
pipelineName: OptionalText,
|
|
769
|
+
executionId: OptionalText,
|
|
770
|
+
triggerRevision: OptionalText,
|
|
771
|
+
sourceRevisions: Schema.optionalKey(Schema.Array(Schema.Struct({ revisionId: OptionalText }))),
|
|
772
|
+
environmentId: OptionalText,
|
|
773
|
+
revision: OptionalText,
|
|
774
|
+
durationMinutes: Schema.optionalKey(Schema.NullOr(Schema.Number)),
|
|
775
|
+
billable: Schema.optionalKey(Schema.Boolean),
|
|
776
|
+
approvalState: OptionalText,
|
|
777
|
+
interval: Schema.optionalKey(Schema.Struct({
|
|
778
|
+
duration: OptionalText,
|
|
779
|
+
state: OptionalText
|
|
780
|
+
}))
|
|
781
|
+
});
|
|
782
|
+
var LegacyIssueAttributes = Schema.Struct({
|
|
783
|
+
key: OptionalText,
|
|
784
|
+
status: Schema.optionalKey(Schema.NullOr(NamedText)),
|
|
785
|
+
priority: Schema.optionalKey(Schema.NullOr(NamedText)),
|
|
786
|
+
estimatePoints: Schema.optionalKey(Schema.NullOr(Schema.Number))
|
|
787
|
+
});
|
|
788
|
+
var LegacyIssueAttributeKeys = /* @__PURE__ */ new Set([
|
|
789
|
+
"key",
|
|
790
|
+
"status",
|
|
791
|
+
"priority",
|
|
792
|
+
"estimatePoints",
|
|
793
|
+
"schemaVersion",
|
|
794
|
+
"summary"
|
|
795
|
+
]);
|
|
796
|
+
var ReleaseAttributes = Schema.Struct({
|
|
797
|
+
serviceName: Schema.String.check(Schema.isTrimmed(), Schema.isNonEmpty(), Schema.isMaxLength(200)),
|
|
798
|
+
version: Schema.String.check(Schema.isTrimmed(), Schema.isNonEmpty(), Schema.isMaxLength(100)),
|
|
799
|
+
lifecycle: Schema.Literals([
|
|
800
|
+
"assembling",
|
|
801
|
+
"candidate",
|
|
802
|
+
"deploying",
|
|
803
|
+
"released",
|
|
804
|
+
"cancelled"
|
|
805
|
+
])
|
|
806
|
+
});
|
|
807
|
+
var JiraIssueRelationshipSnapshot = Schema.Struct({
|
|
808
|
+
fixVersions: Schema.Array(Schema.Struct({ sourceId: Schema.NullOr(Schema.String) })),
|
|
809
|
+
truncatedFields: Schema.Array(Schema.String)
|
|
810
|
+
});
|
|
811
|
+
var EvidenceData = Schema.Struct({
|
|
812
|
+
predicate: Schema.optionalKey(EvidencePredicate),
|
|
813
|
+
value: Schema.optionalKey(EvidenceValue)
|
|
814
|
+
});
|
|
815
|
+
/** Redacted failure raised before a normalized page can become a canonical projection. */
|
|
816
|
+
var NormalizedPluginPageMaterializationError = class extends Schema.TaggedErrorClass()("NormalizedPluginPageMaterializationError", {
|
|
817
|
+
diagnosticCode: Schema.String.check(Schema.isTrimmed(), Schema.isNonEmpty(), Schema.isMaxLength(100)),
|
|
818
|
+
eventId: Schema.NullOr(Schema.String.check(Schema.isTrimmed(), Schema.isNonEmpty(), Schema.isMaxLength(512)))
|
|
819
|
+
}) {};
|
|
820
|
+
var malformed = (diagnosticCode, eventId = null) => new NormalizedPluginPageMaterializationError({
|
|
821
|
+
diagnosticCode,
|
|
822
|
+
eventId
|
|
823
|
+
});
|
|
824
|
+
var decodedAttributes = Effect.fn("NormalizedPluginPageMaterialization.decodeAttributes")(function* (event) {
|
|
825
|
+
return yield* Schema.decodeUnknownEffect(EntityAttributes)(event.attributes).pipe(Effect.mapError(() => malformed("normalized-entity-attributes-invalid", event.eventId)));
|
|
826
|
+
});
|
|
827
|
+
var bounded = (value, fallback, maximum) => {
|
|
828
|
+
const normalized = value?.trim();
|
|
829
|
+
return (normalized === void 0 || normalized.length === 0 ? fallback : normalized).slice(0, maximum);
|
|
830
|
+
};
|
|
831
|
+
var namedText = (value) => typeof value === "string" ? value : value?.name ?? null;
|
|
832
|
+
var decodedIssueAttributes = Effect.fn("NormalizedPluginPageMaterialization.decodeIssueAttributes")(function* (event) {
|
|
833
|
+
const normalized = Schema.decodeUnknownResult(NormalizedIssueAttributes)(event.attributes);
|
|
834
|
+
if (Result.isSuccess(normalized)) return normalized.success;
|
|
835
|
+
if (Object.keys(event.attributes).some((key) => !LegacyIssueAttributeKeys.has(key))) return yield* malformed("normalized-issue-attributes-invalid", event.eventId);
|
|
836
|
+
const legacy = yield* Schema.decodeUnknownEffect(LegacyIssueAttributes)(event.attributes).pipe(Effect.mapError(() => malformed("normalized-issue-attributes-invalid", event.eventId)));
|
|
837
|
+
const key = bounded(legacy.key, event.vendorImmutableId, 100);
|
|
838
|
+
return yield* Schema.decodeUnknownEffect(NormalizedIssueAttributes)({
|
|
839
|
+
key,
|
|
840
|
+
status: bounded(namedText(legacy.status), "unknown", 100),
|
|
841
|
+
priority: legacy.priority === null || legacy.priority === void 0 ? null : bounded(namedText(legacy.priority), "unknown", 100),
|
|
842
|
+
estimatePoints: legacy.estimatePoints ?? null
|
|
843
|
+
}).pipe(Effect.mapError(() => malformed("normalized-issue-attributes-invalid", event.eventId)));
|
|
844
|
+
});
|
|
845
|
+
var canonicalKind = (entityType) => {
|
|
846
|
+
switch (entityType) {
|
|
847
|
+
case "issue":
|
|
848
|
+
case "jira.issue": return "issue";
|
|
849
|
+
case "pull-request": return "pull-request";
|
|
850
|
+
case "page":
|
|
851
|
+
case "confluence-page": return "page";
|
|
852
|
+
case "pipeline-execution":
|
|
853
|
+
case "aws.codepipeline.execution": return "pipeline-execution";
|
|
854
|
+
case "deployment": return "deployment";
|
|
855
|
+
case "time-entry":
|
|
856
|
+
case "clockify.time-entry": return "time-entry";
|
|
857
|
+
default: return null;
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
var reviewState = (value) => {
|
|
861
|
+
switch (value?.toLowerCase()) {
|
|
862
|
+
case "requested":
|
|
863
|
+
case "open": return "requested";
|
|
864
|
+
case "changes-requested":
|
|
865
|
+
case "changes requested": return "changes-requested";
|
|
866
|
+
case "approved": return "approved";
|
|
867
|
+
case "merged":
|
|
868
|
+
case "closed": return "merged";
|
|
869
|
+
default: return "not-requested";
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
var pipelineStatus = (value) => {
|
|
873
|
+
switch (value?.toLowerCase()) {
|
|
874
|
+
case "inprogress":
|
|
875
|
+
case "in-progress":
|
|
876
|
+
case "running": return "running";
|
|
877
|
+
case "succeeded":
|
|
878
|
+
case "success": return "succeeded";
|
|
879
|
+
case "failed":
|
|
880
|
+
case "failure": return "failed";
|
|
881
|
+
case "stopped":
|
|
882
|
+
case "stopping":
|
|
883
|
+
case "superseded":
|
|
884
|
+
case "abandoned": return "stopped";
|
|
885
|
+
default: return "queued";
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
var isoDurationMinutes = (value) => {
|
|
889
|
+
if (value === null || value === void 0) return 0;
|
|
890
|
+
const match = /^PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/u.exec(value);
|
|
891
|
+
if (match === null) return 0;
|
|
892
|
+
const hours = Number(match[1] ?? 0);
|
|
893
|
+
const minutes = Number(match[2] ?? 0);
|
|
894
|
+
const seconds = Number(match[3] ?? 0);
|
|
895
|
+
return Math.max(0, Math.round(hours * 60 + minutes + seconds / 60));
|
|
896
|
+
};
|
|
897
|
+
var entityPresentation = Effect.fn("NormalizedPluginPageMaterialization.entityPresentation")(function* (event, kind) {
|
|
898
|
+
const attributes = yield* decodedAttributes(event);
|
|
899
|
+
switch (kind) {
|
|
900
|
+
case "issue": {
|
|
901
|
+
const issueAttributes = yield* decodedIssueAttributes(event);
|
|
902
|
+
return {
|
|
903
|
+
displayKey: issueAttributes.key,
|
|
904
|
+
details: {
|
|
905
|
+
_tag: "issue",
|
|
906
|
+
...issueAttributes
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
case "pull-request": return {
|
|
911
|
+
displayKey: bounded(event.vendorImmutableId, event.vendorImmutableId, 200),
|
|
912
|
+
details: {
|
|
913
|
+
_tag: "pull-request",
|
|
914
|
+
repository: bounded(attributes.repository, "unknown", 200),
|
|
915
|
+
sourceBranch: bounded(attributes.sourceBranch, "unknown", 500),
|
|
916
|
+
targetBranch: bounded(attributes.targetBranch, "unknown", 500),
|
|
917
|
+
headRevision: bounded(attributes.headRevision, event.revision, 512),
|
|
918
|
+
reviewState: reviewState(attributes.reviewState ?? namedText(attributes.status))
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
case "page": return {
|
|
922
|
+
displayKey: bounded(event.vendorImmutableId, event.vendorImmutableId, 200),
|
|
923
|
+
details: {
|
|
924
|
+
_tag: "page",
|
|
925
|
+
spaceKey: bounded(attributes.spaceKey ?? attributes.spaceId, "unknown", 100),
|
|
926
|
+
revision: bounded(attributes.currentVersion === null || attributes.currentVersion === void 0 ? attributes.revision : String(attributes.currentVersion), event.revision, 512),
|
|
927
|
+
status: namedText(attributes.status)?.toLowerCase() === "superseded" ? "superseded" : "current",
|
|
928
|
+
linkedIssueKeys: attributes.linkedIssueKeys?.map((key) => key.trim()).filter((key, index, keys) => key.length > 0 && key.length <= 100 && keys.indexOf(key) === index).slice(0, 100),
|
|
929
|
+
linkedReleaseVersions: attributes.linkedReleaseVersions?.map((version) => version.trim()).filter((version, index, versions) => version.length > 0 && version.length <= 100 && versions.indexOf(version) === index).slice(0, 100)
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
case "pipeline-execution": {
|
|
933
|
+
const executionId = bounded(attributes.executionId, event.vendorImmutableId, 512);
|
|
934
|
+
const pipelineName = bounded(attributes.pipelineName, "unknown", 200);
|
|
935
|
+
const sourceRevision = attributes.sourceRevisions?.find(({ revisionId }) => revisionId !== null)?.revisionId;
|
|
936
|
+
return {
|
|
937
|
+
displayKey: bounded(`${pipelineName}/${executionId}`, executionId, 200),
|
|
938
|
+
details: {
|
|
939
|
+
_tag: "pipeline-execution",
|
|
940
|
+
pipelineName,
|
|
941
|
+
executionId,
|
|
942
|
+
status: pipelineStatus(namedText(attributes.status)),
|
|
943
|
+
triggerRevision: bounded(attributes.triggerRevision ?? sourceRevision, event.revision, 512)
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
case "deployment": {
|
|
948
|
+
const environmentId = yield* Schema.decodeUnknownEffect(EnvironmentId)(attributes.environmentId).pipe(Effect.mapError(() => malformed("normalized-deployment-environment-invalid", event.eventId)));
|
|
949
|
+
const status = pipelineStatus(namedText(attributes.status));
|
|
950
|
+
return {
|
|
951
|
+
displayKey: bounded(event.vendorImmutableId, event.vendorImmutableId, 200),
|
|
952
|
+
details: {
|
|
953
|
+
_tag: "deployment",
|
|
954
|
+
environmentId,
|
|
955
|
+
revision: bounded(attributes.revision, event.revision, 512),
|
|
956
|
+
status: status === "queued" ? "pending" : status === "running" ? "deploying" : status === "stopped" ? "rolled-back" : status
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
case "time-entry": return {
|
|
961
|
+
displayKey: bounded(event.vendorImmutableId, event.vendorImmutableId, 200),
|
|
962
|
+
details: {
|
|
963
|
+
_tag: "time-entry",
|
|
964
|
+
durationMinutes: Math.max(0, Math.round(attributes.durationMinutes ?? isoDurationMinutes(attributes.interval?.duration))),
|
|
965
|
+
billable: attributes.billable ?? false,
|
|
966
|
+
approvalState: attributes.approvalState === "approved" || attributes.approvalState === "rejected" ? attributes.approvalState : attributes.interval?.state === "running" ? "pending" : "not-required"
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
var stableUuid = Effect.fn("NormalizedPluginPageMaterialization.stableUuid")(function* (cryptoService, identity, eventId) {
|
|
972
|
+
const bytes = yield* Effect.fromResult(Encoding.decodeBase64(Encoding.encodeBase64(identity))).pipe(Effect.mapError(() => malformed("normalized-identity-encoding-failed", eventId)));
|
|
973
|
+
const digest = yield* cryptoService.digest("SHA-256", bytes).pipe(Effect.mapError(() => malformed("normalized-identity-digest-failed", eventId)));
|
|
974
|
+
const hex = Encoding.encodeHex(digest);
|
|
975
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-7${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
|
|
976
|
+
});
|
|
977
|
+
var sourceIdentity = (scope, vendorImmutableId) => ({
|
|
978
|
+
pluginConnectionId: scope.pluginConnectionId,
|
|
979
|
+
providerId: scope.providerId,
|
|
980
|
+
vendorImmutableId
|
|
981
|
+
});
|
|
982
|
+
var findEntity = Effect.fn("NormalizedPluginPageMaterialization.findEntity")(function* (persistence, scope, vendorImmutableId) {
|
|
983
|
+
const found = yield* persistence.entities.findBySourceIdentity(scope.workspaceId, sourceIdentity(scope, vendorImmutableId)).pipe(Effect.result);
|
|
984
|
+
if (Result.isSuccess(found)) return found.success;
|
|
985
|
+
if (found.failure._tag === "RecordNotFoundError") return null;
|
|
986
|
+
return yield* found.failure;
|
|
987
|
+
});
|
|
988
|
+
var readProjection = Effect.fn("NormalizedPluginPageMaterialization.readProjection")(function* (persistence, workspaceId, entityId) {
|
|
989
|
+
const found = yield* persistence.deliveryGraph.read(workspaceId, {
|
|
990
|
+
_tag: "entityProjection",
|
|
991
|
+
entityId,
|
|
992
|
+
revision: null
|
|
993
|
+
}).pipe(Effect.result);
|
|
994
|
+
if (Result.isSuccess(found)) return found.success._tag === "entityProjection" ? found.success.value : null;
|
|
995
|
+
if (found.failure._tag === "RecordNotFoundError") return null;
|
|
996
|
+
return yield* found.failure;
|
|
997
|
+
});
|
|
998
|
+
var materializationKey = (scope, kind, externalId) => `${scope.workspaceId}\u0000${scope.pluginConnectionId}\u0000${scope.providerId}\u0000${kind}\u0000${externalId}`;
|
|
999
|
+
var entityIdFor = Effect.fn("NormalizedPluginPageMaterialization.entityIdFor")(function* (cryptoService, scope, vendorImmutableId, eventId) {
|
|
1000
|
+
return EntityId.make(yield* stableUuid(cryptoService, materializationKey(scope, "entity", vendorImmutableId), eventId));
|
|
1001
|
+
});
|
|
1002
|
+
var nodeIdFor = Effect.fn("NormalizedPluginPageMaterialization.nodeIdFor")(function* (cryptoService, scope, vendorImmutableId, eventId) {
|
|
1003
|
+
return GraphNodeId.make(yield* stableUuid(cryptoService, materializationKey(scope, "entity-node", vendorImmutableId), eventId));
|
|
1004
|
+
});
|
|
1005
|
+
var releaseIdFor = Effect.fn("NormalizedPluginPageMaterialization.releaseIdFor")(function* (cryptoService, scope, vendorImmutableId, eventId) {
|
|
1006
|
+
return ReleaseId.make(yield* stableUuid(cryptoService, materializationKey(scope, "release", vendorImmutableId), eventId));
|
|
1007
|
+
});
|
|
1008
|
+
var releaseNodeIdFor = Effect.fn("NormalizedPluginPageMaterialization.releaseNodeIdFor")(function* (cryptoService, scope, vendorImmutableId, eventId) {
|
|
1009
|
+
return GraphNodeId.make(yield* stableUuid(cryptoService, materializationKey(scope, "release-node", vendorImmutableId), eventId));
|
|
1010
|
+
});
|
|
1011
|
+
var sourceRevision = (scope, event, firstObservedAt, sourceUrl) => ({
|
|
1012
|
+
...sourceIdentity(scope, event.vendorImmutableId),
|
|
1013
|
+
revision: event.revision,
|
|
1014
|
+
sourceUrl,
|
|
1015
|
+
firstObservedAt,
|
|
1016
|
+
lastObservedAt: event.observedAt,
|
|
1017
|
+
synchronizedAt: scope.committedAt,
|
|
1018
|
+
normalizationSchemaVersion: NormalizationSchemaVersion.make(1)
|
|
1019
|
+
});
|
|
1020
|
+
var laterTimestamp = (left, right) => DateTime.Order(left, right) >= 0 ? left : right;
|
|
1021
|
+
var sameSourceUrl = (left, right) => left?.href === right?.href;
|
|
1022
|
+
var writeGraph = Effect.fn("NormalizedPluginPageMaterialization.writeGraph")(function* (persistence, workspaceId, batch, eventId) {
|
|
1023
|
+
const encoded = yield* Schema.encodeEffect(DeliveryGraphWriteBatch)(batch).pipe(Effect.mapError(() => malformed("normalized-delivery-graph-batch-invalid", eventId)));
|
|
1024
|
+
return yield* persistence.deliveryGraph.write(workspaceId, encoded);
|
|
1025
|
+
});
|
|
1026
|
+
var materializeUpsertEntity = Effect.fn("NormalizedPluginPageMaterialization.upsertEntity")(function* (persistence, cryptoService, scope, event) {
|
|
1027
|
+
const kind = canonicalKind(event.entityType);
|
|
1028
|
+
if (kind === null) return {
|
|
1029
|
+
entityProjectionCount: 0,
|
|
1030
|
+
nodeCount: 0,
|
|
1031
|
+
skippedEntityCount: 1
|
|
1032
|
+
};
|
|
1033
|
+
const presentation = yield* entityPresentation(event, kind);
|
|
1034
|
+
const existing = yield* findEntity(persistence, scope, event.vendorImmutableId);
|
|
1035
|
+
const entityId = existing?.entityId ?? (yield* entityIdFor(cryptoService, scope, event.vendorImmutableId, event.eventId));
|
|
1036
|
+
const currentProjection = existing === null ? null : yield* readProjection(persistence, scope.workspaceId, entityId);
|
|
1037
|
+
if (existing !== null && existing.sourceRevision.revision === event.revision && currentProjection?.projection.entityState === "present") return {
|
|
1038
|
+
entityProjectionCount: 0,
|
|
1039
|
+
nodeCount: 0,
|
|
1040
|
+
skippedEntityCount: 0
|
|
1041
|
+
};
|
|
1042
|
+
const persisted = existing === null ? yield* persistence.entities.create(scope.workspaceId, {
|
|
1043
|
+
entityId,
|
|
1044
|
+
entityType: kind,
|
|
1045
|
+
sourceRevision: sourceRevision(scope, event, event.observedAt, event.sourceUrl),
|
|
1046
|
+
createdAt: scope.committedAt
|
|
1047
|
+
}) : existing.sourceRevision.revision === event.revision ? existing : yield* persistence.entities.updateSourceRevision(scope.workspaceId, entityId, {
|
|
1048
|
+
sourceRevision: sourceRevision(scope, event, existing.sourceRevision.firstObservedAt, event.sourceUrl),
|
|
1049
|
+
expectedRevision: existing.revision,
|
|
1050
|
+
updatedAt: scope.committedAt
|
|
1051
|
+
});
|
|
1052
|
+
const projectionRevision = LedgerRevision.make((currentProjection?.projection.projectionRevision ?? 0) + 1);
|
|
1053
|
+
const nodeId = yield* nodeIdFor(cryptoService, scope, event.vendorImmutableId, event.eventId);
|
|
1054
|
+
const batch = {
|
|
1055
|
+
entityProjections: [{
|
|
1056
|
+
projection: {
|
|
1057
|
+
workspaceId: scope.workspaceId,
|
|
1058
|
+
entityId,
|
|
1059
|
+
projectionRevision,
|
|
1060
|
+
sourceEntityRevision: LedgerRevision.make(persisted.revision),
|
|
1061
|
+
supersedesProjectionRevision: currentProjection?.projection.projectionRevision ?? null,
|
|
1062
|
+
projectionSchemaVersion: 1,
|
|
1063
|
+
entityState: "present",
|
|
1064
|
+
entityType: kind,
|
|
1065
|
+
displayKey: presentation.displayKey,
|
|
1066
|
+
title: event.title,
|
|
1067
|
+
details: presentation.details
|
|
1068
|
+
},
|
|
1069
|
+
recordedAt: scope.committedAt
|
|
1070
|
+
}],
|
|
1071
|
+
nodes: currentProjection === null ? [{
|
|
1072
|
+
workspaceId: scope.workspaceId,
|
|
1073
|
+
nodeId,
|
|
1074
|
+
endpointKind: kind,
|
|
1075
|
+
resolution: {
|
|
1076
|
+
_tag: "resolved",
|
|
1077
|
+
target: {
|
|
1078
|
+
_tag: "entity",
|
|
1079
|
+
entityId,
|
|
1080
|
+
entityKind: kind
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
createdAt: scope.committedAt
|
|
1084
|
+
}] : [],
|
|
1085
|
+
evidenceItems: [],
|
|
1086
|
+
evidenceClaims: [],
|
|
1087
|
+
relationships: []
|
|
1088
|
+
};
|
|
1089
|
+
return {
|
|
1090
|
+
...yield* writeGraph(persistence, scope.workspaceId, batch, event.eventId),
|
|
1091
|
+
skippedEntityCount: 0
|
|
1092
|
+
};
|
|
1093
|
+
});
|
|
1094
|
+
var materializeRelease = Effect.fn("NormalizedPluginPageMaterialization.upsertRelease")(function* (persistence, cryptoService, scope, event) {
|
|
1095
|
+
const attributes = yield* Schema.decodeUnknownEffect(ReleaseAttributes)(event.attributes).pipe(Effect.mapError(() => malformed("normalized-release-attributes-invalid", event.eventId)));
|
|
1096
|
+
const releaseId = yield* releaseIdFor(cryptoService, scope, event.vendorImmutableId, event.eventId);
|
|
1097
|
+
const existing = yield* persistence.releases.get(scope.workspaceId, releaseId).pipe(Effect.result);
|
|
1098
|
+
if (Result.isFailure(existing) && existing.failure._tag !== "RecordNotFoundError") return yield* existing.failure;
|
|
1099
|
+
const previous = Result.isSuccess(existing) ? existing.success : null;
|
|
1100
|
+
const previousSource = previous?.release.sourceRevisions.find(({ pluginConnectionId, providerId, vendorImmutableId }) => pluginConnectionId === scope.pluginConnectionId && providerId === scope.providerId && vendorImmutableId === event.vendorImmutableId);
|
|
1101
|
+
const observedAt = previousSource === void 0 ? event.observedAt : laterTimestamp(previousSource.lastObservedAt, event.observedAt);
|
|
1102
|
+
const refreshedSource = {
|
|
1103
|
+
...sourceRevision(scope, event, previousSource?.firstObservedAt ?? event.observedAt, event.sourceUrl),
|
|
1104
|
+
lastObservedAt: observedAt
|
|
1105
|
+
};
|
|
1106
|
+
const sourceAgeSeconds = Math.max(0, (DateTime.toEpochMillis(scope.committedAt) - DateTime.toEpochMillis(observedAt)) / 1e3);
|
|
1107
|
+
const release = yield* Schema.decodeUnknownEffect(Schema.toType(Release))({
|
|
1108
|
+
createdAt: previous?.release.createdAt ?? event.observedAt,
|
|
1109
|
+
freshness: {
|
|
1110
|
+
_tag: "current",
|
|
1111
|
+
evaluatedAt: scope.committedAt,
|
|
1112
|
+
pluginHealth: scope.successfulHealth,
|
|
1113
|
+
provenance: {
|
|
1114
|
+
_tag: "provider",
|
|
1115
|
+
sourceRevision: refreshedSource
|
|
1116
|
+
},
|
|
1117
|
+
sourceObservedAt: observedAt,
|
|
1118
|
+
staleAfterSeconds: Math.max(1, Math.ceil(sourceAgeSeconds) + 86400),
|
|
1119
|
+
synchronizedAt: scope.committedAt
|
|
1120
|
+
},
|
|
1121
|
+
id: releaseId,
|
|
1122
|
+
lifecycle: attributes.lifecycle,
|
|
1123
|
+
relay: deriveReleaseRelay(releaseId),
|
|
1124
|
+
roleAssignments: previous?.release.roleAssignments ?? [],
|
|
1125
|
+
serviceName: attributes.serviceName,
|
|
1126
|
+
sourceRevisions: [...previous?.release.sourceRevisions.filter(({ pluginConnectionId, providerId, vendorImmutableId }) => pluginConnectionId !== scope.pluginConnectionId || providerId !== scope.providerId || vendorImmutableId !== event.vendorImmutableId) ?? [], refreshedSource],
|
|
1127
|
+
targetEnvironmentIds: previous?.release.targetEnvironmentIds ?? [],
|
|
1128
|
+
updatedAt: scope.committedAt,
|
|
1129
|
+
version: attributes.version,
|
|
1130
|
+
workspaceId: scope.workspaceId
|
|
1131
|
+
}).pipe(Effect.mapError(() => malformed("normalized-release-invalid", event.eventId)));
|
|
1132
|
+
if (previous === null) yield* persistence.releases.create(scope.workspaceId, release);
|
|
1133
|
+
else if (previousSource === void 0 || previousSource.revision !== refreshedSource.revision || !sameSourceUrl(previousSource.sourceUrl, refreshedSource.sourceUrl) || !DateTime.Equivalence(previousSource.lastObservedAt, refreshedSource.lastObservedAt) || !DateTime.Equivalence(previousSource.synchronizedAt, refreshedSource.synchronizedAt) || previous.release.serviceName !== release.serviceName || previous.release.version !== release.version || previous.release.lifecycle !== release.lifecycle) yield* persistence.releases.append(scope.workspaceId, release, previous.revision);
|
|
1134
|
+
const nodeId = yield* releaseNodeIdFor(cryptoService, scope, event.vendorImmutableId, event.eventId);
|
|
1135
|
+
const existingNode = yield* persistence.deliveryGraph.read(scope.workspaceId, {
|
|
1136
|
+
_tag: "node",
|
|
1137
|
+
nodeId
|
|
1138
|
+
}).pipe(Effect.result);
|
|
1139
|
+
if (Result.isSuccess(existingNode)) return { nodeCount: 0 };
|
|
1140
|
+
if (existingNode.failure._tag !== "RecordNotFoundError") return yield* existingNode.failure;
|
|
1141
|
+
return { nodeCount: (yield* writeGraph(persistence, scope.workspaceId, {
|
|
1142
|
+
entityProjections: [],
|
|
1143
|
+
nodes: [{
|
|
1144
|
+
workspaceId: scope.workspaceId,
|
|
1145
|
+
nodeId,
|
|
1146
|
+
endpointKind: "release",
|
|
1147
|
+
resolution: {
|
|
1148
|
+
_tag: "resolved",
|
|
1149
|
+
target: {
|
|
1150
|
+
_tag: "release",
|
|
1151
|
+
releaseId
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
createdAt: scope.committedAt
|
|
1155
|
+
}],
|
|
1156
|
+
evidenceItems: [],
|
|
1157
|
+
evidenceClaims: [],
|
|
1158
|
+
relationships: []
|
|
1159
|
+
}, event.eventId)).nodeCount };
|
|
1160
|
+
});
|
|
1161
|
+
var materializeTombstoneEntity = Effect.fn("NormalizedPluginPageMaterialization.tombstoneEntity")(function* (persistence, scope, event) {
|
|
1162
|
+
const existing = yield* findEntity(persistence, scope, event.vendorImmutableId);
|
|
1163
|
+
if (existing === null) return { entityProjectionCount: 0 };
|
|
1164
|
+
const current = yield* readProjection(persistence, scope.workspaceId, existing.entityId);
|
|
1165
|
+
if (current === null) return yield* malformed("normalized-tombstone-projection-missing", event.eventId);
|
|
1166
|
+
if (existing.sourceRevision.revision === event.revision && current.projection.entityState === "deleted") return { entityProjectionCount: 0 };
|
|
1167
|
+
const persisted = existing.sourceRevision.revision === event.revision ? existing : yield* persistence.entities.updateSourceRevision(scope.workspaceId, existing.entityId, {
|
|
1168
|
+
sourceRevision: sourceRevision(scope, event, existing.sourceRevision.firstObservedAt, existing.sourceRevision.sourceUrl),
|
|
1169
|
+
expectedRevision: existing.revision,
|
|
1170
|
+
updatedAt: scope.committedAt
|
|
1171
|
+
});
|
|
1172
|
+
const projectionRevision = LedgerRevision.make(current.projection.projectionRevision + 1);
|
|
1173
|
+
return { entityProjectionCount: (yield* writeGraph(persistence, scope.workspaceId, {
|
|
1174
|
+
entityProjections: [{
|
|
1175
|
+
projection: {
|
|
1176
|
+
...current.projection,
|
|
1177
|
+
projectionRevision,
|
|
1178
|
+
sourceEntityRevision: LedgerRevision.make(persisted.revision),
|
|
1179
|
+
supersedesProjectionRevision: current.projection.projectionRevision,
|
|
1180
|
+
entityState: "deleted"
|
|
1181
|
+
},
|
|
1182
|
+
recordedAt: scope.committedAt
|
|
1183
|
+
}],
|
|
1184
|
+
nodes: [],
|
|
1185
|
+
evidenceItems: [],
|
|
1186
|
+
evidenceClaims: [],
|
|
1187
|
+
relationships: []
|
|
1188
|
+
}, event.eventId)).entityProjectionCount };
|
|
1189
|
+
});
|
|
1190
|
+
var materializePerson = Effect.fn("NormalizedPluginPageMaterialization.upsertPerson")(function* (persistence, cryptoService, scope, event) {
|
|
1191
|
+
const identity = {
|
|
1192
|
+
pluginConnectionId: scope.pluginConnectionId,
|
|
1193
|
+
providerId: scope.providerId,
|
|
1194
|
+
vendorPersonId: VendorImmutableId.make(event.vendorPersonId)
|
|
1195
|
+
};
|
|
1196
|
+
const existing = yield* persistence.people.findPersonBySourceIdentity(scope.workspaceId, identity).pipe(Effect.result);
|
|
1197
|
+
if (Result.isFailure(existing) && existing.failure._tag !== "RecordNotFoundError") return yield* existing.failure;
|
|
1198
|
+
const personId = Result.isSuccess(existing) ? existing.success.person.personId : PersonId.make(yield* stableUuid(cryptoService, materializationKey(scope, "person", event.vendorPersonId), event.eventId));
|
|
1199
|
+
const avatar = event.avatarUrl !== null && event.avatarUrl.toString().length <= 500 ? {
|
|
1200
|
+
_tag: "reference",
|
|
1201
|
+
reference: event.avatarUrl.toString()
|
|
1202
|
+
} : {
|
|
1203
|
+
_tag: "initials",
|
|
1204
|
+
text: derivePersonInitials(event.displayName)
|
|
1205
|
+
};
|
|
1206
|
+
const person = yield* Schema.decodeUnknownEffect(Schema.toType(Person))({
|
|
1207
|
+
personId,
|
|
1208
|
+
displayName: event.displayName,
|
|
1209
|
+
avatar,
|
|
1210
|
+
isActive: event.active,
|
|
1211
|
+
sourceIdentities: Result.isSuccess(existing) ? existing.success.person.sourceIdentities : [identity]
|
|
1212
|
+
}).pipe(Effect.mapError(() => malformed("normalized-person-invalid", event.eventId)));
|
|
1213
|
+
if (Result.isSuccess(existing) && existing.success.person.displayName === person.displayName && existing.success.person.isActive === person.isActive && existing.success.person.avatar._tag === person.avatar._tag && (existing.success.person.avatar._tag === "initials" ? existing.success.person.avatar.text === (person.avatar._tag === "initials" ? person.avatar.text : "") : existing.success.person.avatar.reference === (person.avatar._tag === "reference" ? person.avatar.reference : ""))) return 0;
|
|
1214
|
+
if (Result.isSuccess(existing)) yield* persistence.people.updatePerson(scope.workspaceId, person, existing.success.revision, scope.committedAt);
|
|
1215
|
+
else yield* persistence.people.createPerson(scope.workspaceId, person, scope.committedAt);
|
|
1216
|
+
return 1;
|
|
1217
|
+
});
|
|
1218
|
+
var evidencePredicate = (event) => {
|
|
1219
|
+
const decoded = Schema.decodeUnknownResult(EvidencePredicate)(event.evidenceType);
|
|
1220
|
+
if (Result.isSuccess(decoded)) return decoded.success;
|
|
1221
|
+
return "status-observed";
|
|
1222
|
+
};
|
|
1223
|
+
var materializeEvidence = Effect.fn("NormalizedPluginPageMaterialization.appendEvidence")(function* (persistence, cryptoService, scope, event) {
|
|
1224
|
+
const subject = yield* findEntity(persistence, scope, event.subject.vendorImmutableId);
|
|
1225
|
+
if (subject === null) return yield* malformed("normalized-evidence-subject-missing", event.eventId);
|
|
1226
|
+
if (canonicalKind(event.subject.entityType) === null) return yield* malformed("normalized-evidence-subject-unsupported", event.eventId);
|
|
1227
|
+
const nodeId = yield* nodeIdFor(cryptoService, scope, event.subject.vendorImmutableId, event.eventId);
|
|
1228
|
+
const evidenceId = EvidenceId.make(yield* stableUuid(cryptoService, materializationKey(scope, "evidence", event.evidenceId), event.eventId));
|
|
1229
|
+
const evidenceClaimId = EvidenceClaimId.make(yield* stableUuid(cryptoService, materializationKey(scope, "evidence-claim", event.evidenceId), event.eventId));
|
|
1230
|
+
const decodedData = Schema.decodeUnknownResult(EvidenceData)(event.data);
|
|
1231
|
+
const predicate = Result.isSuccess(decodedData) && decodedData.success.predicate !== void 0 ? decodedData.success.predicate : evidencePredicate(event);
|
|
1232
|
+
const value = Result.isSuccess(decodedData) && decodedData.success.value !== void 0 ? decodedData.success.value : {
|
|
1233
|
+
_tag: "state",
|
|
1234
|
+
value: event.summary
|
|
1235
|
+
};
|
|
1236
|
+
const source = subject.sourceRevision;
|
|
1237
|
+
const ageSeconds = Math.max(0, (DateTime.toEpochMillis(scope.committedAt) - DateTime.toEpochMillis(source.lastObservedAt)) / 1e3);
|
|
1238
|
+
const health = scope.successfulHealth._tag === "healthy" ? {
|
|
1239
|
+
_tag: "healthy",
|
|
1240
|
+
checkedAt: scope.committedAt
|
|
1241
|
+
} : {
|
|
1242
|
+
...scope.successfulHealth,
|
|
1243
|
+
checkedAt: scope.committedAt
|
|
1244
|
+
};
|
|
1245
|
+
const receipt = yield* writeGraph(persistence, scope.workspaceId, {
|
|
1246
|
+
entityProjections: [],
|
|
1247
|
+
nodes: [],
|
|
1248
|
+
evidenceItems: [{
|
|
1249
|
+
workspaceId: scope.workspaceId,
|
|
1250
|
+
evidenceId,
|
|
1251
|
+
schemaVersion: 1,
|
|
1252
|
+
attribution: {
|
|
1253
|
+
_tag: "plugin",
|
|
1254
|
+
pluginConnectionId: scope.pluginConnectionId,
|
|
1255
|
+
sourceEntityId: subject.entityId,
|
|
1256
|
+
sourceEntityRevision: LedgerRevision.make(subject.revision)
|
|
1257
|
+
},
|
|
1258
|
+
verifier: {
|
|
1259
|
+
_tag: "system",
|
|
1260
|
+
component: "normalized-plugin-page-materializer"
|
|
1261
|
+
},
|
|
1262
|
+
observedAt: event.capturedAt,
|
|
1263
|
+
recordedAt: scope.committedAt,
|
|
1264
|
+
validUntil: null,
|
|
1265
|
+
freshness: {
|
|
1266
|
+
_tag: "current",
|
|
1267
|
+
evaluatedAt: scope.committedAt,
|
|
1268
|
+
pluginHealth: health,
|
|
1269
|
+
provenance: {
|
|
1270
|
+
_tag: "provider",
|
|
1271
|
+
sourceRevision: source
|
|
1272
|
+
},
|
|
1273
|
+
sourceObservedAt: source.lastObservedAt,
|
|
1274
|
+
staleAfterSeconds: Math.max(1, Math.ceil(ageSeconds) + 1),
|
|
1275
|
+
synchronizedAt: scope.committedAt
|
|
1276
|
+
},
|
|
1277
|
+
retention: {
|
|
1278
|
+
classification: "evidence",
|
|
1279
|
+
retainUntil: null,
|
|
1280
|
+
legalHold: false
|
|
1281
|
+
}
|
|
1282
|
+
}],
|
|
1283
|
+
evidenceClaims: [{
|
|
1284
|
+
workspaceId: scope.workspaceId,
|
|
1285
|
+
evidenceClaimId,
|
|
1286
|
+
evidenceId,
|
|
1287
|
+
subjectNodeId: nodeId,
|
|
1288
|
+
predicate,
|
|
1289
|
+
value,
|
|
1290
|
+
recordedAt: scope.committedAt,
|
|
1291
|
+
supersedesEvidenceClaimId: null
|
|
1292
|
+
}],
|
|
1293
|
+
relationships: []
|
|
1294
|
+
}, event.eventId);
|
|
1295
|
+
return {
|
|
1296
|
+
evidenceItemCount: receipt.evidenceItemCount,
|
|
1297
|
+
evidenceClaimCount: receipt.evidenceClaimCount
|
|
1298
|
+
};
|
|
1299
|
+
});
|
|
1300
|
+
var materializeRelationship = Effect.fn("NormalizedPluginPageMaterialization.proposeRelationship")(function* (persistence, cryptoService, scope, event) {
|
|
1301
|
+
const resolveEndpoint = Effect.fn("NormalizedPluginPageMaterialization.resolveRelationshipEndpoint")(function* (reference) {
|
|
1302
|
+
if (reference.entityType === "release") {
|
|
1303
|
+
const releaseId = yield* releaseIdFor(cryptoService, scope, reference.vendorImmutableId, event.eventId);
|
|
1304
|
+
const release = yield* persistence.releases.get(scope.workspaceId, releaseId).pipe(Effect.result);
|
|
1305
|
+
if (Result.isFailure(release)) {
|
|
1306
|
+
if (release.failure._tag === "RecordNotFoundError") return yield* malformed("normalized-relationship-endpoint-missing", event.eventId);
|
|
1307
|
+
return yield* release.failure;
|
|
1308
|
+
}
|
|
1309
|
+
const nodeId = yield* releaseNodeIdFor(cryptoService, scope, reference.vendorImmutableId, event.eventId);
|
|
1310
|
+
const existingNode = yield* persistence.deliveryGraph.read(scope.workspaceId, {
|
|
1311
|
+
_tag: "node",
|
|
1312
|
+
nodeId
|
|
1313
|
+
}).pipe(Effect.result);
|
|
1314
|
+
if (Result.isFailure(existingNode) && existingNode.failure._tag !== "RecordNotFoundError") return yield* existingNode.failure;
|
|
1315
|
+
return {
|
|
1316
|
+
entity: null,
|
|
1317
|
+
kind: "release",
|
|
1318
|
+
node: Result.isSuccess(existingNode) ? null : {
|
|
1319
|
+
workspaceId: scope.workspaceId,
|
|
1320
|
+
nodeId,
|
|
1321
|
+
endpointKind: "release",
|
|
1322
|
+
resolution: {
|
|
1323
|
+
_tag: "resolved",
|
|
1324
|
+
target: {
|
|
1325
|
+
_tag: "release",
|
|
1326
|
+
releaseId
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
createdAt: scope.committedAt
|
|
1330
|
+
},
|
|
1331
|
+
nodeId,
|
|
1332
|
+
releaseId
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
const entity = yield* findEntity(persistence, scope, reference.vendorImmutableId);
|
|
1336
|
+
const kind = canonicalKind(reference.entityType);
|
|
1337
|
+
if (entity === null) return yield* malformed("normalized-relationship-endpoint-missing", event.eventId);
|
|
1338
|
+
if (kind === null) return yield* malformed("normalized-relationship-endpoint-unsupported", event.eventId);
|
|
1339
|
+
return {
|
|
1340
|
+
entity,
|
|
1341
|
+
kind,
|
|
1342
|
+
node: null,
|
|
1343
|
+
nodeId: yield* nodeIdFor(cryptoService, scope, reference.vendorImmutableId, event.eventId),
|
|
1344
|
+
releaseId: null
|
|
1345
|
+
};
|
|
1346
|
+
});
|
|
1347
|
+
const source = yield* resolveEndpoint(event.from);
|
|
1348
|
+
const target = yield* resolveEndpoint(event.to);
|
|
1349
|
+
const kind = yield* Schema.decodeUnknownEffect(RelationshipKind)(event.relationshipType).pipe(Effect.mapError(() => malformed("normalized-relationship-kind-invalid", event.eventId)));
|
|
1350
|
+
const provenanceEntity = source.entity ?? target.entity;
|
|
1351
|
+
if (provenanceEntity === null) return yield* malformed("normalized-relationship-provenance-entity-missing", event.eventId);
|
|
1352
|
+
const relationshipScope = source.releaseId !== null ? {
|
|
1353
|
+
_tag: "release",
|
|
1354
|
+
releaseId: source.releaseId
|
|
1355
|
+
} : null;
|
|
1356
|
+
const relationshipId = RelationshipId.make(yield* stableUuid(cryptoService, materializationKey(scope, "relationship", event.relationshipId), event.eventId));
|
|
1357
|
+
const existing = yield* persistence.deliveryGraph.read(scope.workspaceId, {
|
|
1358
|
+
_tag: "relationship",
|
|
1359
|
+
relationshipId,
|
|
1360
|
+
revision: null
|
|
1361
|
+
}).pipe(Effect.result);
|
|
1362
|
+
if (Result.isFailure(existing) && existing.failure._tag !== "RecordNotFoundError") return yield* existing.failure;
|
|
1363
|
+
const previous = Result.isSuccess(existing) && existing.success._tag === "relationship" ? existing.success.value : null;
|
|
1364
|
+
const revision = LedgerRevision.make((previous?.revision ?? 0) + 1);
|
|
1365
|
+
const nodes = [];
|
|
1366
|
+
if (source.node !== null) nodes.push(source.node);
|
|
1367
|
+
if (target.node !== null && target.node.nodeId !== source.nodeId) nodes.push(target.node);
|
|
1368
|
+
const receipt = yield* writeGraph(persistence, scope.workspaceId, {
|
|
1369
|
+
entityProjections: [],
|
|
1370
|
+
nodes,
|
|
1371
|
+
evidenceItems: [],
|
|
1372
|
+
evidenceClaims: [],
|
|
1373
|
+
relationships: [{
|
|
1374
|
+
workspaceId: scope.workspaceId,
|
|
1375
|
+
relationshipId,
|
|
1376
|
+
relationshipSchemaVersion: 1,
|
|
1377
|
+
revision,
|
|
1378
|
+
supersedesRevision: previous?.revision ?? null,
|
|
1379
|
+
kind,
|
|
1380
|
+
sourceNodeId: source.nodeId,
|
|
1381
|
+
sourceNodeKind: source.kind,
|
|
1382
|
+
targetNodeId: target.nodeId,
|
|
1383
|
+
targetNodeKind: target.kind,
|
|
1384
|
+
scope: relationshipScope,
|
|
1385
|
+
lifecycle: {
|
|
1386
|
+
_tag: "proposed",
|
|
1387
|
+
effectiveAt: event.observedAt
|
|
1388
|
+
},
|
|
1389
|
+
confidence: {
|
|
1390
|
+
_tag: "inferred",
|
|
1391
|
+
score: event.confidence,
|
|
1392
|
+
rationale: `Proposed by ${scope.providerId} normalized synchronization.`
|
|
1393
|
+
},
|
|
1394
|
+
provenance: {
|
|
1395
|
+
_tag: "plugin",
|
|
1396
|
+
pluginConnectionId: scope.pluginConnectionId,
|
|
1397
|
+
sourceEntityId: provenanceEntity.entityId,
|
|
1398
|
+
sourceEntityRevision: LedgerRevision.make(provenanceEntity.revision)
|
|
1399
|
+
},
|
|
1400
|
+
recordedBy: {
|
|
1401
|
+
_tag: "system",
|
|
1402
|
+
component: "normalized-plugin-page-materializer"
|
|
1403
|
+
},
|
|
1404
|
+
evidenceClaimIds: yield* Effect.forEach(event.evidenceIds, (evidenceId) => stableUuid(cryptoService, materializationKey(scope, "evidence-claim", evidenceId), event.eventId).pipe(Effect.map(EvidenceClaimId.make))),
|
|
1405
|
+
recordedAt: scope.committedAt
|
|
1406
|
+
}]
|
|
1407
|
+
}, event.eventId);
|
|
1408
|
+
return {
|
|
1409
|
+
nodeCount: receipt.nodeCount,
|
|
1410
|
+
relationshipCount: receipt.relationshipCount
|
|
1411
|
+
};
|
|
1412
|
+
});
|
|
1413
|
+
var hasAuthoritativeJiraFixVersions = (event) => {
|
|
1414
|
+
if (event._tag !== "UpsertEntity" || event.entityType !== "jira.issue") return false;
|
|
1415
|
+
const snapshot = Schema.decodeUnknownResult(JiraIssueRelationshipSnapshot)(event.attributes);
|
|
1416
|
+
return Result.isSuccess(snapshot) && !snapshot.success.truncatedFields.includes("fixVersions");
|
|
1417
|
+
};
|
|
1418
|
+
var isReleaseContainmentForIssue = (event, issue) => event._tag === "ProposeRelationship" && event.relationshipType === "contains" && event.from.entityType === "release" && event.to.entityType === issue.entityType && event.to.vendorImmutableId === issue.vendorImmutableId;
|
|
1419
|
+
var retireMissingJiraReleaseContainments = Effect.fn("NormalizedPluginPageMaterialization.retireMissingJiraReleaseContainments")(function* (persistence, cryptoService, scope, acceptedEvents) {
|
|
1420
|
+
let relationshipCount = 0;
|
|
1421
|
+
for (const issue of acceptedEvents) {
|
|
1422
|
+
if (!hasAuthoritativeJiraFixVersions(issue)) continue;
|
|
1423
|
+
const source = yield* findEntity(persistence, scope, issue.vendorImmutableId);
|
|
1424
|
+
if (source === null) return yield* malformed("normalized-relationship-endpoint-missing", issue.eventId);
|
|
1425
|
+
const issueNodeId = yield* nodeIdFor(cryptoService, scope, issue.vendorImmutableId, issue.eventId);
|
|
1426
|
+
const neighborhood = yield* persistence.deliveryGraph.read(scope.workspaceId, {
|
|
1427
|
+
_tag: "nodeRelationships",
|
|
1428
|
+
nodeId: issueNodeId,
|
|
1429
|
+
limit: 500
|
|
1430
|
+
});
|
|
1431
|
+
if (neighborhood._tag !== "nodeRelationships") continue;
|
|
1432
|
+
if (neighborhood.value.truncated) return yield* malformed("normalized-jira-containment-neighborhood-truncated", issue.eventId);
|
|
1433
|
+
const currentRelationshipIds = new Set(yield* Effect.forEach(acceptedEvents.filter((event) => isReleaseContainmentForIssue(event, issue)), ({ relationshipId }) => stableUuid(cryptoService, materializationKey(scope, "relationship", relationshipId), issue.eventId).pipe(Effect.map(RelationshipId.make))));
|
|
1434
|
+
const removed = neighborhood.value.relationships.filter((relationship) => relationship.kind === "contains" && relationship.sourceNodeKind === "release" && relationship.targetNodeId === issueNodeId && relationship.targetNodeKind === "issue" && relationship.provenance._tag === "plugin" && relationship.provenance.pluginConnectionId === scope.pluginConnectionId && relationship.provenance.sourceEntityId === source.entityId && !currentRelationshipIds.has(relationship.relationshipId));
|
|
1435
|
+
if (removed.length === 0) continue;
|
|
1436
|
+
for (const previous of removed) {
|
|
1437
|
+
if (previous.lifecycle._tag === "rejected" || previous.lifecycle._tag === "superseded") continue;
|
|
1438
|
+
const receipt = yield* writeGraph(persistence, scope.workspaceId, {
|
|
1439
|
+
entityProjections: [],
|
|
1440
|
+
nodes: [],
|
|
1441
|
+
evidenceItems: [],
|
|
1442
|
+
evidenceClaims: [],
|
|
1443
|
+
relationships: [{
|
|
1444
|
+
...previous,
|
|
1445
|
+
revision: LedgerRevision.make(previous.revision + 1),
|
|
1446
|
+
supersedesRevision: previous.revision,
|
|
1447
|
+
lifecycle: {
|
|
1448
|
+
_tag: "superseded",
|
|
1449
|
+
effectiveAt: issue.observedAt,
|
|
1450
|
+
reason: "No longer present in the latest Jira fixVersion observation."
|
|
1451
|
+
},
|
|
1452
|
+
provenance: {
|
|
1453
|
+
_tag: "plugin",
|
|
1454
|
+
pluginConnectionId: scope.pluginConnectionId,
|
|
1455
|
+
sourceEntityId: source.entityId,
|
|
1456
|
+
sourceEntityRevision: LedgerRevision.make(source.revision)
|
|
1457
|
+
},
|
|
1458
|
+
recordedBy: {
|
|
1459
|
+
_tag: "system",
|
|
1460
|
+
component: "normalized-plugin-page-materializer"
|
|
1461
|
+
},
|
|
1462
|
+
recordedAt: scope.committedAt
|
|
1463
|
+
}]
|
|
1464
|
+
}, issue.eventId);
|
|
1465
|
+
relationshipCount += receipt.relationshipCount;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
return relationshipCount;
|
|
1469
|
+
});
|
|
1470
|
+
/**
|
|
1471
|
+
* Commit one decoded page and all accepted canonical projections atomically.
|
|
1472
|
+
* The existing plugin checkpoint transaction nests as a savepoint; only its
|
|
1473
|
+
* newly accepted event identities cross the materialization seam.
|
|
1474
|
+
*/
|
|
1475
|
+
var materializeNormalizedPluginPage = Effect.fn("NormalizedPluginPageMaterialization.materializePage")(function* (scope, page) {
|
|
1476
|
+
const cryptoService = yield* Crypto.Crypto;
|
|
1477
|
+
const persistence = yield* Persistence;
|
|
1478
|
+
return yield* persistence.transact(Effect.gen(function* () {
|
|
1479
|
+
if (scope.expectedAuthority !== void 0) yield* verifyPluginSynchronizationAuthority(persistence, scope.expectedAuthority);
|
|
1480
|
+
const committed = yield* persistence.pluginRuntime.commitNormalizedPageReceipt(scope.workspaceId, scope.pluginConnectionId, scope.providerId, scope.streamKey, scope.expectedRevision, page, scope.committedAt, scope.successfulHealth);
|
|
1481
|
+
const accepted = new Set(committed.acceptedEventIds);
|
|
1482
|
+
const events = page.events.filter(({ eventId }) => accepted.has(eventId));
|
|
1483
|
+
let entityProjectionCount = 0;
|
|
1484
|
+
let evidenceClaimCount = 0;
|
|
1485
|
+
let evidenceItemCount = 0;
|
|
1486
|
+
let nodeCount = 0;
|
|
1487
|
+
let personCount = 0;
|
|
1488
|
+
let relationshipCount = 0;
|
|
1489
|
+
let skippedEntityCount = 0;
|
|
1490
|
+
for (const event of events) {
|
|
1491
|
+
if (event._tag !== "UpsertPerson") continue;
|
|
1492
|
+
personCount += yield* materializePerson(persistence, cryptoService, scope, event);
|
|
1493
|
+
}
|
|
1494
|
+
for (const event of events) if (event._tag === "UpsertEntity") {
|
|
1495
|
+
if (event.entityType === "release") {
|
|
1496
|
+
nodeCount += (yield* materializeRelease(persistence, cryptoService, scope, event)).nodeCount;
|
|
1497
|
+
continue;
|
|
1498
|
+
}
|
|
1499
|
+
const receipt = yield* materializeUpsertEntity(persistence, cryptoService, scope, event);
|
|
1500
|
+
entityProjectionCount += receipt.entityProjectionCount;
|
|
1501
|
+
nodeCount += receipt.nodeCount;
|
|
1502
|
+
skippedEntityCount += receipt.skippedEntityCount;
|
|
1503
|
+
} else if (event._tag === "TombstoneEntity") entityProjectionCount += (yield* materializeTombstoneEntity(persistence, scope, event)).entityProjectionCount;
|
|
1504
|
+
for (const event of events) {
|
|
1505
|
+
if (event._tag !== "AppendEvidence") continue;
|
|
1506
|
+
const receipt = yield* materializeEvidence(persistence, cryptoService, scope, event);
|
|
1507
|
+
evidenceItemCount += receipt.evidenceItemCount;
|
|
1508
|
+
evidenceClaimCount += receipt.evidenceClaimCount;
|
|
1509
|
+
}
|
|
1510
|
+
for (const event of events) {
|
|
1511
|
+
if (event._tag !== "ProposeRelationship") continue;
|
|
1512
|
+
const receipt = yield* materializeRelationship(persistence, cryptoService, scope, event);
|
|
1513
|
+
nodeCount += receipt.nodeCount;
|
|
1514
|
+
relationshipCount += receipt.relationshipCount;
|
|
1515
|
+
}
|
|
1516
|
+
relationshipCount += yield* retireMissingJiraReleaseContainments(persistence, cryptoService, scope, events);
|
|
1517
|
+
if (events.length > 0) {
|
|
1518
|
+
const inference = yield* materializeRelationshipInference(persistence, (identity) => stableUuid(cryptoService, identity, "relationship-inference"), scope);
|
|
1519
|
+
evidenceClaimCount += inference.evidenceClaimCount;
|
|
1520
|
+
evidenceItemCount += inference.evidenceItemCount;
|
|
1521
|
+
nodeCount += inference.nodeCount;
|
|
1522
|
+
relationshipCount += inference.relationshipCount;
|
|
1523
|
+
}
|
|
1524
|
+
return {
|
|
1525
|
+
pageCommitted: committed.pageCommitted,
|
|
1526
|
+
acceptedEventCount: events.length,
|
|
1527
|
+
entityProjectionCount,
|
|
1528
|
+
evidenceClaimCount,
|
|
1529
|
+
evidenceItemCount,
|
|
1530
|
+
nodeCount,
|
|
1531
|
+
personCount,
|
|
1532
|
+
relationshipCount,
|
|
1533
|
+
skippedEntityCount
|
|
1534
|
+
};
|
|
1535
|
+
}));
|
|
1536
|
+
});
|
|
1537
|
+
//#endregion
|
|
1538
|
+
//#region src/server/application/manualPluginSynchronization.ts
|
|
1539
|
+
var MAXIMUM_PAGES_PER_INVOCATION = 100;
|
|
1540
|
+
var SYNCHRONIZATION_CLAIM_LIFETIME_MINUTES = 15;
|
|
1541
|
+
var SOURCE_UNAVAILABLE_OUTCOME = "source-unavailable";
|
|
1542
|
+
var SYNCHRONIZED_OUTCOME = "synchronized";
|
|
1543
|
+
var successfulHealthAt = (health, checkedAt) => health._tag === "healthy" ? {
|
|
1544
|
+
_tag: "healthy",
|
|
1545
|
+
checkedAt
|
|
1546
|
+
} : {
|
|
1547
|
+
...health,
|
|
1548
|
+
checkedAt,
|
|
1549
|
+
retryAt: health.retryAt !== null && DateTime.Order(checkedAt, health.retryAt) <= 0 ? health.retryAt : null
|
|
1550
|
+
};
|
|
1551
|
+
/** Build a deterministic driver registry for production or fixture connections. */
|
|
1552
|
+
var makeManualPluginSyncDriverRegistry = (drivers) => {
|
|
1553
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
1554
|
+
for (const driver of drivers) byProvider.set(driver.providerId, driver);
|
|
1555
|
+
return { get: (providerId) => Option.fromNullishOr(byProvider.get(providerId)) };
|
|
1556
|
+
};
|
|
1557
|
+
var connectionSync = (connection, request) => connection.sync(request);
|
|
1558
|
+
/** Production drivers for first-party connections that currently negotiate synchronization. */
|
|
1559
|
+
var firstPartyManualPluginSyncDrivers = makeManualPluginSyncDriverRegistry([
|
|
1560
|
+
{
|
|
1561
|
+
providerId: "codecommit",
|
|
1562
|
+
streamKey: firstPartySyncStreamKey("codecommit"),
|
|
1563
|
+
sync: connectionSync
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
providerId: "codepipeline",
|
|
1567
|
+
streamKey: firstPartySyncStreamKey("codepipeline"),
|
|
1568
|
+
sync: connectionSync
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
providerId: "jira",
|
|
1572
|
+
streamKey: firstPartySyncStreamKey("jira"),
|
|
1573
|
+
sync: connectionSync
|
|
1574
|
+
},
|
|
1575
|
+
{
|
|
1576
|
+
providerId: "clockify",
|
|
1577
|
+
streamKey: firstPartySyncStreamKey("clockify"),
|
|
1578
|
+
sync: connectionSync
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
providerId: "confluence",
|
|
1582
|
+
streamKey: firstPartySyncStreamKey("confluence"),
|
|
1583
|
+
sync: connectionSync
|
|
1584
|
+
}
|
|
1585
|
+
]);
|
|
1586
|
+
var unavailable = () => new ApplicationServiceUnavailable({ retryAt: null });
|
|
1587
|
+
var mapPersistenceRead = (failure) => failure._tag === "RecordNotFoundError" ? new ApplicationResourceNotFound() : unavailable();
|
|
1588
|
+
var pluginFailureTags = /* @__PURE__ */ new Set([
|
|
1589
|
+
"PluginAuthenticationFailure",
|
|
1590
|
+
"PluginAuthorizationFailure",
|
|
1591
|
+
"PluginRateLimitFailure",
|
|
1592
|
+
"PluginTimeoutFailure",
|
|
1593
|
+
"PluginMalformedResponseFailure",
|
|
1594
|
+
"PluginOutageFailure",
|
|
1595
|
+
"PluginCancellationFailure",
|
|
1596
|
+
"PluginConflictFailure",
|
|
1597
|
+
"PluginUnsupportedCapabilityFailure",
|
|
1598
|
+
"PluginConfigurationFailure",
|
|
1599
|
+
"PluginUnknownOutcomeFailure"
|
|
1600
|
+
]);
|
|
1601
|
+
var isPluginFailure = (failure) => Predicate.hasProperty(failure, "_tag") && typeof failure._tag === "string" && pluginFailureTags.has(failure._tag);
|
|
1602
|
+
var sourceFailure = (failure) => {
|
|
1603
|
+
if (isPluginFailure(failure)) return failure;
|
|
1604
|
+
if (Predicate.hasProperty(failure, "_tag") && failure._tag === "NormalizedPluginPageMaterializationError") return new PluginMalformedResponseFailure({
|
|
1605
|
+
operation: "manual-sync",
|
|
1606
|
+
diagnosticCode: "normalized-plugin-page-rejected"
|
|
1607
|
+
});
|
|
1608
|
+
if (Predicate.hasProperty(failure, "_tag") && failure._tag === "SourceIdentityMismatchError" && Predicate.hasProperty(failure, "recordKind") && (failure.recordKind === "plugin-sync-event" || failure.recordKind === "plugin-sync-page")) return new PluginMalformedResponseFailure({
|
|
1609
|
+
operation: "manual-sync",
|
|
1610
|
+
diagnosticCode: "plugin-sync-source-identity-conflict"
|
|
1611
|
+
});
|
|
1612
|
+
return null;
|
|
1613
|
+
};
|
|
1614
|
+
var safeFailureMessage = (failure) => {
|
|
1615
|
+
switch (failure._tag) {
|
|
1616
|
+
case "PluginAuthenticationFailure": return "Provider authentication failed.";
|
|
1617
|
+
case "PluginAuthorizationFailure": return "Provider permission was denied.";
|
|
1618
|
+
case "PluginRateLimitFailure": return "Provider rate limit was reached.";
|
|
1619
|
+
case "PluginTimeoutFailure": return "Provider request timed out.";
|
|
1620
|
+
case "PluginMalformedResponseFailure": return "Provider returned an invalid response.";
|
|
1621
|
+
case "PluginOutageFailure": return "Provider is temporarily unavailable.";
|
|
1622
|
+
case "PluginCancellationFailure": return "Provider synchronization was cancelled.";
|
|
1623
|
+
case "PluginConflictFailure": return "Provider state changed during synchronization.";
|
|
1624
|
+
case "PluginUnsupportedCapabilityFailure": return "Provider synchronization is not supported.";
|
|
1625
|
+
case "PluginConfigurationFailure": return "Provider configuration is incomplete.";
|
|
1626
|
+
case "PluginUnknownOutcomeFailure": return "Provider synchronization outcome is unknown.";
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
var failureHealth = Effect.fn("ManualPluginSynchronization.failureHealth")(function* (failure, checkedAt) {
|
|
1630
|
+
return yield* Schema.decodeUnknownEffect(Schema.toType(PluginHealth))({
|
|
1631
|
+
_tag: "unavailable",
|
|
1632
|
+
checkedAt,
|
|
1633
|
+
failureClass: pluginFailureClass(failure),
|
|
1634
|
+
retryAt: failure._tag === "PluginRateLimitFailure" ? failure.retryAt : null,
|
|
1635
|
+
safeMessage: safeFailureMessage(failure)
|
|
1636
|
+
});
|
|
1637
|
+
});
|
|
1638
|
+
var stateFromAttemptState = (pluginConnectionId, providerId, streamKey, attemptState) => {
|
|
1639
|
+
const lastAttempt = attemptState.latestAttempt ?? void 0;
|
|
1640
|
+
const lastSuccess = attemptState.latestSynchronized ?? void 0;
|
|
1641
|
+
return {
|
|
1642
|
+
pluginConnectionId,
|
|
1643
|
+
providerId,
|
|
1644
|
+
streamKey,
|
|
1645
|
+
lastAttemptAt: lastAttempt?.startedAt ?? null,
|
|
1646
|
+
lastSuccessAt: lastSuccess?.completedAt ?? null,
|
|
1647
|
+
result: lastAttempt === void 0 ? "never" : lastAttempt.outcome === null ? "running" : lastAttempt.outcome,
|
|
1648
|
+
pagesCommitted: lastAttempt?.pagesCommitted ?? 0
|
|
1649
|
+
};
|
|
1650
|
+
};
|
|
1651
|
+
/** Build the bounded synchronization application over a scoped provider runtime map. */
|
|
1652
|
+
var makeManualPluginSynchronization = Effect.fn("ManualPluginSynchronization.make")(function* (connections, drivers = firstPartyManualPluginSyncDrivers) {
|
|
1653
|
+
const persistence = yield* Persistence;
|
|
1654
|
+
const wakeups = yield* DomainEventWakeups;
|
|
1655
|
+
const cryptoService = yield* Crypto.Crypto;
|
|
1656
|
+
const bind = Effect.fn("ManualPluginSynchronization.bind")(function* (input) {
|
|
1657
|
+
const connection = yield* persistence.pluginConnections.get(input.workspaceId, input.pluginConnectionId).pipe(Effect.mapError(mapPersistenceRead));
|
|
1658
|
+
const driver = drivers.get(connection.providerId);
|
|
1659
|
+
if (Option.isNone(driver)) return yield* new ApplicationInvalidRequest();
|
|
1660
|
+
const runtime = yield* persistence.pluginRuntime.getRuntime(input.workspaceId, input.pluginConnectionId).pipe(Effect.mapError(mapPersistenceRead));
|
|
1661
|
+
const descriptor = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(NegotiatedPluginDescriptorV1))(runtime.descriptorJson).pipe(Effect.mapError(() => new ApplicationInvalidRequest()));
|
|
1662
|
+
if (!supportsFirstPartySynchronization(connection.providerId, descriptor)) return yield* new ApplicationInvalidRequest();
|
|
1663
|
+
const streamKey = yield* Schema.decodeUnknownEffect(PluginStreamKey)(driver.value.streamKey).pipe(Effect.mapError(() => new ApplicationInvalidRequest()));
|
|
1664
|
+
return {
|
|
1665
|
+
...input,
|
|
1666
|
+
providerId: connection.providerId,
|
|
1667
|
+
driver: driver.value,
|
|
1668
|
+
streamKey
|
|
1669
|
+
};
|
|
1670
|
+
});
|
|
1671
|
+
const releaseSynchronization = Effect.fn("ManualPluginSynchronization.releaseSynchronization")(function* (claim) {
|
|
1672
|
+
yield* persistence.pluginRuntime.releaseSyncClaim(claim.workspaceId, claim.pluginConnectionId, claim.streamKey, claim.claimId).pipe(Effect.mapError(() => unavailable()));
|
|
1673
|
+
});
|
|
1674
|
+
const claimSynchronization = Effect.fn("ManualPluginSynchronization.claimSynchronization")(function* (bound) {
|
|
1675
|
+
const claimId = yield* cryptoService.randomUUIDv4.pipe(Effect.mapError(() => unavailable()));
|
|
1676
|
+
const claimedAt = DateTime.makeUnsafe(yield* Effect.clockWith((clock) => clock.currentTimeMillis));
|
|
1677
|
+
const expiresAt = DateTime.add(claimedAt, { minutes: SYNCHRONIZATION_CLAIM_LIFETIME_MINUTES });
|
|
1678
|
+
if (!(yield* persistence.pluginRuntime.claimSync(bound.workspaceId, bound.pluginConnectionId, bound.providerId, bound.streamKey, claimId, claimedAt, expiresAt).pipe(Effect.mapError(() => unavailable())))) return yield* unavailable();
|
|
1679
|
+
return {
|
|
1680
|
+
...bound,
|
|
1681
|
+
claimId
|
|
1682
|
+
};
|
|
1683
|
+
});
|
|
1684
|
+
const stateFor = Effect.fn("ManualPluginSynchronization.stateFor")(function* (bound) {
|
|
1685
|
+
const attemptState = yield* persistence.pluginRuntime.getSyncAttemptState(bound.workspaceId, bound.pluginConnectionId, bound.streamKey).pipe(Effect.mapError(() => unavailable()));
|
|
1686
|
+
return stateFromAttemptState(bound.pluginConnectionId, bound.providerId, bound.streamKey, attemptState);
|
|
1687
|
+
});
|
|
1688
|
+
const readState = Effect.fn("ManualPluginSynchronization.state")(function* (input) {
|
|
1689
|
+
const bound = yield* bind(input);
|
|
1690
|
+
return yield* stateFor(bound);
|
|
1691
|
+
});
|
|
1692
|
+
const persistHealth = Effect.fn("ManualPluginSynchronization.persistHealth")(function* (bound, authority, health, failed) {
|
|
1693
|
+
const persisted = yield* persistence.transact(Effect.gen(function* () {
|
|
1694
|
+
yield* verifyPluginSynchronizationAuthority(persistence, authority);
|
|
1695
|
+
const runtime = yield* persistence.pluginRuntime.getRuntime(bound.workspaceId, bound.pluginConnectionId);
|
|
1696
|
+
yield* persistence.pluginRuntime.recordHealth(bound.workspaceId, bound.pluginConnectionId, runtime.revision, health, failed ? runtime.consecutiveFailures + 1 : 0);
|
|
1697
|
+
yield* appendPortfolioInvalidation({
|
|
1698
|
+
workspaceId: bound.workspaceId,
|
|
1699
|
+
pluginConnectionId: bound.pluginConnectionId,
|
|
1700
|
+
releaseId: null,
|
|
1701
|
+
occurredAt: health.checkedAt,
|
|
1702
|
+
reason: "plugin-health"
|
|
1703
|
+
}).pipe(Effect.provideService(Crypto.Crypto, cryptoService), Effect.provideService(Persistence, persistence));
|
|
1704
|
+
return true;
|
|
1705
|
+
})).pipe(Effect.catchTag("PluginConflictFailure", () => Effect.succeed(false)), Effect.mapError(() => unavailable()));
|
|
1706
|
+
if (persisted) yield* wakeups.notify(bound.workspaceId);
|
|
1707
|
+
return persisted;
|
|
1708
|
+
});
|
|
1709
|
+
const initialCheckpoint = Effect.fn("ManualPluginSynchronization.initialCheckpoint")(function* (bound) {
|
|
1710
|
+
const current = yield* Effect.result(persistence.pluginRuntime.getStream(bound.workspaceId, bound.pluginConnectionId, bound.streamKey));
|
|
1711
|
+
if (Result.isFailure(current)) {
|
|
1712
|
+
if (current.failure._tag === "RecordNotFoundError") return null;
|
|
1713
|
+
return yield* Effect.fail(current.failure);
|
|
1714
|
+
}
|
|
1715
|
+
return current.success.checkpointJson === null ? null : yield* Schema.decodeUnknownEffect(Schema.fromJsonString(PluginCheckpointV1))(current.success.checkpointJson);
|
|
1716
|
+
});
|
|
1717
|
+
const run = Effect.fn("ManualPluginSynchronization.run")(function* (bound, authority, connection, health) {
|
|
1718
|
+
const checkpoint = yield* initialCheckpoint(bound);
|
|
1719
|
+
const request = yield* Schema.decodeUnknownEffect(PluginSyncRequestV1)({
|
|
1720
|
+
streamKey: bound.streamKey,
|
|
1721
|
+
checkpoint
|
|
1722
|
+
});
|
|
1723
|
+
const initialStream = yield* Effect.result(persistence.pluginRuntime.getStream(bound.workspaceId, bound.pluginConnectionId, bound.streamKey));
|
|
1724
|
+
const revision = Result.isSuccess(initialStream) ? initialStream.success.revision : 0;
|
|
1725
|
+
return yield* Stream.runFoldEffect(bound.driver.sync(connection, request).pipe(Stream.take(MAXIMUM_PAGES_PER_INVOCATION)), () => ({
|
|
1726
|
+
health,
|
|
1727
|
+
isTerminal: false,
|
|
1728
|
+
pagesSeen: 0,
|
|
1729
|
+
pagesCommitted: 0,
|
|
1730
|
+
revision
|
|
1731
|
+
}), (state, page) => Effect.gen(function* () {
|
|
1732
|
+
if (state.isTerminal) return yield* new PluginMalformedResponseFailure({
|
|
1733
|
+
operation: "manual-sync",
|
|
1734
|
+
diagnosticCode: "manual-sync-page-after-terminal"
|
|
1735
|
+
});
|
|
1736
|
+
const committedAt = DateTime.makeUnsafe(yield* Clock.currentTimeMillis);
|
|
1737
|
+
const successfulHealth = successfulHealthAt(state.health, committedAt);
|
|
1738
|
+
const receipt = yield* materializeNormalizedPluginPage({
|
|
1739
|
+
workspaceId: bound.workspaceId,
|
|
1740
|
+
pluginConnectionId: bound.pluginConnectionId,
|
|
1741
|
+
providerId: bound.providerId,
|
|
1742
|
+
streamKey: bound.streamKey,
|
|
1743
|
+
expectedRevision: state.revision,
|
|
1744
|
+
committedAt,
|
|
1745
|
+
successfulHealth,
|
|
1746
|
+
expectedAuthority: authority
|
|
1747
|
+
}, page).pipe(Effect.provideService(Crypto.Crypto, cryptoService), Effect.provideService(Persistence, persistence));
|
|
1748
|
+
const pagesSeen = state.pagesSeen + 1;
|
|
1749
|
+
return {
|
|
1750
|
+
health: successfulHealth,
|
|
1751
|
+
isTerminal: !page.hasMore,
|
|
1752
|
+
pagesSeen,
|
|
1753
|
+
pagesCommitted: state.pagesCommitted + (receipt.pageCommitted ? 1 : 0),
|
|
1754
|
+
revision: state.revision + (receipt.pageCommitted ? 1 : 0)
|
|
1755
|
+
};
|
|
1756
|
+
}));
|
|
1757
|
+
});
|
|
1758
|
+
const synchronizeBound = Effect.fn("ManualPluginSynchronization.synchronizeBound")(function* (input, bound) {
|
|
1759
|
+
const { authority, connection: connectionRecord } = yield* capturePluginSynchronizationAuthority(persistence, bound.workspaceId, bound.pluginConnectionId).pipe(Effect.mapError(mapPersistenceRead));
|
|
1760
|
+
if (!connectionRecord.isEnabled) return yield* new ApplicationInvalidRequest();
|
|
1761
|
+
const startedAt = DateTime.makeUnsafe(yield* Effect.clockWith((clock) => clock.currentTimeMillis));
|
|
1762
|
+
const attempt = yield* persistence.pluginRuntime.beginSyncAttempt(bound.workspaceId, bound.pluginConnectionId, bound.providerId, bound.streamKey, startedAt).pipe(Effect.mapError(() => unavailable()));
|
|
1763
|
+
const synchronized = yield* Effect.result(Effect.scoped(Effect.flatMap(connections.contextEffect({
|
|
1764
|
+
workspaceId: bound.workspaceId,
|
|
1765
|
+
pluginConnectionId: bound.pluginConnectionId
|
|
1766
|
+
}), (context) => Effect.gen(function* () {
|
|
1767
|
+
const connection = Context.get(context, PluginConnection);
|
|
1768
|
+
const health = yield* connection.health;
|
|
1769
|
+
if (health._tag === "unavailable" || health._tag === "disabled") return health;
|
|
1770
|
+
const completed = yield* run(bound, authority, connection, health);
|
|
1771
|
+
if (!completed.isTerminal && (completed.pagesSeen < MAXIMUM_PAGES_PER_INVOCATION || completed.pagesCommitted === 0)) return yield* new PluginMalformedResponseFailure({
|
|
1772
|
+
operation: "manual-sync",
|
|
1773
|
+
diagnosticCode: "manual-sync-terminal-page-missing"
|
|
1774
|
+
});
|
|
1775
|
+
return completed.health;
|
|
1776
|
+
}).pipe(Effect.provide(context)))));
|
|
1777
|
+
const outcome = yield* Effect.gen(function* () {
|
|
1778
|
+
if (Result.isSuccess(synchronized)) {
|
|
1779
|
+
const health = synchronized.success;
|
|
1780
|
+
const sourceUnavailable = health._tag === "unavailable" || health._tag === "disabled";
|
|
1781
|
+
const healthPersisted = yield* persistHealth(bound, authority, health, sourceUnavailable);
|
|
1782
|
+
return sourceUnavailable || !healthPersisted ? SOURCE_UNAVAILABLE_OUTCOME : SYNCHRONIZED_OUTCOME;
|
|
1783
|
+
}
|
|
1784
|
+
const failure = sourceFailure(synchronized.failure);
|
|
1785
|
+
if (failure === null) return yield* unavailable();
|
|
1786
|
+
const health = yield* failureHealth(failure, DateTime.makeUnsafe(yield* Effect.clockWith((clock) => clock.currentTimeMillis))).pipe(Effect.mapError(() => unavailable()));
|
|
1787
|
+
yield* persistHealth(bound, authority, health, true);
|
|
1788
|
+
return SOURCE_UNAVAILABLE_OUTCOME;
|
|
1789
|
+
});
|
|
1790
|
+
const completedAt = DateTime.makeUnsafe(yield* Effect.clockWith((clock) => clock.currentTimeMillis));
|
|
1791
|
+
yield* persistence.pluginRuntime.completeSyncAttempt(bound.workspaceId, bound.pluginConnectionId, bound.streamKey, attempt.attemptSequence, outcome, completedAt).pipe(Effect.mapError(() => unavailable()));
|
|
1792
|
+
return yield* readState(input);
|
|
1793
|
+
});
|
|
1794
|
+
return {
|
|
1795
|
+
state: readState,
|
|
1796
|
+
synchronize: Effect.fn("ManualPluginSynchronization.synchronize")(function* (input) {
|
|
1797
|
+
const bound = yield* bind(input);
|
|
1798
|
+
return yield* Effect.acquireUseRelease(claimSynchronization(bound), () => synchronizeBound(input, bound), releaseSynchronization);
|
|
1799
|
+
})
|
|
1800
|
+
};
|
|
1801
|
+
});
|
|
1802
|
+
//#endregion
|
|
1803
|
+
export { firstPartyManualPluginSyncDrivers, makeManualPluginSyncDriverRegistry, makeManualPluginSynchronization };
|
|
1804
|
+
|
|
1805
|
+
//# sourceMappingURL=manualPluginSynchronization-C0aHB4UM.js.map
|