@braidhq/server 0.1.0 → 0.2.1
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 +134 -106
- package/dist/app.d.ts +7 -15
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +74 -45
- package/dist/app.js.map +1 -1
- package/dist/authMode.d.ts +39 -0
- package/dist/authMode.d.ts.map +1 -0
- package/dist/authMode.js +50 -0
- package/dist/authMode.js.map +1 -0
- package/dist/composeApp.d.ts +80 -0
- package/dist/composeApp.d.ts.map +1 -0
- package/dist/composeApp.js +137 -0
- package/dist/composeApp.js.map +1 -0
- package/dist/composeFsApp.d.ts +27 -0
- package/dist/composeFsApp.d.ts.map +1 -0
- package/dist/{composeFs.js → composeFsApp.js} +127 -126
- package/dist/composeFsApp.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/_shared/env.d.ts +10 -0
- package/dist/infrastructure/_shared/env.d.ts.map +1 -0
- package/dist/infrastructure/{env.js → _shared/env.js} +5 -6
- package/dist/infrastructure/_shared/env.js.map +1 -0
- package/dist/infrastructure/_shared/frontmatter.d.ts +13 -0
- package/dist/infrastructure/_shared/frontmatter.d.ts.map +1 -0
- package/dist/infrastructure/{fs → _shared}/frontmatter.js +5 -5
- package/dist/infrastructure/_shared/frontmatter.js.map +1 -0
- package/dist/infrastructure/_shared/jsonFileStore.d.ts.map +1 -0
- package/dist/infrastructure/_shared/jsonFileStore.js.map +1 -0
- package/dist/infrastructure/{fs → _shared}/paths.d.ts +17 -10
- package/dist/infrastructure/_shared/paths.d.ts.map +1 -0
- package/dist/infrastructure/{fs → _shared}/paths.js +27 -20
- package/dist/infrastructure/_shared/paths.js.map +1 -0
- package/dist/infrastructure/auth/AccessPolicy.d.ts +33 -58
- package/dist/infrastructure/auth/AccessPolicy.d.ts.map +1 -1
- package/dist/infrastructure/auth/AccessPolicy.js +35 -42
- package/dist/infrastructure/auth/AccessPolicy.js.map +1 -1
- package/dist/infrastructure/auth/SessionStore.d.ts +22 -12
- package/dist/infrastructure/auth/SessionStore.d.ts.map +1 -1
- package/dist/infrastructure/auth/SessionStore.js +20 -20
- package/dist/infrastructure/auth/SessionStore.js.map +1 -1
- package/dist/infrastructure/batch/FsBatchPlanRepository.d.ts +14 -0
- package/dist/infrastructure/batch/FsBatchPlanRepository.d.ts.map +1 -0
- package/dist/infrastructure/{fs → batch}/FsBatchPlanRepository.js +9 -7
- package/dist/infrastructure/batch/FsBatchPlanRepository.js.map +1 -0
- package/dist/infrastructure/history/GitWorkspaceHistory.d.ts.map +1 -0
- package/dist/infrastructure/{git → history}/GitWorkspaceHistory.js +31 -24
- package/dist/infrastructure/history/GitWorkspaceHistory.js.map +1 -0
- package/dist/infrastructure/history/commitMessage.d.ts.map +1 -0
- package/dist/infrastructure/history/commitMessage.js +90 -0
- package/dist/infrastructure/history/commitMessage.js.map +1 -0
- package/dist/infrastructure/hitl/FsClarificationRepository.d.ts +13 -0
- package/dist/infrastructure/hitl/FsClarificationRepository.d.ts.map +1 -0
- package/dist/infrastructure/hitl/FsClarificationRepository.js +40 -0
- package/dist/infrastructure/hitl/FsClarificationRepository.js.map +1 -0
- package/dist/infrastructure/hitl/FsProposalRepository.d.ts.map +1 -0
- package/dist/infrastructure/{fs → hitl}/FsProposalRepository.js +8 -8
- package/dist/infrastructure/hitl/FsProposalRepository.js.map +1 -0
- package/dist/infrastructure/hitl/StatusedJsonStore.d.ts +30 -0
- package/dist/infrastructure/hitl/StatusedJsonStore.d.ts.map +1 -0
- package/dist/infrastructure/{fs/FsStatusedJsonRepository.js → hitl/StatusedJsonStore.js} +3 -3
- package/dist/infrastructure/hitl/StatusedJsonStore.js.map +1 -0
- package/dist/infrastructure/model/FsModelSerializer.d.ts +94 -0
- package/dist/infrastructure/model/FsModelSerializer.d.ts.map +1 -0
- package/dist/infrastructure/{fs/FsGraphSerializer.js → model/FsModelSerializer.js} +11 -11
- package/dist/infrastructure/model/FsModelSerializer.js.map +1 -0
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts +20 -38
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts.map +1 -1
- package/dist/infrastructure/oauth/GoogleOAuth.js +21 -22
- package/dist/infrastructure/oauth/GoogleOAuth.js.map +1 -1
- package/dist/infrastructure/reactor/FsReactorCycleRepository.d.ts +29 -0
- package/dist/infrastructure/reactor/FsReactorCycleRepository.d.ts.map +1 -0
- package/dist/infrastructure/reactor/FsReactorCycleRepository.js +94 -0
- package/dist/infrastructure/reactor/FsReactorCycleRepository.js.map +1 -0
- package/dist/infrastructure/secrets/SecretStore.d.ts +11 -14
- package/dist/infrastructure/secrets/SecretStore.d.ts.map +1 -1
- package/dist/infrastructure/secrets/SecretStore.js +4 -4
- package/dist/infrastructure/secrets/SecretStore.js.map +1 -1
- package/dist/infrastructure/{fs → skill}/FsRunRepository.d.ts +5 -3
- package/dist/infrastructure/skill/FsRunRepository.d.ts.map +1 -0
- package/dist/infrastructure/{fs → skill}/FsRunRepository.js +11 -9
- package/dist/infrastructure/skill/FsRunRepository.js.map +1 -0
- package/dist/infrastructure/{fs → skill}/FsSkillRegistry.d.ts +4 -13
- package/dist/infrastructure/skill/FsSkillRegistry.d.ts.map +1 -0
- package/dist/infrastructure/{fs → skill}/FsSkillRegistry.js +28 -20
- package/dist/infrastructure/skill/FsSkillRegistry.js.map +1 -0
- package/dist/infrastructure/skill/SubprocessSkillRunner.d.ts +52 -0
- package/dist/infrastructure/skill/SubprocessSkillRunner.d.ts.map +1 -0
- package/dist/infrastructure/{agent → skill}/SubprocessSkillRunner.js +107 -55
- package/dist/infrastructure/skill/SubprocessSkillRunner.js.map +1 -0
- package/dist/infrastructure/skill/asyncQueue.d.ts +20 -0
- package/dist/infrastructure/skill/asyncQueue.d.ts.map +1 -0
- package/dist/infrastructure/{agent → skill}/asyncQueue.js +2 -3
- package/dist/infrastructure/{agent → skill}/asyncQueue.js.map +1 -1
- package/dist/infrastructure/skill/lineBuffer.d.ts +15 -0
- package/dist/infrastructure/skill/lineBuffer.d.ts.map +1 -0
- package/dist/infrastructure/{agent/streamJsonParser.js → skill/lineBuffer.js} +5 -17
- package/dist/infrastructure/skill/lineBuffer.js.map +1 -0
- package/dist/infrastructure/skill/orphanReaper.d.ts +20 -0
- package/dist/infrastructure/skill/orphanReaper.d.ts.map +1 -0
- package/dist/infrastructure/{orphanReaper.js → skill/orphanReaper.js} +7 -5
- package/dist/infrastructure/skill/orphanReaper.js.map +1 -0
- package/dist/infrastructure/skill/subprocessEventStream.d.ts +16 -0
- package/dist/infrastructure/skill/subprocessEventStream.d.ts.map +1 -0
- package/dist/infrastructure/skill/subprocessEventStream.js +29 -0
- package/dist/infrastructure/skill/subprocessEventStream.js.map +1 -0
- package/dist/infrastructure/source/FsSourceUnitDigest.d.ts +19 -0
- package/dist/infrastructure/source/FsSourceUnitDigest.d.ts.map +1 -0
- package/dist/infrastructure/{fs → source}/FsSourceUnitDigest.js +9 -9
- package/dist/infrastructure/source/FsSourceUnitDigest.js.map +1 -0
- package/dist/infrastructure/source/FsSourceUnitObservationRepository.d.ts +31 -0
- package/dist/infrastructure/source/FsSourceUnitObservationRepository.d.ts.map +1 -0
- package/dist/infrastructure/{fs/FsSourceUnitStateRepository.js → source/FsSourceUnitObservationRepository.js} +18 -17
- package/dist/infrastructure/source/FsSourceUnitObservationRepository.js.map +1 -0
- package/dist/infrastructure/source/unitScan.d.ts +11 -0
- package/dist/infrastructure/source/unitScan.d.ts.map +1 -0
- package/dist/infrastructure/{fs/intentScan.js → source/unitScan.js} +36 -27
- package/dist/infrastructure/source/unitScan.js.map +1 -0
- package/dist/infrastructure/users/UserDirectoryFromRegistry.d.ts +2 -2
- package/dist/infrastructure/users/UserDirectoryFromRegistry.d.ts.map +1 -1
- package/dist/infrastructure/users/UserDirectoryFromRegistry.js +3 -2
- package/dist/infrastructure/users/UserDirectoryFromRegistry.js.map +1 -1
- package/dist/infrastructure/users/UserRegistryFile.d.ts +4 -5
- package/dist/infrastructure/users/UserRegistryFile.d.ts.map +1 -1
- package/dist/infrastructure/users/UserRegistryFile.js +6 -8
- package/dist/infrastructure/users/UserRegistryFile.js.map +1 -1
- package/dist/infrastructure/users/ensureWorkspaceOwners.d.ts +9 -6
- package/dist/infrastructure/users/ensureWorkspaceOwners.d.ts.map +1 -1
- package/dist/infrastructure/users/ensureWorkspaceOwners.js +10 -7
- package/dist/infrastructure/users/ensureWorkspaceOwners.js.map +1 -1
- package/dist/infrastructure/workspace/FsWorkspaceRepository.d.ts.map +1 -0
- package/dist/infrastructure/{fs → workspace}/FsWorkspaceRepository.js +7 -6
- package/dist/infrastructure/workspace/FsWorkspaceRepository.js.map +1 -0
- package/dist/infrastructure/workspace/WorkspaceDiscovery.d.ts +18 -0
- package/dist/infrastructure/workspace/WorkspaceDiscovery.d.ts.map +1 -0
- package/dist/infrastructure/{fs → workspace}/WorkspaceDiscovery.js +15 -11
- package/dist/infrastructure/workspace/WorkspaceDiscovery.js.map +1 -0
- package/dist/infrastructure/{fs → workspace}/WorkspaceRegistryFile.d.ts +10 -9
- package/dist/infrastructure/workspace/WorkspaceRegistryFile.d.ts.map +1 -0
- package/dist/infrastructure/{fs → workspace}/WorkspaceRegistryFile.js +15 -17
- package/dist/infrastructure/workspace/WorkspaceRegistryFile.js.map +1 -0
- package/dist/infrastructure/workspace/productManifestWriter.d.ts +24 -0
- package/dist/infrastructure/workspace/productManifestWriter.d.ts.map +1 -0
- package/dist/infrastructure/{fs → workspace}/productManifestWriter.js +14 -26
- package/dist/infrastructure/workspace/productManifestWriter.js.map +1 -0
- package/dist/middleware/auth.d.ts +27 -17
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +69 -53
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/cors.js +4 -1
- package/dist/middleware/cors.js.map +1 -1
- package/dist/middleware/error.d.ts.map +1 -1
- package/dist/middleware/error.js +15 -13
- package/dist/middleware/error.js.map +1 -1
- package/dist/middleware/workspaceAccess.d.ts +23 -19
- package/dist/middleware/workspaceAccess.d.ts.map +1 -1
- package/dist/middleware/workspaceAccess.js +31 -26
- package/dist/middleware/workspaceAccess.js.map +1 -1
- package/dist/policy/CapabilityCheck.d.ts +5 -5
- package/dist/policy/PermissionRegistry.d.ts +11 -9
- package/dist/policy/PermissionRegistry.d.ts.map +1 -1
- package/dist/policy/PermissionRegistry.js +10 -8
- package/dist/policy/PermissionRegistry.js.map +1 -1
- package/dist/policy/ViewerContext.d.ts +13 -11
- package/dist/policy/ViewerContext.d.ts.map +1 -1
- package/dist/policy/checks.d.ts +9 -9
- package/dist/policy/checks.d.ts.map +1 -1
- package/dist/policy/checks.js +14 -11
- package/dist/policy/checks.js.map +1 -1
- package/dist/policy/defaultRegistry.d.ts +3 -4
- package/dist/policy/defaultRegistry.d.ts.map +1 -1
- package/dist/policy/defaultRegistry.js +3 -4
- package/dist/policy/defaultRegistry.js.map +1 -1
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.d.ts.map +1 -1
- package/dist/policy/index.js +1 -1
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/resolveViewer.d.ts +9 -9
- package/dist/policy/resolveViewer.js +9 -9
- package/dist/routes/_shared.d.ts +93 -153
- package/dist/routes/_shared.d.ts.map +1 -1
- package/dist/routes/_shared.js +9 -5
- package/dist/routes/_shared.js.map +1 -1
- package/dist/routes/admin.d.ts +1 -1
- package/dist/routes/admin.d.ts.map +1 -1
- package/dist/routes/admin.js +13 -12
- package/dist/routes/admin.js.map +1 -1
- package/dist/routes/auth.d.ts +12 -10
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +32 -34
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/clarifications.d.ts +8 -0
- package/dist/routes/clarifications.d.ts.map +1 -0
- package/dist/routes/clarifications.js +246 -0
- package/dist/routes/clarifications.js.map +1 -0
- package/dist/routes/edges.d.ts.map +1 -1
- package/dist/routes/edges.js +2 -6
- package/dist/routes/edges.js.map +1 -1
- package/dist/routes/history.d.ts.map +1 -1
- package/dist/routes/history.js +12 -10
- package/dist/routes/history.js.map +1 -1
- package/dist/routes/nodes.d.ts.map +1 -1
- package/dist/routes/nodes.js +4 -8
- package/dist/routes/nodes.js.map +1 -1
- package/dist/routes/oauth.d.ts +6 -7
- package/dist/routes/oauth.d.ts.map +1 -1
- package/dist/routes/oauth.js +6 -7
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/ontologies.d.ts +7 -0
- package/dist/routes/ontologies.d.ts.map +1 -0
- package/dist/routes/ontologies.js +29 -0
- package/dist/routes/ontologies.js.map +1 -0
- package/dist/routes/ontology.d.ts.map +1 -1
- package/dist/routes/ontology.js +2 -1
- package/dist/routes/ontology.js.map +1 -1
- package/dist/routes/proposals.d.ts +2 -2
- package/dist/routes/proposals.d.ts.map +1 -1
- package/dist/routes/proposals.js +35 -30
- package/dist/routes/proposals.js.map +1 -1
- package/dist/routes/reactorCycles.d.ts +7 -0
- package/dist/routes/reactorCycles.d.ts.map +1 -0
- package/dist/routes/reactorCycles.js +60 -0
- package/dist/routes/reactorCycles.js.map +1 -0
- package/dist/routes/runs.d.ts.map +1 -1
- package/dist/routes/runs.js +22 -19
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/skillInputOptions.d.ts +2 -2
- package/dist/routes/skillInputOptions.d.ts.map +1 -1
- package/dist/routes/skillInputOptions.js +53 -53
- package/dist/routes/skillInputOptions.js.map +1 -1
- package/dist/routes/skills.d.ts +19 -1
- package/dist/routes/skills.d.ts.map +1 -1
- package/dist/routes/skills.js +141 -7
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/sourceLoaders.d.ts.map +1 -1
- package/dist/routes/sourceLoaders.js +1 -0
- package/dist/routes/sourceLoaders.js.map +1 -1
- package/dist/routes/sourceUnitObservations.d.ts +20 -0
- package/dist/routes/sourceUnitObservations.d.ts.map +1 -0
- package/dist/routes/sourceUnitObservations.js +80 -0
- package/dist/routes/sourceUnitObservations.js.map +1 -0
- package/dist/routes/sourceWebhooks.d.ts +26 -0
- package/dist/routes/sourceWebhooks.d.ts.map +1 -0
- package/dist/routes/sourceWebhooks.js +301 -0
- package/dist/routes/sourceWebhooks.js.map +1 -0
- package/dist/routes/users.d.ts +0 -2
- package/dist/routes/users.d.ts.map +1 -1
- package/dist/routes/users.js +15 -33
- package/dist/routes/users.js.map +1 -1
- package/dist/routes/workspaceEvents.d.ts +5 -4
- package/dist/routes/workspaceEvents.d.ts.map +1 -1
- package/dist/routes/workspaceEvents.js +7 -6
- package/dist/routes/workspaceEvents.js.map +1 -1
- package/dist/routes/workspaceMembers.d.ts +1 -1
- package/dist/routes/workspaceMembers.d.ts.map +1 -1
- package/dist/routes/workspaceMembers.js +2 -2
- package/dist/routes/workspaceMembers.js.map +1 -1
- package/dist/routes/workspaces.d.ts +21 -10
- package/dist/routes/workspaces.d.ts.map +1 -1
- package/dist/routes/workspaces.js +95 -69
- package/dist/routes/workspaces.js.map +1 -1
- package/dist/server.js +6 -70
- package/dist/server.js.map +1 -1
- package/dist/serviceAccounts.d.ts +13 -0
- package/dist/serviceAccounts.d.ts.map +1 -0
- package/dist/serviceAccounts.js +26 -0
- package/dist/serviceAccounts.js.map +1 -0
- package/dist/startServer.d.ts +17 -0
- package/dist/startServer.d.ts.map +1 -0
- package/dist/startServer.js +81 -0
- package/dist/startServer.js.map +1 -0
- package/dist/startup.d.ts +28 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +94 -0
- package/dist/startup.js.map +1 -0
- package/package.json +35 -40
- package/dist/composeFs.d.ts +0 -55
- package/dist/composeFs.d.ts.map +0 -1
- package/dist/composeFs.js.map +0 -1
- package/dist/composition.d.ts +0 -133
- package/dist/composition.d.ts.map +0 -1
- package/dist/composition.js +0 -113
- package/dist/composition.js.map +0 -1
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts +0 -75
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts.map +0 -1
- package/dist/infrastructure/agent/SubprocessSkillRunner.js.map +0 -1
- package/dist/infrastructure/agent/asyncQueue.d.ts +0 -22
- package/dist/infrastructure/agent/asyncQueue.d.ts.map +0 -1
- package/dist/infrastructure/agent/mcpConfig.d.ts +0 -38
- package/dist/infrastructure/agent/mcpConfig.d.ts.map +0 -1
- package/dist/infrastructure/agent/mcpConfig.js +0 -55
- package/dist/infrastructure/agent/mcpConfig.js.map +0 -1
- package/dist/infrastructure/agent/streamJsonParser.d.ts +0 -20
- package/dist/infrastructure/agent/streamJsonParser.d.ts.map +0 -1
- package/dist/infrastructure/agent/streamJsonParser.js.map +0 -1
- package/dist/infrastructure/agent/subprocessEventStream.d.ts +0 -26
- package/dist/infrastructure/agent/subprocessEventStream.d.ts.map +0 -1
- package/dist/infrastructure/agent/subprocessEventStream.js +0 -112
- package/dist/infrastructure/agent/subprocessEventStream.js.map +0 -1
- package/dist/infrastructure/auth/ensureApprovedEmails.d.ts +0 -16
- package/dist/infrastructure/auth/ensureApprovedEmails.d.ts.map +0 -1
- package/dist/infrastructure/auth/ensureApprovedEmails.js +0 -20
- package/dist/infrastructure/auth/ensureApprovedEmails.js.map +0 -1
- package/dist/infrastructure/env.d.ts +0 -11
- package/dist/infrastructure/env.d.ts.map +0 -1
- package/dist/infrastructure/env.js.map +0 -1
- package/dist/infrastructure/fs/FsBatchPlanRepository.d.ts +0 -300
- package/dist/infrastructure/fs/FsBatchPlanRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsBatchPlanRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts +0 -13
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js +0 -39
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts +0 -13
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsDecisionRepository.js +0 -56
- package/dist/infrastructure/fs/FsDecisionRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsGraphSerializer.d.ts +0 -629
- package/dist/infrastructure/fs/FsGraphSerializer.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsGraphSerializer.js.map +0 -1
- package/dist/infrastructure/fs/FsProposalRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsProposalRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsRunRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsRunRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsSkillRegistry.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsSkillRegistry.js.map +0 -1
- package/dist/infrastructure/fs/FsSourceUnitDigest.d.ts +0 -19
- package/dist/infrastructure/fs/FsSourceUnitDigest.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsSourceUnitDigest.js.map +0 -1
- package/dist/infrastructure/fs/FsSourceUnitStateRepository.d.ts +0 -30
- package/dist/infrastructure/fs/FsSourceUnitStateRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsSourceUnitStateRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts +0 -35
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsStatusedJsonRepository.js.map +0 -1
- package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts.map +0 -1
- package/dist/infrastructure/fs/FsWorkspaceRepository.js.map +0 -1
- package/dist/infrastructure/fs/WorkspaceDiscovery.d.ts +0 -15
- package/dist/infrastructure/fs/WorkspaceDiscovery.d.ts.map +0 -1
- package/dist/infrastructure/fs/WorkspaceDiscovery.js.map +0 -1
- package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts.map +0 -1
- package/dist/infrastructure/fs/WorkspaceRegistryFile.js.map +0 -1
- package/dist/infrastructure/fs/frontmatter.d.ts +0 -13
- package/dist/infrastructure/fs/frontmatter.d.ts.map +0 -1
- package/dist/infrastructure/fs/frontmatter.js.map +0 -1
- package/dist/infrastructure/fs/intentScan.d.ts +0 -9
- package/dist/infrastructure/fs/intentScan.d.ts.map +0 -1
- package/dist/infrastructure/fs/intentScan.js.map +0 -1
- package/dist/infrastructure/fs/jsonFileStore.d.ts.map +0 -1
- package/dist/infrastructure/fs/jsonFileStore.js.map +0 -1
- package/dist/infrastructure/fs/paths.d.ts.map +0 -1
- package/dist/infrastructure/fs/paths.js.map +0 -1
- package/dist/infrastructure/fs/productManifestWriter.d.ts +0 -22
- package/dist/infrastructure/fs/productManifestWriter.d.ts.map +0 -1
- package/dist/infrastructure/fs/productManifestWriter.js.map +0 -1
- package/dist/infrastructure/git/GitWorkspaceHistory.d.ts.map +0 -1
- package/dist/infrastructure/git/GitWorkspaceHistory.js.map +0 -1
- package/dist/infrastructure/git/commitMessage.d.ts.map +0 -1
- package/dist/infrastructure/git/commitMessage.js +0 -71
- package/dist/infrastructure/git/commitMessage.js.map +0 -1
- package/dist/infrastructure/orphanReaper.d.ts +0 -18
- package/dist/infrastructure/orphanReaper.d.ts.map +0 -1
- package/dist/infrastructure/orphanReaper.js.map +0 -1
- package/dist/infrastructure/users/ensureLocalUser.d.ts +0 -15
- package/dist/infrastructure/users/ensureLocalUser.d.ts.map +0 -1
- package/dist/infrastructure/users/ensureLocalUser.js +0 -38
- package/dist/infrastructure/users/ensureLocalUser.js.map +0 -1
- package/dist/middleware/requireAdmin.d.ts +0 -10
- package/dist/middleware/requireAdmin.d.ts.map +0 -1
- package/dist/middleware/requireAdmin.js +0 -24
- package/dist/middleware/requireAdmin.js.map +0 -1
- package/dist/middleware/userId.d.ts +0 -16
- package/dist/middleware/userId.d.ts.map +0 -1
- package/dist/middleware/userId.js +0 -27
- package/dist/middleware/userId.js.map +0 -1
- package/dist/policy/Capability.d.ts +0 -12
- package/dist/policy/Capability.d.ts.map +0 -1
- package/dist/policy/Capability.js +0 -31
- package/dist/policy/Capability.js.map +0 -1
- package/dist/routes/clarify.d.ts +0 -9
- package/dist/routes/clarify.d.ts.map +0 -1
- package/dist/routes/clarify.js +0 -274
- package/dist/routes/clarify.js.map +0 -1
- package/dist/routes/decisions.d.ts +0 -7
- package/dist/routes/decisions.d.ts.map +0 -1
- package/dist/routes/decisions.js +0 -68
- package/dist/routes/decisions.js.map +0 -1
- package/dist/routes/sourceUnitStates.d.ts +0 -7
- package/dist/routes/sourceUnitStates.d.ts.map +0 -1
- package/dist/routes/sourceUnitStates.js +0 -45
- package/dist/routes/sourceUnitStates.js.map +0 -1
- /package/dist/infrastructure/{fs → _shared}/jsonFileStore.d.ts +0 -0
- /package/dist/infrastructure/{fs → _shared}/jsonFileStore.js +0 -0
- /package/dist/infrastructure/{git → history}/GitWorkspaceHistory.d.ts +0 -0
- /package/dist/infrastructure/{git → history}/commitMessage.d.ts +0 -0
- /package/dist/infrastructure/{fs → hitl}/FsProposalRepository.d.ts +0 -0
- /package/dist/infrastructure/{fs → workspace}/FsWorkspaceRepository.d.ts +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { computeSourceDiff } from '@braidhq/core';
|
|
2
|
+
import { SourceId, SourceUnitDiff, SourceUnitObservation } from '@braidhq/schema';
|
|
3
|
+
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
|
|
4
|
+
import { getWorkspaceId } from '../middleware/workspaceId.js';
|
|
5
|
+
import { NotFoundResponse, ValidationFailureResponse, WorkspaceIdParam } from './_shared.js';
|
|
6
|
+
const ListQuery = z.object({
|
|
7
|
+
sourceId: SourceId.optional().openapi({ description: 'Restrict to one source.' }),
|
|
8
|
+
});
|
|
9
|
+
const ListResponse = z.object({
|
|
10
|
+
items: z.array(SourceUnitObservation),
|
|
11
|
+
}).openapi('SourceUnitObservationListResponse');
|
|
12
|
+
const SourceIdParam = WorkspaceIdParam.extend({
|
|
13
|
+
sourceId: SourceId.openapi({ param: { name: 'sourceId', in: 'path' } }),
|
|
14
|
+
});
|
|
15
|
+
const DiffResponse = SourceUnitDiff.openapi('SourceUnitDiffResponse');
|
|
16
|
+
const listRoute = createRoute({
|
|
17
|
+
method: 'get',
|
|
18
|
+
path: '/',
|
|
19
|
+
operationId: 'listSourceUnitObservations',
|
|
20
|
+
summary: 'List recorded observations per source unit for a workspace.',
|
|
21
|
+
description: 'Returns the framework\'s current view of each source unit '
|
|
22
|
+
+ 'last seen by an extract run. One entry per (sourceId, path). Used '
|
|
23
|
+
+ 'by Studio to display per-unit freshness and by Reactor to compute '
|
|
24
|
+
+ 'what needs re-extraction.',
|
|
25
|
+
tags: ['source-unit-states'],
|
|
26
|
+
request: {
|
|
27
|
+
params: WorkspaceIdParam,
|
|
28
|
+
query: ListQuery,
|
|
29
|
+
},
|
|
30
|
+
responses: {
|
|
31
|
+
200: {
|
|
32
|
+
description: 'The recorded observations.',
|
|
33
|
+
content: { 'application/json': { schema: ListResponse } },
|
|
34
|
+
},
|
|
35
|
+
400: ValidationFailureResponse,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
const diffRoute = createRoute({
|
|
39
|
+
method: 'get',
|
|
40
|
+
path: '/{sourceId}/diff',
|
|
41
|
+
operationId: 'getSourceUnitDiff',
|
|
42
|
+
summary: 'Diff a source\'s current units on disk against the recorded ledger.',
|
|
43
|
+
description: 'Returns the partition (`new`, `changed`, `unchanged`, `orphaned`) the Reactor uses internally to decide what to re-extract. Studio\'s Actions form consumes the same shape to render per-option badges on the source picker.',
|
|
44
|
+
tags: ['source-unit-states'],
|
|
45
|
+
request: { params: SourceIdParam },
|
|
46
|
+
responses: {
|
|
47
|
+
200: {
|
|
48
|
+
description: 'The diff partition.',
|
|
49
|
+
content: { 'application/json': { schema: DiffResponse } },
|
|
50
|
+
},
|
|
51
|
+
404: NotFoundResponse,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
export function createSourceUnitObservationsRouter(deps) {
|
|
55
|
+
const router = new OpenAPIHono();
|
|
56
|
+
router.openapi(listRoute, async (context) => {
|
|
57
|
+
const workspaceId = getWorkspaceId(context);
|
|
58
|
+
const { sourceId } = context.req.valid('query');
|
|
59
|
+
const items = sourceId
|
|
60
|
+
? await deps.sourceUnitObservationService.listBySource(workspaceId, sourceId)
|
|
61
|
+
: await deps.sourceUnitObservationService.listByWorkspace(workspaceId);
|
|
62
|
+
return context.json({ items: [...items] }, 200);
|
|
63
|
+
});
|
|
64
|
+
if (deps.diffSupport) {
|
|
65
|
+
const { workspaceService, unitLister, digest } = deps.diffSupport;
|
|
66
|
+
router.openapi(diffRoute, async (context) => {
|
|
67
|
+
const workspaceId = getWorkspaceId(context);
|
|
68
|
+
const { sourceId } = context.req.valid('param');
|
|
69
|
+
const workspace = await workspaceService.findById(workspaceId);
|
|
70
|
+
const diff = await computeSourceDiff({
|
|
71
|
+
unitLister,
|
|
72
|
+
digest,
|
|
73
|
+
sourceUnitObservationService: deps.sourceUnitObservationService,
|
|
74
|
+
}, workspace, sourceId);
|
|
75
|
+
return context.json(diff, 200);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return router;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=sourceUnitObservations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceUnitObservations.js","sourceRoot":"","sources":["../../src/routes/sourceUnitObservations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PluginRegistry, SourceLoaderRunner, WorkspaceService } from '@braidhq/core';
|
|
2
|
+
import type { SecretStore } from '../infrastructure/secrets/SecretStore.js';
|
|
3
|
+
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
4
|
+
import { Hono } from 'hono';
|
|
5
|
+
export interface GithubWebhookReceiverDeps {
|
|
6
|
+
readonly workspaceService: WorkspaceService;
|
|
7
|
+
readonly sourceLoaderRunner: SourceLoaderRunner;
|
|
8
|
+
readonly secretStore: SecretStore;
|
|
9
|
+
readonly pluginRegistry: PluginRegistry;
|
|
10
|
+
}
|
|
11
|
+
export declare function createGithubWebhookReceiver(deps: GithubWebhookReceiverDeps): Hono;
|
|
12
|
+
export interface SourceWebhooksAdminDeps {
|
|
13
|
+
readonly workspaceService: WorkspaceService;
|
|
14
|
+
readonly secretStore: SecretStore;
|
|
15
|
+
readonly pluginRegistry: PluginRegistry;
|
|
16
|
+
/**
|
|
17
|
+
* Base URL under which the public webhook receiver is reachable.
|
|
18
|
+
* Required so the admin response can return an absolute URL,
|
|
19
|
+
* that the user pastes straight into GitHub's webhook settings.
|
|
20
|
+
* When unset (composeApp in tests), the admin endpoints return 503.
|
|
21
|
+
* Better than returning a relative path Studio would render verbatim.
|
|
22
|
+
*/
|
|
23
|
+
readonly apiUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function createSourceWebhooksAdminRouter(deps: SourceWebhooksAdminDeps): OpenAPIHono;
|
|
26
|
+
//# sourceMappingURL=sourceWebhooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceWebhooks.d.ts","sourceRoot":"","sources":["../../src/routes/sourceWebhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAElB,gBAAgB,EACjB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAA;AAK3E,OAAO,EAAe,WAAW,EAAK,MAAM,mBAAmB,CAAA;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA0C3B,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAA;IAC3C,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;CACxC;AA6FD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,yBAAyB,GAAG,IAAI,CAgFjF;AAYD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAA;IAC3C,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AA2DD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,uBAAuB,GAAG,WAAW,CAoC1F"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
3
|
+
import { createLogger, NotFoundError, ServiceUnavailableError, UnauthorizedError, ValidationError } from '@braidhq/core';
|
|
4
|
+
import { SourceId, WorkspaceId } from '@braidhq/schema';
|
|
5
|
+
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
|
|
6
|
+
import { Hono } from 'hono';
|
|
7
|
+
import { WorkspaceIdParam } from './_shared.js';
|
|
8
|
+
/**
|
|
9
|
+
* GitHub webhook plumbing for filesystem sources,
|
|
10
|
+
* whose loader plugin declares a `webhook` capability.
|
|
11
|
+
*
|
|
12
|
+
* Two routers.
|
|
13
|
+
*
|
|
14
|
+
* `createGithubWebhookReceiver` is public (no Bearer auth).
|
|
15
|
+
* GitHub POSTs deliveries here.
|
|
16
|
+
* We verify the HMAC, confirm the payload names the claimed repo,
|
|
17
|
+
* ask the plugin whether the event is worth a `syncOne`,
|
|
18
|
+
* and dispatch in the background. The response returns immediately,
|
|
19
|
+
* so GitHub's ~10s delivery timeout never trips on a slow loader.
|
|
20
|
+
*
|
|
21
|
+
* `createSourceWebhooksAdminRouter` is workspace-scoped,
|
|
22
|
+
* and gated by the existing auth middleware.
|
|
23
|
+
* Studio uses it to display the webhook URL and rotate the secret.
|
|
24
|
+
*
|
|
25
|
+
* The receiver is loader-agnostic and does not switch on `loader.kind`.
|
|
26
|
+
* A new loader extends the webhook surface from its plugin definition,
|
|
27
|
+
* via `webhook: { repoIdentity, shouldDispatch }`.
|
|
28
|
+
*
|
|
29
|
+
* Secrets live in the existing `SecretStore`,
|
|
30
|
+
* under namespace `webhook-github`, keyed by `<workspaceId>--<sourceId>`.
|
|
31
|
+
* That mirrors the OAuth namespaces (oauth-google, oauth-github),
|
|
32
|
+
* which already use the same `--` separator.
|
|
33
|
+
*/
|
|
34
|
+
const SECRET_NAMESPACE = 'webhook-github';
|
|
35
|
+
const PROVIDER = 'github';
|
|
36
|
+
function secretKey(workspaceId, sourceId) {
|
|
37
|
+
return `${workspaceId}--${sourceId}`;
|
|
38
|
+
}
|
|
39
|
+
const receiverLogger = createLogger('webhooks.github.receiver');
|
|
40
|
+
// Verify GitHub's `X-Hub-Signature-256` header.
|
|
41
|
+
// GitHub computes `sha256=<hex>` over the raw body with the secret.
|
|
42
|
+
// We recompute and compare in constant time.
|
|
43
|
+
// The prefix check is case-insensitive,
|
|
44
|
+
// because some proxies and WAFs normalise headers.
|
|
45
|
+
function verifySignature(rawBody, header, secret) {
|
|
46
|
+
if (!header || !header.toLowerCase().startsWith('sha256='))
|
|
47
|
+
return false;
|
|
48
|
+
// Normalise the hex digest to lowercase,
|
|
49
|
+
// so the timing-safe compare still accepts an uppercased hex,
|
|
50
|
+
// (rare but valid).
|
|
51
|
+
const provided = `sha256=${header.slice('sha256='.length).toLowerCase()}`;
|
|
52
|
+
const expected = `sha256=${createHmac('sha256', secret).update(rawBody).digest('hex')}`;
|
|
53
|
+
const a = Buffer.from(expected);
|
|
54
|
+
const b = Buffer.from(provided);
|
|
55
|
+
if (a.length !== b.length)
|
|
56
|
+
return false;
|
|
57
|
+
return timingSafeEqual(a, b);
|
|
58
|
+
}
|
|
59
|
+
// Look up the loader plugin's `webhook` capability for a source.
|
|
60
|
+
// Returns undefined when the source is not webhook-capable, never throws.
|
|
61
|
+
function resolveWebhookCapability(pluginRegistry, source) {
|
|
62
|
+
if (source.kind !== 'filesystem' || !source.loader)
|
|
63
|
+
return undefined;
|
|
64
|
+
const plugin = pluginRegistry.findSourceLoader(source.loader.kind);
|
|
65
|
+
if (!plugin?.webhook)
|
|
66
|
+
return undefined;
|
|
67
|
+
return { capability: plugin.webhook, config: source.loader.config };
|
|
68
|
+
}
|
|
69
|
+
// Uniform anonymous response for any pre-signature failure,
|
|
70
|
+
// (missing workspace, source, webhook capability, secret, or HMAC).
|
|
71
|
+
// Distinct error bodies would leak which pairs exist,
|
|
72
|
+
// and which are webhook-armed, to an unauthenticated caller.
|
|
73
|
+
// That recon ladder we deliberately close off.
|
|
74
|
+
function unauthorized() {
|
|
75
|
+
throw new UnauthorizedError('Invalid webhook signature.');
|
|
76
|
+
}
|
|
77
|
+
// Run the full pre-signature pipeline inside a single try/catch,
|
|
78
|
+
// (header presence, body read, workspace and source lookup,
|
|
79
|
+
// plugin webhook capability, repo identity, secret read, HMAC verify).
|
|
80
|
+
// Returns the trusted state on success and `undefined` on any failure.
|
|
81
|
+
// The caller collapses every failure mode to a 401.
|
|
82
|
+
async function verifyDelivery(deps, context, workspaceId, sourceId) {
|
|
83
|
+
try {
|
|
84
|
+
const signature = context.req.header('X-Hub-Signature-256');
|
|
85
|
+
if (!signature)
|
|
86
|
+
return undefined;
|
|
87
|
+
const rawBody = await context.req.text();
|
|
88
|
+
const workspace = await deps.workspaceService.findById(workspaceId);
|
|
89
|
+
const source = workspace.sources.find(s => s.id === sourceId);
|
|
90
|
+
if (!source)
|
|
91
|
+
return undefined;
|
|
92
|
+
const resolved = resolveWebhookCapability(deps.pluginRegistry, source);
|
|
93
|
+
if (!resolved)
|
|
94
|
+
return undefined;
|
|
95
|
+
const identity = resolved.capability.repoIdentity(resolved.config);
|
|
96
|
+
if (!identity || identity.provider !== PROVIDER)
|
|
97
|
+
return undefined;
|
|
98
|
+
const record = await deps.secretStore.read(SECRET_NAMESPACE, secretKey(workspaceId, sourceId));
|
|
99
|
+
if (!record)
|
|
100
|
+
return undefined;
|
|
101
|
+
if (!verifySignature(rawBody, signature, record.secret))
|
|
102
|
+
return undefined;
|
|
103
|
+
return { workspace, resolved, identity, rawBody };
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
receiverLogger.warn({ workspaceId, sourceId, err: err instanceof Error ? err.message : String(err) }, 'webhook: pre-signature check failed');
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function createGithubWebhookReceiver(deps) {
|
|
111
|
+
const router = new Hono();
|
|
112
|
+
// `:workspaceId/:sourceId` is the routing identity,
|
|
113
|
+
// the user installs on the GitHub side.
|
|
114
|
+
// We accept the request, verify, and return 202 immediately.
|
|
115
|
+
// Sync runs in the background,
|
|
116
|
+
// so a slow loader never blocks GitHub's delivery worker.
|
|
117
|
+
// GitHub times deliveries out at ~10s.
|
|
118
|
+
router.post('/github/:workspaceId/:sourceId', async (context) => {
|
|
119
|
+
const workspaceId = WorkspaceId.parse(context.req.param('workspaceId'));
|
|
120
|
+
const sourceId = SourceId.parse(context.req.param('sourceId'));
|
|
121
|
+
// The verifyDelivery call returns either the trusted state or undefined,
|
|
122
|
+
// (workspace, resolved capability, repository identity, raw body).
|
|
123
|
+
// On undefined we always return a uniform 401,
|
|
124
|
+
// so distinct errors never tell an anonymous caller apart,
|
|
125
|
+
// "no such workspace", "no secret yet", and "bad signature".
|
|
126
|
+
const verified = await verifyDelivery(deps, context, workspaceId, sourceId);
|
|
127
|
+
if (!verified)
|
|
128
|
+
return unauthorized();
|
|
129
|
+
const { workspace, resolved, identity, rawBody } = verified;
|
|
130
|
+
// Parse the body only after the signature check,
|
|
131
|
+
// so an attacker who can't forge the HMAC, never reaches our JSON parser.
|
|
132
|
+
let payload;
|
|
133
|
+
try {
|
|
134
|
+
payload = JSON.parse(rawBody);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
throw new ValidationError('Invalid JSON payload.');
|
|
138
|
+
}
|
|
139
|
+
const fullName = extractFullName(payload);
|
|
140
|
+
const expectedFullName = `${identity.owner}/${identity.repo}`.toLowerCase();
|
|
141
|
+
// GitHub repo names are case-insensitive,
|
|
142
|
+
// (a stored `Owner/Repo` may arrive as `owner/repo`, or vice versa).
|
|
143
|
+
// Compare normalised. Also REQUIRE full_name to be present.
|
|
144
|
+
// A verified delivery without one is rejected,
|
|
145
|
+
// since this receiver is per-source,
|
|
146
|
+
// (some org-level or installation events omit it).
|
|
147
|
+
if (typeof fullName !== 'string' || fullName.toLowerCase() !== expectedFullName)
|
|
148
|
+
throw new ValidationError(`Payload repository "${fullName ?? '(missing)'}" does not match configured "${expectedFullName}".`);
|
|
149
|
+
// X-GitHub-Event must be present on real deliveries.
|
|
150
|
+
// Treating an absent header as "unknown",
|
|
151
|
+
// would let a stripping proxy silently drop every event,
|
|
152
|
+
// since loaders default to skipping unknown events.
|
|
153
|
+
const event = context.req.header('X-GitHub-Event');
|
|
154
|
+
if (!event)
|
|
155
|
+
throw new ValidationError('Missing X-GitHub-Event header.');
|
|
156
|
+
const shouldDispatch = resolved.capability.shouldDispatch?.(resolved.config, { event, payload }) ?? true;
|
|
157
|
+
if (!shouldDispatch) {
|
|
158
|
+
// Return 202 so GitHub does not treat the delivery as a failure,
|
|
159
|
+
// and back off retries, deliberately accepting and dropping.
|
|
160
|
+
return context.json({ accepted: true, event, workspaceId, sourceId, skipped: true }, 202);
|
|
161
|
+
}
|
|
162
|
+
// Fire-and-forget. Deliveries time out at ~10s,
|
|
163
|
+
// and a clean repo with many issues can take minutes to poll.
|
|
164
|
+
// Errors are logged so a failing sync doesn't silently disappear,
|
|
165
|
+
// the next delivery retries.
|
|
166
|
+
// Concurrent deliveries are allowed to race, loaders are idempotent,
|
|
167
|
+
// (last-writer-wins per file) so the result still converges,
|
|
168
|
+
// to the latest remote state.
|
|
169
|
+
void deps.sourceLoaderRunner.syncOne(workspace, sourceId).catch((err) => {
|
|
170
|
+
receiverLogger.warn({
|
|
171
|
+
workspaceId,
|
|
172
|
+
sourceId,
|
|
173
|
+
err: err instanceof Error ? err.message : String(err),
|
|
174
|
+
}, 'background syncOne triggered by github webhook failed');
|
|
175
|
+
});
|
|
176
|
+
return context.json({ accepted: true, event, workspaceId, sourceId, skipped: false }, 202);
|
|
177
|
+
});
|
|
178
|
+
return router;
|
|
179
|
+
}
|
|
180
|
+
function extractFullName(payload) {
|
|
181
|
+
if (typeof payload !== 'object' || payload === null)
|
|
182
|
+
return undefined;
|
|
183
|
+
const repository = payload.repository;
|
|
184
|
+
if (typeof repository !== 'object' || repository === null)
|
|
185
|
+
return undefined;
|
|
186
|
+
const fullName = repository.full_name;
|
|
187
|
+
return typeof fullName === 'string' ? fullName : undefined;
|
|
188
|
+
}
|
|
189
|
+
const adminLogger = createLogger('webhooks.github.admin');
|
|
190
|
+
const SourceIdParam = WorkspaceIdParam.extend({
|
|
191
|
+
sourceId: SourceId.openapi({ param: { name: 'sourceId', in: 'path' } }),
|
|
192
|
+
});
|
|
193
|
+
const WebhookStatusResponse = z.object({
|
|
194
|
+
url: z.string(),
|
|
195
|
+
hasSecret: z.boolean(),
|
|
196
|
+
createdAt: z.string().optional(),
|
|
197
|
+
}).openapi('GithubWebhookStatusResponse');
|
|
198
|
+
const WebhookRotateResponse = z.object({
|
|
199
|
+
url: z.string(),
|
|
200
|
+
secret: z.string(),
|
|
201
|
+
createdAt: z.string(),
|
|
202
|
+
}).openapi('GithubWebhookRotateResponse');
|
|
203
|
+
const ErrorBody = z.object({ error: z.string() }).openapi('GithubWebhookErrorBody');
|
|
204
|
+
const getStatusRoute = createRoute({
|
|
205
|
+
method: 'get',
|
|
206
|
+
path: '/{sourceId}/github',
|
|
207
|
+
operationId: 'getGithubWebhookStatus',
|
|
208
|
+
summary: 'Read the GitHub webhook URL and whether a secret has been provisioned for a source.',
|
|
209
|
+
tags: ['source-webhooks'],
|
|
210
|
+
request: { params: SourceIdParam },
|
|
211
|
+
responses: {
|
|
212
|
+
200: {
|
|
213
|
+
description: 'Webhook URL plus secret-presence flag (the secret itself is never returned on read).',
|
|
214
|
+
content: { 'application/json': { schema: WebhookStatusResponse } },
|
|
215
|
+
},
|
|
216
|
+
400: { description: 'Source is not webhook-capable.', content: { 'application/json': { schema: ErrorBody } } },
|
|
217
|
+
404: { description: 'Source not found.', content: { 'application/json': { schema: ErrorBody } } },
|
|
218
|
+
503: { description: 'Server was not configured with apiUrl.', content: { 'application/json': { schema: ErrorBody } } },
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
const rotateRoute = createRoute({
|
|
222
|
+
method: 'post',
|
|
223
|
+
path: '/{sourceId}/github/rotate',
|
|
224
|
+
operationId: 'rotateGithubWebhookSecret',
|
|
225
|
+
summary: 'Generate a fresh 32-byte hex secret for the GitHub webhook, returning it ONCE.',
|
|
226
|
+
description: 'The secret is shown exactly once in the rotate response so the user can copy it into GitHub. Subsequent GET requests return only `hasSecret` + `createdAt`.',
|
|
227
|
+
tags: ['source-webhooks'],
|
|
228
|
+
request: { params: SourceIdParam },
|
|
229
|
+
responses: {
|
|
230
|
+
200: {
|
|
231
|
+
description: 'New secret minted and stored.',
|
|
232
|
+
content: { 'application/json': { schema: WebhookRotateResponse } },
|
|
233
|
+
},
|
|
234
|
+
400: { description: 'Source is not webhook-capable.', content: { 'application/json': { schema: ErrorBody } } },
|
|
235
|
+
404: { description: 'Source not found.', content: { 'application/json': { schema: ErrorBody } } },
|
|
236
|
+
503: { description: 'Server was not configured with apiUrl.', content: { 'application/json': { schema: ErrorBody } } },
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
export function createSourceWebhooksAdminRouter(deps) {
|
|
240
|
+
const router = new OpenAPIHono();
|
|
241
|
+
router.openapi(getStatusRoute, async (context) => {
|
|
242
|
+
const { workspaceId, sourceId } = context.req.valid('param');
|
|
243
|
+
if (!deps.apiUrl)
|
|
244
|
+
throw new ServiceUnavailableError('Server is not configured with a public apiUrl. Webhook URLs cannot be rendered.');
|
|
245
|
+
await guardWebhookSource(deps, workspaceId, sourceId);
|
|
246
|
+
const record = await deps.secretStore.read(SECRET_NAMESPACE, secretKey(workspaceId, sourceId));
|
|
247
|
+
return context.json({
|
|
248
|
+
url: buildWebhookUrl(deps.apiUrl, workspaceId, sourceId),
|
|
249
|
+
hasSecret: record !== undefined,
|
|
250
|
+
...(record?.createdAt ? { createdAt: record.createdAt } : {}),
|
|
251
|
+
}, 200);
|
|
252
|
+
});
|
|
253
|
+
router.openapi(rotateRoute, async (context) => {
|
|
254
|
+
const { workspaceId, sourceId } = context.req.valid('param');
|
|
255
|
+
if (!deps.apiUrl)
|
|
256
|
+
throw new ServiceUnavailableError('Server is not configured with a public apiUrl. Webhook URLs cannot be rendered.');
|
|
257
|
+
await guardWebhookSource(deps, workspaceId, sourceId);
|
|
258
|
+
// 32 bytes is the GitHub-recommended minimum,
|
|
259
|
+
// matching what their own webhook setup UI generates.
|
|
260
|
+
const secret = randomBytes(32).toString('hex');
|
|
261
|
+
const createdAt = new Date().toISOString();
|
|
262
|
+
const record = { secret, createdAt };
|
|
263
|
+
await deps.secretStore.write(SECRET_NAMESPACE, secretKey(workspaceId, sourceId), record);
|
|
264
|
+
return context.json({
|
|
265
|
+
url: buildWebhookUrl(deps.apiUrl, workspaceId, sourceId),
|
|
266
|
+
secret,
|
|
267
|
+
createdAt,
|
|
268
|
+
}, 200);
|
|
269
|
+
});
|
|
270
|
+
return router;
|
|
271
|
+
}
|
|
272
|
+
// Shared admin precondition check.
|
|
273
|
+
// Returns undefined when the source is a webhook-capable github source,
|
|
274
|
+
// otherwise returns the 4xx the caller should surface.
|
|
275
|
+
// We never throw. On schema drift defineSourceLoaderPlugin's wrapper,
|
|
276
|
+
// may throw ZodError, which we catch and translate to 400.
|
|
277
|
+
async function guardWebhookSource(deps, workspaceId, sourceId) {
|
|
278
|
+
const workspace = await deps.workspaceService.findById(workspaceId);
|
|
279
|
+
const source = workspace.sources.find(s => s.id === sourceId);
|
|
280
|
+
if (!source)
|
|
281
|
+
throw new NotFoundError(`Source "${sourceId}" not found`);
|
|
282
|
+
const resolved = resolveWebhookCapability(deps.pluginRegistry, source);
|
|
283
|
+
if (!resolved)
|
|
284
|
+
throw new ValidationError(`Source "${sourceId}" has no webhook-capable loader.`);
|
|
285
|
+
try {
|
|
286
|
+
const identity = resolved.capability.repoIdentity(resolved.config);
|
|
287
|
+
if (!identity || identity.provider !== PROVIDER)
|
|
288
|
+
throw new ValidationError(`Source "${sourceId}" is not bound to a github repo.`);
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
if (err instanceof ValidationError)
|
|
292
|
+
throw err;
|
|
293
|
+
adminLogger.warn({ workspaceId, sourceId, err: err instanceof Error ? err.message : String(err) }, 'admin: repoIdentity threw');
|
|
294
|
+
throw new ValidationError(`Source "${sourceId}" loader config does not match the loader's schema.`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function buildWebhookUrl(apiUrl, workspaceId, sourceId) {
|
|
298
|
+
const base = apiUrl.replace(/\/$/, '');
|
|
299
|
+
return `${base}/webhooks/github/${workspaceId}/${sourceId}`;
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=sourceWebhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sourceWebhooks.js","sourceRoot":"","sources":["../../src/routes/sourceWebhooks.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/users.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type { Clock } from '@braidhq/core';
|
|
2
1
|
import type { UserRegistryFile } from '../infrastructure/users/UserRegistryFile.js';
|
|
3
2
|
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
4
3
|
export interface UsersRouterDeps {
|
|
5
4
|
userRegistry: UserRegistryFile;
|
|
6
|
-
clock: Clock;
|
|
7
5
|
}
|
|
8
6
|
export declare function createUsersRouter(deps: UsersRouterDeps): OpenAPIHono;
|
|
9
7
|
//# sourceMappingURL=users.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/routes/users.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/routes/users.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAA;AAGnF,OAAO,EAAe,WAAW,EAAK,MAAM,mBAAmB,CAAA;AAkB/D,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,gBAAgB,CAAA;CAC/B;AAmED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,WAAW,CAmCpE"}
|
package/dist/routes/users.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { User,
|
|
1
|
+
import { ForbiddenError, NotFoundError } from '@braidhq/core';
|
|
2
|
+
import { User, UserId } from '@braidhq/schema';
|
|
3
3
|
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
|
|
4
|
-
import { getUserId } from '../middleware/
|
|
5
|
-
import {
|
|
4
|
+
import { getUserId } from '../middleware/auth.js';
|
|
5
|
+
import { ForbiddenResponse, NotFoundResponse } from './_shared.js';
|
|
6
6
|
const UserIdParam = z.object({
|
|
7
7
|
userId: UserId.openapi({ param: { name: 'userId', in: 'path' } }),
|
|
8
8
|
});
|
|
9
9
|
const UserListResponse = z.object({
|
|
10
10
|
items: z.array(User),
|
|
11
11
|
}).openapi('UserListResponse');
|
|
12
|
+
// Self-service profile edit, only the display name.
|
|
13
|
+
// Server-role changes go through the admin-gated `/admin/users` routes.
|
|
14
|
+
const SelfProfileUpdate = z.object({
|
|
15
|
+
displayName: z.string().min(1),
|
|
16
|
+
});
|
|
12
17
|
const listUsersRoute = createRoute({
|
|
13
18
|
method: 'get',
|
|
14
19
|
path: '/',
|
|
@@ -51,38 +56,22 @@ const getUserRoute = createRoute({
|
|
|
51
56
|
404: NotFoundResponse,
|
|
52
57
|
},
|
|
53
58
|
});
|
|
54
|
-
const createUserRoute = createRoute({
|
|
55
|
-
method: 'post',
|
|
56
|
-
path: '/',
|
|
57
|
-
operationId: 'createUser',
|
|
58
|
-
summary: 'Create a user. Phase A: any caller; Phase B/C will gate by Admin role.',
|
|
59
|
-
tags: ['users'],
|
|
60
|
-
request: {
|
|
61
|
-
body: { content: { 'application/json': { schema: UserDraft } } },
|
|
62
|
-
},
|
|
63
|
-
responses: {
|
|
64
|
-
201: {
|
|
65
|
-
description: 'The created user.',
|
|
66
|
-
content: { 'application/json': { schema: User } },
|
|
67
|
-
},
|
|
68
|
-
400: ValidationFailureResponse,
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
59
|
const updateUserRoute = createRoute({
|
|
72
60
|
method: 'patch',
|
|
73
61
|
path: '/{userId}',
|
|
74
62
|
operationId: 'updateUser',
|
|
75
|
-
summary: '
|
|
63
|
+
summary: 'Update your own display name, role changes go through /admin.',
|
|
76
64
|
tags: ['users'],
|
|
77
65
|
request: {
|
|
78
66
|
params: UserIdParam,
|
|
79
|
-
body: { content: { 'application/json': { schema:
|
|
67
|
+
body: { content: { 'application/json': { schema: SelfProfileUpdate } } },
|
|
80
68
|
},
|
|
81
69
|
responses: {
|
|
82
70
|
200: {
|
|
83
71
|
description: 'The updated user.',
|
|
84
72
|
content: { 'application/json': { schema: User } },
|
|
85
73
|
},
|
|
74
|
+
403: ForbiddenResponse,
|
|
86
75
|
404: NotFoundResponse,
|
|
87
76
|
},
|
|
88
77
|
});
|
|
@@ -106,18 +95,11 @@ export function createUsersRouter(deps) {
|
|
|
106
95
|
throw new NotFoundError(`User "${userId}" not found`);
|
|
107
96
|
return context.json(user, 200);
|
|
108
97
|
});
|
|
109
|
-
router.openapi(createUserRoute, async (context) => {
|
|
110
|
-
const draft = context.req.valid('json');
|
|
111
|
-
const created = await deps.userRegistry.create({
|
|
112
|
-
id: newUserId(),
|
|
113
|
-
...draft,
|
|
114
|
-
serverRole: draft.serverRole ?? 'user',
|
|
115
|
-
createdAt: deps.clock.now(),
|
|
116
|
-
});
|
|
117
|
-
return context.json(created, 201);
|
|
118
|
-
});
|
|
119
98
|
router.openapi(updateUserRoute, async (context) => {
|
|
120
99
|
const { userId } = context.req.valid('param');
|
|
100
|
+
// Self-service only. Server-admin edits go through the admin routes.
|
|
101
|
+
if (userId !== getUserId(context))
|
|
102
|
+
throw new ForbiddenError('You can only update your own profile.');
|
|
121
103
|
const patch = context.req.valid('json');
|
|
122
104
|
const updated = await deps.userRegistry.update(userId, patch);
|
|
123
105
|
return context.json(updated, 200);
|
package/dist/routes/users.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/routes/users.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/routes/users.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,11 @@ export interface WorkspaceEventsRouterDeps {
|
|
|
4
4
|
readonly eventBus: WorkspaceEventBus;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
* SSE endpoint the Studio opens once per workspace
|
|
8
|
-
* react-query caches in real time.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* SSE endpoint the Studio opens once per workspace,
|
|
8
|
+
* to invalidate react-query caches in real time.
|
|
9
|
+
* Delivery is best-effort, events are dropped when no one is listening,
|
|
10
|
+
* and the route makes no attempt to backfill state on connect.
|
|
11
|
+
* The client re-fetches list endpoints on `EventSource.open`,
|
|
11
12
|
* so a fresh subscriber catches up.
|
|
12
13
|
*/
|
|
13
14
|
export declare function createWorkspaceEventsRouter(deps: WorkspaceEventsRouterDeps): Hono;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaceEvents.d.ts","sourceRoot":"","sources":["../../src/routes/workspaceEvents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"workspaceEvents.d.ts","sourceRoot":"","sources":["../../src/routes/workspaceEvents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEtD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAK3B,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,yBAAyB,GAAG,IAAI,CA0BjF"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { streamSSE } from 'hono/streaming';
|
|
3
|
-
import { createAsyncQueue } from '../infrastructure/
|
|
3
|
+
import { createAsyncQueue } from '../infrastructure/skill/asyncQueue.js';
|
|
4
4
|
import { getWorkspaceId, workspaceIdMiddleware } from '../middleware/workspaceId.js';
|
|
5
5
|
/**
|
|
6
|
-
* SSE endpoint the Studio opens once per workspace
|
|
7
|
-
* react-query caches in real time.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* SSE endpoint the Studio opens once per workspace,
|
|
7
|
+
* to invalidate react-query caches in real time.
|
|
8
|
+
* Delivery is best-effort, events are dropped when no one is listening,
|
|
9
|
+
* and the route makes no attempt to backfill state on connect.
|
|
10
|
+
* The client re-fetches list endpoints on `EventSource.open`,
|
|
10
11
|
* so a fresh subscriber catches up.
|
|
11
12
|
*/
|
|
12
13
|
export function createWorkspaceEventsRouter(deps) {
|
|
@@ -18,7 +19,7 @@ export function createWorkspaceEventsRouter(deps) {
|
|
|
18
19
|
const unsubscribe = deps.eventBus.subscribe(workspaceId, (event) => {
|
|
19
20
|
queue.push(event);
|
|
20
21
|
});
|
|
21
|
-
// Initial comment so the client's EventSource.onopen fires
|
|
22
|
+
// Initial comment so the client's EventSource.onopen fires,
|
|
22
23
|
// immediately even if no event has been published yet.
|
|
23
24
|
await stream.writeSSE({ event: 'ready', data: JSON.stringify({ workspaceId }) });
|
|
24
25
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaceEvents.js","sourceRoot":"","sources":["../../src/routes/workspaceEvents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspaceEvents.js","sourceRoot":"","sources":["../../src/routes/workspaceEvents.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AAMpF;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAA+B;IACzE,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC1E,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,OAAO,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACzC,MAAM,KAAK,GAAG,gBAAgB,EAAkB,CAAA;YAChD,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;gBACjE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnB,CAAC,CAAC,CAAA;YACF,4DAA4D;YAC5D,uDAAuD;YACvD,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAA;YAChF,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC1C,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;gBAC3E,CAAC;YACH,CAAC;oBACO,CAAC;gBACP,WAAW,EAAE,CAAA;gBACb,KAAK,CAAC,GAAG,EAAE,CAAA;YACb,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Clock, WorkspaceService } from '@braidhq/core';
|
|
2
|
-
import type { WorkspaceRegistryFile } from '../infrastructure/
|
|
2
|
+
import type { WorkspaceRegistryFile } from '../infrastructure/workspace/WorkspaceRegistryFile.js';
|
|
3
3
|
import { Hono } from 'hono';
|
|
4
4
|
export interface WorkspaceMembersRouterDeps {
|
|
5
5
|
workspaceService: WorkspaceService;
|