@hotmeshio/long-tail 0.1.4 → 0.1.5
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/README.md +1 -1
- package/build/examples/seed.js +1 -1
- package/build/examples/workflows/basic-echo/activities.d.ts +2 -2
- package/build/examples/workflows/basic-echo/activities.js +7 -7
- package/build/examples/workflows/basic-echo/index.js +1 -1
- package/build/examples/workflows/kitchen-sink/index.js +2 -2
- package/build/index.d.ts +11 -10
- package/build/index.js +13 -12
- package/build/lib/db/index.d.ts +18 -0
- package/build/{services → lib}/db/index.js +9 -0
- package/build/{services → lib}/db/migrate.js +3 -3
- package/build/{services → lib}/telemetry/honeycomb.d.ts +2 -2
- package/build/{services → lib}/telemetry/honeycomb.js +2 -2
- package/build/modules/defaults.d.ts +2 -0
- package/build/modules/defaults.js +3 -1
- package/build/routes/controlplane.js +1 -1
- package/build/routes/dba.js +4 -0
- package/build/routes/docs.d.ts +2 -0
- package/build/routes/docs.js +87 -0
- package/build/routes/escalations/bulk.js +120 -202
- package/build/routes/escalations/resolve.js +1 -1
- package/build/routes/escalations/single.js +1 -1
- package/build/routes/files.js +1 -1
- package/build/routes/index.js +2 -0
- package/build/routes/insight.js +2 -1
- package/build/routes/mcp.js +3 -2
- package/build/routes/oauth.js +1 -1
- package/build/routes/settings.js +4 -4
- package/build/routes/workflows/discovery.js +3 -3
- package/build/routes/workflows/invocation.js +1 -1
- package/build/routes/yaml-workflows/crud.js +1 -1
- package/build/routes/yaml-workflows/deployment.js +25 -0
- package/build/services/auth/bot-api-key.js +1 -1
- package/build/services/auth/index.d.ts +4 -0
- package/build/services/auth/index.js +17 -0
- package/build/services/auth/service-token.js +1 -1
- package/build/services/config/provider.js +1 -1
- package/build/services/config/read.js +1 -1
- package/build/services/config/write.js +1 -1
- package/build/services/controlplane/index.js +3 -4
- package/build/services/controlplane/quorum-bridge.js +2 -2
- package/build/services/cron/index.js +4 -5
- package/build/services/dba.d.ts +4 -0
- package/build/services/dba.js +3 -6
- package/build/services/escalation/bulk.js +1 -1
- package/build/services/escalation/crud.js +1 -1
- package/build/services/escalation/queries.js +1 -1
- package/build/services/export/client.js +2 -5
- package/build/services/export/index.js +14 -2
- package/build/services/hotmesh-utils.js +1 -1
- package/build/services/iam/bots.js +6 -12
- package/build/services/iam/context.d.ts +1 -1
- package/build/services/iam/context.js +5 -5
- package/build/services/iam/credentials.js +1 -1
- package/build/services/iam/ephemeral.js +8 -15
- package/build/services/iam/principal.js +3 -10
- package/build/services/iam/resolve.js +1 -1
- package/build/services/iam/sql.d.ts +10 -0
- package/build/services/iam/sql.js +42 -0
- package/build/services/insight/index.d.ts +1 -0
- package/build/services/insight/index.js +4 -6
- package/build/services/interceptor/activities/escalation.js +1 -1
- package/build/services/interceptor/activities/task.js +9 -6
- package/build/services/interceptor/activities/workflow.js +4 -5
- package/build/services/interceptor/activity-interceptor.d.ts +1 -1
- package/build/services/interceptor/activity-interceptor.js +5 -5
- package/build/services/interceptor/completion.js +1 -1
- package/build/services/interceptor/escalation.js +1 -1
- package/build/services/interceptor/index.js +4 -4
- package/build/services/interceptor/lifecycle.js +1 -1
- package/build/services/maintenance/index.js +4 -5
- package/build/services/mcp/adapter.js +1 -16
- package/build/services/mcp/client/connection.d.ts +1 -1
- package/build/services/mcp/client/connection.js +2 -2
- package/build/services/mcp/client/tools.js +1 -1
- package/build/services/mcp/db-server/index.js +1 -1
- package/build/services/mcp/db-server/tools.js +17 -4
- package/build/services/mcp/db.js +1 -1
- package/build/services/mcp/playwright-server/index.js +1 -1
- package/build/services/mcp/playwright-server/lifecycle.js +1 -1
- package/build/services/mcp/playwright-server/schemas.d.ts +2 -2
- package/build/services/mcp/playwright-server/tools.js +1 -1
- package/build/services/mcp/server.js +1 -1
- package/build/services/mcp/sql.d.ts +6 -0
- package/build/services/mcp/sql.js +34 -1
- package/build/services/mcp/workflow-compiler-server.js +1 -1
- package/build/services/mcp/workflow-server.js +1 -1
- package/build/services/mcp-runs/execution-builder.js +8 -6
- package/build/services/mcp-runs/queries.js +2 -2
- package/build/services/mcp-runs/sql.d.ts +4 -1
- package/build/services/mcp-runs/sql.js +23 -2
- package/build/services/namespace/index.js +1 -1
- package/build/services/oauth/db.js +9 -37
- package/build/services/oauth/index.js +1 -1
- package/build/services/oauth/providers/registry.js +1 -1
- package/build/services/oauth/sql.d.ts +7 -0
- package/build/services/oauth/sql.js +32 -0
- package/build/services/orchestrator/index.js +3 -3
- package/build/services/role/index.js +1 -1
- package/build/services/task/crud.js +1 -1
- package/build/services/task/process.js +1 -1
- package/build/services/task/resolve.js +1 -1
- package/build/services/user/auth.js +1 -1
- package/build/services/user/crud.js +1 -1
- package/build/services/user/rbac.js +1 -1
- package/build/services/user/roles.js +1 -1
- package/build/services/user/sql.d.ts +2 -0
- package/build/services/user/sql.js +3 -1
- package/build/services/yaml-workflow/db-utils.js +1 -1
- package/build/services/yaml-workflow/db.js +1 -1
- package/build/services/yaml-workflow/deployer-helpers.js +1 -1
- package/build/services/yaml-workflow/deployer.js +4 -4
- package/build/services/yaml-workflow/generator.js +1 -1
- package/build/services/yaml-workflow/input-analyzer-helpers.d.ts +6 -0
- package/build/services/yaml-workflow/input-analyzer-helpers.js +36 -7
- package/build/services/yaml-workflow/input-analyzer.js +16 -3
- package/build/services/yaml-workflow/pipeline/analyze.js +1 -1
- package/build/services/yaml-workflow/pipeline/build/dag.js +10 -5
- package/build/services/yaml-workflow/pipeline/compile/llm-call.js +1 -1
- package/build/services/yaml-workflow/pipeline/extract.js +5 -3
- package/build/services/yaml-workflow/pipeline/index.d.ts +5 -0
- package/build/services/yaml-workflow/pipeline/index.js +22 -0
- package/build/services/yaml-workflow/pipeline/validate.js +2 -2
- package/build/services/yaml-workflow/workers/callbacks.js +1 -1
- package/build/services/yaml-workflow/workers/events.js +2 -2
- package/build/services/yaml-workflow/workers/register.js +8 -8
- package/build/start/adapters.js +7 -7
- package/build/start/index.js +4 -4
- package/build/start/server.js +1 -1
- package/build/start/workers.d.ts +1 -2
- package/build/start/workers.js +8 -7
- package/build/system/activities/claude-code.js +1 -1
- package/build/system/activities/file-storage.js +1 -1
- package/build/system/activities/knowledge.d.ts +58 -0
- package/build/system/activities/knowledge.js +128 -0
- package/build/system/activities/sql.d.ts +9 -0
- package/build/system/activities/sql.js +41 -0
- package/build/system/activities/triage/context.js +1 -1
- package/build/system/activities/triage/discovery.d.ts +2 -14
- package/build/system/activities/triage/discovery.js +5 -161
- package/build/system/activities/triage/llm.d.ts +1 -8
- package/build/system/activities/triage/llm.js +2 -28
- package/build/system/activities/triage/tools.d.ts +1 -17
- package/build/system/activities/triage/tools.js +8 -167
- package/build/system/index.js +5 -4
- package/build/system/mcp-servers/admin/escalations.d.ts +5 -0
- package/build/system/mcp-servers/admin/escalations.js +149 -0
- package/build/system/mcp-servers/admin/index.d.ts +31 -0
- package/build/system/mcp-servers/admin/index.js +80 -0
- package/build/system/mcp-servers/admin/maintenance.d.ts +5 -0
- package/build/system/mcp-servers/admin/maintenance.js +58 -0
- package/build/system/mcp-servers/admin/mcp-servers.d.ts +5 -0
- package/build/system/mcp-servers/admin/mcp-servers.js +146 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +411 -0
- package/build/system/mcp-servers/admin/schemas.js +177 -0
- package/build/system/mcp-servers/admin/tasks.d.ts +5 -0
- package/build/system/mcp-servers/admin/tasks.js +112 -0
- package/build/system/mcp-servers/admin/users.d.ts +5 -0
- package/build/system/mcp-servers/admin/users.js +167 -0
- package/build/system/mcp-servers/admin/workflow-config.d.ts +9 -0
- package/build/system/mcp-servers/admin/workflow-config.js +118 -0
- package/build/system/mcp-servers/admin/workflows.d.ts +6 -0
- package/build/system/mcp-servers/admin/workflows.js +138 -0
- package/build/system/mcp-servers/admin/yaml-workflows.d.ts +8 -0
- package/build/system/mcp-servers/admin/yaml-workflows.js +237 -0
- package/build/system/mcp-servers/claude-code.js +1 -1
- package/build/system/mcp-servers/db-query/index.js +1 -1
- package/build/system/mcp-servers/db-query/tools.js +17 -4
- package/build/system/mcp-servers/docs.d.ts +5 -0
- package/build/system/mcp-servers/docs.js +147 -0
- package/build/system/mcp-servers/file-storage.js +1 -1
- package/build/system/mcp-servers/http-fetch.js +1 -1
- package/build/system/mcp-servers/human-queue.js +1 -1
- package/build/system/mcp-servers/knowledge.d.ts +4 -0
- package/build/system/mcp-servers/knowledge.js +137 -0
- package/build/system/mcp-servers/oauth.js +1 -1
- package/build/system/mcp-servers/playwright/browser-lifecycle.js +1 -1
- package/build/system/mcp-servers/playwright/index.js +1 -1
- package/build/system/mcp-servers/playwright/schemas.d.ts +19 -8
- package/build/system/mcp-servers/playwright/schemas.js +3 -0
- package/build/system/mcp-servers/playwright/tools-navigation.js +22 -9
- package/build/system/mcp-servers/playwright/tools-run-script.js +20 -3
- package/build/system/mcp-servers/playwright/vision-helper.d.ts +12 -0
- package/build/system/mcp-servers/playwright/vision-helper.js +81 -0
- package/build/system/mcp-servers/playwright-cli/helpers.js +2 -2
- package/build/system/mcp-servers/playwright-cli/index.js +1 -1
- package/build/system/mcp-servers/playwright-cli/schemas.d.ts +28 -28
- package/build/system/mcp-servers/playwright-cli/schemas.js +1 -1
- package/build/system/mcp-servers/playwright-cli/tools-auth.js +1 -1
- package/build/system/mcp-servers/playwright-cli/tools-capture.js +4 -2
- package/build/system/mcp-servers/translation.d.ts +14 -0
- package/build/system/mcp-servers/translation.js +130 -0
- package/build/system/mcp-servers/vision-prompts.d.ts +2 -0
- package/build/system/mcp-servers/vision-prompts.js +9 -0
- package/build/system/mcp-servers/{document-vision.d.ts → vision.d.ts} +3 -4
- package/build/system/mcp-servers/vision.js +221 -0
- package/build/system/mcp-servers/workflow-compiler.js +1 -1
- package/build/system/mcp-servers/workflow.js +1 -1
- package/build/system/seed/index.js +13 -2
- package/build/system/seed/server-definitions.d.ts +1954 -322
- package/build/system/seed/server-definitions.js +65 -34
- package/build/system/seed/tool-manifests-admin.d.ts +1645 -0
- package/build/system/seed/tool-manifests-admin.js +45 -0
- package/build/system/seed/tool-manifests-browser.d.ts +1 -1
- package/build/system/seed/tool-manifests-browser.js +3 -3
- package/build/system/seed/tool-manifests-data.d.ts +62 -21
- package/build/system/seed/tool-manifests-data.js +55 -17
- package/build/system/seed/tool-manifests-knowledge.d.ts +171 -0
- package/build/system/seed/tool-manifests-knowledge.js +94 -0
- package/build/system/workflows/mcp-deterministic/index.js +1 -1
- package/build/system/workflows/mcp-query/activities/discovery.d.ts +2 -20
- package/build/system/workflows/mcp-query/activities/discovery.js +5 -163
- package/build/system/workflows/mcp-query/activities/llm.d.ts +1 -7
- package/build/system/workflows/mcp-query/activities/llm.js +2 -27
- package/build/system/workflows/mcp-query/activities/tool-executor.d.ts +0 -4
- package/build/system/workflows/mcp-query/activities/tool-executor.js +2 -106
- package/build/system/workflows/mcp-query/activities/tool-loader.d.ts +0 -9
- package/build/system/workflows/mcp-query/activities/tool-loader.js +2 -87
- package/build/system/workflows/mcp-query/index.js +55 -5
- package/build/system/workflows/mcp-query/prompts.d.ts +1 -2
- package/build/system/workflows/mcp-query/prompts.js +5 -32
- package/build/system/workflows/mcp-query/strategy-advisors.d.ts +3 -14
- package/build/system/workflows/mcp-query/strategy-advisors.js +4 -107
- package/build/system/workflows/mcp-query/types.d.ts +2 -10
- package/build/system/workflows/mcp-query/types.js +0 -1
- package/build/system/workflows/mcp-query-router/index.js +1 -1
- package/build/system/workflows/mcp-triage/index.d.ts +2 -2
- package/build/system/workflows/mcp-triage/index.js +39 -7
- package/build/system/workflows/mcp-triage/prompts.js +7 -14
- package/build/system/workflows/mcp-triage-deterministic/index.js +1 -1
- package/build/system/workflows/mcp-triage-router/index.js +1 -1
- package/build/system/workflows/shared/discovery.d.ts +35 -0
- package/build/system/workflows/shared/discovery.js +175 -0
- package/build/system/workflows/shared/index.d.ts +7 -0
- package/build/system/workflows/shared/index.js +18 -0
- package/build/system/workflows/shared/llm-caller.d.ts +8 -0
- package/build/system/workflows/shared/llm-caller.js +31 -0
- package/build/system/workflows/shared/prompts.d.ts +2 -0
- package/build/system/workflows/shared/prompts.js +32 -0
- package/build/system/workflows/shared/strategy-advisors.d.ts +14 -0
- package/build/system/workflows/shared/strategy-advisors.js +109 -0
- package/build/system/workflows/shared/tool-executor.d.ts +11 -0
- package/build/system/workflows/shared/tool-executor.js +111 -0
- package/build/system/workflows/shared/tool-loader.d.ts +19 -0
- package/build/system/workflows/shared/tool-loader.js +94 -0
- package/build/system/workflows/shared/types.d.ts +9 -0
- package/build/system/workflows/shared/types.js +2 -0
- package/build/system/workflows/tool-result-guard.d.ts +14 -0
- package/build/system/workflows/tool-result-guard.js +78 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/user.d.ts +2 -0
- package/build/vitest.config.d.ts +1 -1
- package/build/vitest.integration.config.d.ts +1 -1
- package/build/workers/index.js +2 -8
- package/dashboard/dist/assets/AdminDashboard-CTyAMUJR.js +2 -0
- package/dashboard/dist/assets/AdminDashboard-CTyAMUJR.js.map +1 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-BMXV3Q4l.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-BMXV3Q4l.js.map +1 -0
- package/dashboard/dist/assets/BotPicker-C51nKFEu.js +2 -0
- package/dashboard/dist/assets/{BotPicker-D6FYW1Gt.js.map → BotPicker-C51nKFEu.js.map} +1 -1
- package/dashboard/dist/assets/CollapsibleSection-BSyfd8uL.js +2 -0
- package/dashboard/dist/assets/{CollapsibleSection-Cxk4wvjT.js.map → CollapsibleSection-BSyfd8uL.js.map} +1 -1
- package/dashboard/dist/assets/ConfirmDeleteModal-CBdhia5T.js +2 -0
- package/dashboard/dist/assets/{ConfirmDeleteModal-FSXyKjaB.js.map → ConfirmDeleteModal-CBdhia5T.js.map} +1 -1
- package/dashboard/dist/assets/CopyableId-dGlewBCS.js +2 -0
- package/dashboard/dist/assets/{CopyableId-CBdxWfp8.js.map → CopyableId-dGlewBCS.js.map} +1 -1
- package/dashboard/dist/assets/CredentialsPage-CoBNFSAu.js +2 -0
- package/dashboard/dist/assets/{CredentialsPage-Ikzsot0w.js.map → CredentialsPage-CoBNFSAu.js.map} +1 -1
- package/dashboard/dist/assets/CustomDurationPicker-BataWFj8.js +2 -0
- package/dashboard/dist/assets/{CustomDurationPicker-CAninCbl.js.map → CustomDurationPicker-BataWFj8.js.map} +1 -1
- package/dashboard/dist/assets/DataTable-B3uf5CCo.js +2 -0
- package/dashboard/dist/assets/DataTable-B3uf5CCo.js.map +1 -0
- package/dashboard/dist/assets/ElapsedCell-G5oSwTpT.js +2 -0
- package/dashboard/dist/assets/ElapsedCell-G5oSwTpT.js.map +1 -0
- package/dashboard/dist/assets/EmptyState-BChBJNGS.js +2 -0
- package/dashboard/dist/assets/{EmptyState-2CmV-IaS.js.map → EmptyState-BChBJNGS.js.map} +1 -1
- package/dashboard/dist/assets/EscalationsOverview-CxUv8xjG.js +2 -0
- package/dashboard/dist/assets/{EscalationsOverview-GXYFPASS.js.map → EscalationsOverview-CxUv8xjG.js.map} +1 -1
- package/dashboard/dist/assets/EventTable-CVt8B0BZ.js +2 -0
- package/dashboard/dist/assets/{EventTable-B01oJf6Y.js.map → EventTable-CVt8B0BZ.js.map} +1 -1
- package/dashboard/dist/assets/FilterBar-CShf0oe7.js +2 -0
- package/dashboard/dist/assets/{FilterBar-Ck4K4rzu.js.map → FilterBar-CShf0oe7.js.map} +1 -1
- package/dashboard/dist/assets/McpOverview-CbaZRnJl.js +2 -0
- package/dashboard/dist/assets/{McpOverview-JkvRcX2e.js.map → McpOverview-CbaZRnJl.js.map} +1 -1
- package/dashboard/dist/assets/McpQueryDetailPage-CGoR9XK6.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-CGoR9XK6.js.map +1 -0
- package/dashboard/dist/assets/McpQueryPage-BjXoYQuU.js +2 -0
- package/dashboard/dist/assets/McpQueryPage-BjXoYQuU.js.map +1 -0
- package/dashboard/dist/assets/McpRunDetailPage-DLkA5Aar.js +2 -0
- package/dashboard/dist/assets/McpRunDetailPage-DLkA5Aar.js.map +1 -0
- package/dashboard/dist/assets/McpRunsPage-DCh9n11D.js +2 -0
- package/dashboard/dist/assets/McpRunsPage-DCh9n11D.js.map +1 -0
- package/dashboard/dist/assets/Modal-CI5RBPOQ.js +2 -0
- package/dashboard/dist/assets/{Modal-B4rbIVAn.js.map → Modal-CI5RBPOQ.js.map} +1 -1
- package/dashboard/dist/assets/OperatorDashboard-Dc80suXd.js +2 -0
- package/dashboard/dist/assets/OperatorDashboard-Dc80suXd.js.map +1 -0
- package/dashboard/dist/assets/PageHeader-SMD9qtOO.js +2 -0
- package/dashboard/dist/assets/PageHeader-SMD9qtOO.js.map +1 -0
- package/dashboard/dist/assets/PageHeaderWithStats-TikLQsTp.js +2 -0
- package/dashboard/dist/assets/PageHeaderWithStats-TikLQsTp.js.map +1 -0
- package/dashboard/dist/assets/PriorityBadge-CQ0EsLTA.js +2 -0
- package/dashboard/dist/assets/{PriorityBadge-DfQY9St9.js.map → PriorityBadge-CQ0EsLTA.js.map} +1 -1
- package/dashboard/dist/assets/ProcessDetailPage-B2GKuGzk.js +2 -0
- package/dashboard/dist/assets/ProcessDetailPage-B2GKuGzk.js.map +1 -0
- package/dashboard/dist/assets/ProcessesListPage-CTjI3Wn6.js +2 -0
- package/dashboard/dist/assets/ProcessesListPage-CTjI3Wn6.js.map +1 -0
- package/dashboard/dist/assets/RefreshButton-BcQDObrv.js +2 -0
- package/dashboard/dist/assets/RefreshButton-BcQDObrv.js.map +1 -0
- package/dashboard/dist/assets/RolePill-Crj4TH5p.js +2 -0
- package/dashboard/dist/assets/{RolePill-BTPa8L-P.js.map → RolePill-Crj4TH5p.js.map} +1 -1
- package/dashboard/dist/assets/RolesPage-C_RInUwS.js +2 -0
- package/dashboard/dist/assets/RolesPage-C_RInUwS.js.map +1 -0
- package/dashboard/dist/assets/RowActions-Cp5HyK_w.js +2 -0
- package/dashboard/dist/assets/{RowActions-Dg-Fsm5O.js.map → RowActions-Cp5HyK_w.js.map} +1 -1
- package/dashboard/dist/assets/RunAsSelector-BhyWtofX.js +2 -0
- package/dashboard/dist/assets/RunAsSelector-BhyWtofX.js.map +1 -0
- package/dashboard/dist/assets/StatCard-BKZLSgNV.js +2 -0
- package/dashboard/dist/assets/{StatCard-DlgF0CJC.js.map → StatCard-BKZLSgNV.js.map} +1 -1
- package/dashboard/dist/assets/StatusBadge-BYNGGZK5.js +2 -0
- package/dashboard/dist/assets/StatusBadge-BYNGGZK5.js.map +1 -0
- package/dashboard/dist/assets/StickyPagination-CTosgiU2.js +2 -0
- package/dashboard/dist/assets/{StickyPagination-F9FZsRy9.js.map → StickyPagination-CTosgiU2.js.map} +1 -1
- package/dashboard/dist/assets/SwimlaneTimeline-ylG5Ps1s.js +2 -0
- package/dashboard/dist/assets/SwimlaneTimeline-ylG5Ps1s.js.map +1 -0
- package/dashboard/dist/assets/TaskDetailPage-C9pDGdD2.js +2 -0
- package/dashboard/dist/assets/TaskDetailPage-C9pDGdD2.js.map +1 -0
- package/dashboard/dist/assets/TaskQueuePill-BtJbZTT0.js +2 -0
- package/dashboard/dist/assets/{TaskQueuePill-awmtb0qw.js.map → TaskQueuePill-BtJbZTT0.js.map} +1 -1
- package/dashboard/dist/assets/TasksListPage-DtFLUEhg.js +2 -0
- package/dashboard/dist/assets/{TasksListPage-C_QF23c1.js.map → TasksListPage-DtFLUEhg.js.map} +1 -1
- package/dashboard/dist/assets/TimeAgo-WuM6xImZ.js +2 -0
- package/dashboard/dist/assets/TimeAgo-WuM6xImZ.js.map +1 -0
- package/dashboard/dist/assets/TimestampCell-IVL_-Upy.js +2 -0
- package/dashboard/dist/assets/TimestampCell-IVL_-Upy.js.map +1 -0
- package/dashboard/dist/assets/UserName-DU9qeg13.js +2 -0
- package/dashboard/dist/assets/{UserName-DaP4YAKr.js.map → UserName-DU9qeg13.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-DOocX81f.js +2 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-DOocX81f.js.map +1 -0
- package/dashboard/dist/assets/WorkflowPill-Diw8iWBP.js +2 -0
- package/dashboard/dist/assets/WorkflowPill-Diw8iWBP.js.map +1 -0
- package/dashboard/dist/assets/WorkflowsDashboard-DDtUIrTy.js +2 -0
- package/dashboard/dist/assets/WorkflowsDashboard-DDtUIrTy.js.map +1 -0
- package/dashboard/dist/assets/WorkflowsOverview-CPuvA4t3.js +2 -0
- package/dashboard/dist/assets/{WorkflowsOverview-D9OzzQqw.js.map → WorkflowsOverview-CPuvA4t3.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-DlwwkluN.js +2 -0
- package/dashboard/dist/assets/YamlWorkflowsPage-DlwwkluN.js.map +1 -0
- package/dashboard/dist/assets/{bots-BkKVMbUW.js → bots-BPiZXf2h.js} +2 -2
- package/dashboard/dist/assets/{bots-BkKVMbUW.js.map → bots-BPiZXf2h.js.map} +1 -1
- package/dashboard/dist/assets/constants-BHkpVaqx.js +2 -0
- package/dashboard/dist/assets/constants-BHkpVaqx.js.map +1 -0
- package/dashboard/dist/assets/escalation-DTY_OKRh.js +2 -0
- package/dashboard/dist/assets/escalation-DTY_OKRh.js.map +1 -0
- package/dashboard/dist/assets/escalation-columns-C91fHSkp.js +2 -0
- package/dashboard/dist/assets/{escalation-columns-D6aqStaY.js.map → escalation-columns-C91fHSkp.js.map} +1 -1
- package/dashboard/dist/assets/helpers-DBUZ9pnG.js +2 -0
- package/dashboard/dist/assets/helpers-DBUZ9pnG.js.map +1 -0
- package/dashboard/dist/assets/index-BOeA-gfK.js +17 -0
- package/dashboard/dist/assets/{index-X85K5bHC.js.map → index-BOeA-gfK.js.map} +1 -1
- package/dashboard/dist/assets/index-BZ6K_kmL.js +3 -0
- package/dashboard/dist/assets/index-BZ6K_kmL.js.map +1 -0
- package/dashboard/dist/assets/index-Bpm0yeoi.js +2 -0
- package/dashboard/dist/assets/index-Bpm0yeoi.js.map +1 -0
- package/dashboard/dist/assets/index-BtOwLI0K.js +2 -0
- package/dashboard/dist/assets/{index-DTPzZr_X.js.map → index-BtOwLI0K.js.map} +1 -1
- package/dashboard/dist/assets/index-CBF3ZvRZ.js +6 -0
- package/dashboard/dist/assets/index-CBF3ZvRZ.js.map +1 -0
- package/dashboard/dist/assets/index-CDWOfCmi.js +2 -0
- package/dashboard/dist/assets/index-CDWOfCmi.js.map +1 -0
- package/dashboard/dist/assets/index-Ce6sL__n.js +2 -0
- package/dashboard/dist/assets/index-Ce6sL__n.js.map +1 -0
- package/dashboard/dist/assets/index-DSzSoku1.js +283 -0
- package/dashboard/dist/assets/index-DSzSoku1.js.map +1 -0
- package/dashboard/dist/assets/index-D_qEAYrg.js +2 -0
- package/dashboard/dist/assets/index-D_qEAYrg.js.map +1 -0
- package/dashboard/dist/assets/index-gCy9XX3W.css +1 -0
- package/dashboard/dist/assets/mcp-BzVpaaKF.js +2 -0
- package/dashboard/dist/assets/{mcp-blCW6IL7.js.map → mcp-BzVpaaKF.js.map} +1 -1
- package/dashboard/dist/assets/mcp-query-wTuxTTCV.js +2 -0
- package/dashboard/dist/assets/mcp-query-wTuxTTCV.js.map +1 -0
- package/dashboard/dist/assets/{mcp-runs-ChPbpvXK.js → mcp-runs-DmXYJD19.js} +2 -2
- package/dashboard/dist/assets/{mcp-runs-ChPbpvXK.js.map → mcp-runs-DmXYJD19.js.map} +1 -1
- package/dashboard/dist/assets/namespaces-DoGa7jc7.js +2 -0
- package/dashboard/dist/assets/{namespaces-BgbaC3ow.js.map → namespaces-DoGa7jc7.js.map} +1 -1
- package/dashboard/dist/assets/{roles-ZNrqqnQl.js → roles-wCdQ2Z7k.js} +2 -2
- package/dashboard/dist/assets/{roles-ZNrqqnQl.js.map → roles-wCdQ2Z7k.js.map} +1 -1
- package/dashboard/dist/assets/settings-DDe_L7JT.js +2 -0
- package/dashboard/dist/assets/{settings-eBRSE0mQ.js.map → settings-DDe_L7JT.js.map} +1 -1
- package/dashboard/dist/assets/tasks-3Hih8Bt7.js +2 -0
- package/dashboard/dist/assets/{tasks-tRqClPns.js.map → tasks-3Hih8Bt7.js.map} +1 -1
- package/dashboard/dist/assets/{useFilterParams-BaXUAkYK.js → useFilterParams-BUyLHcx_.js} +2 -2
- package/dashboard/dist/assets/{useFilterParams-BaXUAkYK.js.map → useFilterParams-BUyLHcx_.js.map} +1 -1
- package/dashboard/dist/assets/{useNatsEvents-Xr43X1fG.js → useNatsEvents-DeGKHFTX.js} +2 -2
- package/dashboard/dist/assets/{useNatsEvents-Xr43X1fG.js.map → useNatsEvents-DeGKHFTX.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BO51u8tm.js → useYamlActivityEvents-B5dHec6Y.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BO51u8tm.js.map → useYamlActivityEvents-B5dHec6Y.js.map} +1 -1
- package/dashboard/dist/assets/{users-tMvNyOo8.js → users-BTagPmGW.js} +2 -2
- package/dashboard/dist/assets/{users-tMvNyOo8.js.map → users-BTagPmGW.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-ZTAKVwGc.js → vendor-icons-DCLlGYO9.js} +112 -57
- package/dashboard/dist/assets/vendor-icons-DCLlGYO9.js.map +1 -0
- package/dashboard/dist/assets/vendor-query-DLp59M9_.js +35 -0
- package/dashboard/dist/assets/vendor-query-DLp59M9_.js.map +1 -0
- package/dashboard/dist/assets/vendor-react-Co3Y8ikm.js +26 -0
- package/dashboard/dist/assets/vendor-react-Co3Y8ikm.js.map +1 -0
- package/dashboard/dist/assets/{workflows-Cc4VHcrp.js → workflows-B20dR3NE.js} +2 -2
- package/dashboard/dist/assets/{workflows-Cc4VHcrp.js.map → workflows-B20dR3NE.js.map} +1 -1
- package/dashboard/dist/assets/yaml-workflows-CaLPMQha.js +2 -0
- package/dashboard/dist/assets/yaml-workflows-CaLPMQha.js.map +1 -0
- package/dashboard/dist/index.html +5 -5
- package/docs/api/dba.md +81 -0
- package/docs/api/escalations.md +575 -0
- package/docs/api/exports.md +170 -0
- package/docs/api/maintenance.md +93 -0
- package/docs/api/mcp-runs.md +128 -0
- package/docs/api/mcp-servers.md +195 -0
- package/docs/api/namespaces.md +48 -0
- package/docs/api/roles.md +390 -0
- package/docs/api/service-accounts.md +188 -0
- package/docs/api/settings.md +33 -0
- package/docs/api/tasks.md +167 -0
- package/docs/api/users.md +180 -0
- package/docs/api/workflows.md +616 -0
- package/docs/api/yaml-workflows.md +312 -0
- package/docs/architecture.md +221 -0
- package/docs/auth.md +181 -0
- package/docs/cloud.md +272 -0
- package/docs/compilation.md +136 -0
- package/docs/contributing.md +56 -0
- package/docs/dashboard.md +145 -0
- package/docs/data.md +478 -0
- package/docs/escalation-strategies.md +264 -0
- package/docs/events.md +251 -0
- package/docs/iam.md +222 -0
- package/docs/img/01-login.png +0 -0
- package/docs/img/02-dashboard-home.png +0 -0
- package/docs/img/03-processes-list.png +0 -0
- package/docs/img/04-escalations-list.png +0 -0
- package/docs/img/05-mcp-servers.png +0 -0
- package/docs/img/06-mcp-pipelines.png +0 -0
- package/docs/img/07-workflows-list.png +0 -0
- package/docs/img/compilation/01-query-submit.png +0 -0
- package/docs/img/compilation/02-mcp-servers.png +0 -0
- package/docs/img/compilation/03-query-completed.png +0 -0
- package/docs/img/compilation/04-wizard-original.png +0 -0
- package/docs/img/compilation/05-wizard-timeline.png +0 -0
- package/docs/img/compilation/06-wizard-profile.png +0 -0
- package/docs/img/compilation/07-wizard-deploy.png +0 -0
- package/docs/img/compilation/08-wizard-test-modal.png +0 -0
- package/docs/img/compilation/09-wizard-test-compare.png +0 -0
- package/docs/img/compilation/10-wizard-verify.png +0 -0
- package/docs/logging.md +110 -0
- package/docs/maintenance.md +221 -0
- package/docs/mcp.md +715 -0
- package/docs/oauth-and-delegation.md +469 -0
- package/docs/telemetry.md +144 -0
- package/docs/workflows.md +695 -0
- package/lib/db/schemas/015_knowledge.sql +23 -0
- package/package.json +8 -9
- package/build/services/db/index.d.ts +0 -3
- package/build/services/mcp/vision-server.d.ts +0 -15
- package/build/services/mcp/vision-server.js +0 -214
- package/build/system/mcp-servers/document-vision.js +0 -228
- package/build/system/mcp-servers/prompts.d.ts +0 -4
- package/build/system/mcp-servers/prompts.js +0 -10
- package/dashboard/dist/assets/AdminDashboard-jfacvOC7.js +0 -2
- package/dashboard/dist/assets/AdminDashboard-jfacvOC7.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-BglLDoT8.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-BglLDoT8.js.map +0 -1
- package/dashboard/dist/assets/BotPicker-D6FYW1Gt.js +0 -2
- package/dashboard/dist/assets/CollapsibleSection-Cxk4wvjT.js +0 -2
- package/dashboard/dist/assets/ConfirmDeleteModal-FSXyKjaB.js +0 -2
- package/dashboard/dist/assets/CopyableId-CBdxWfp8.js +0 -2
- package/dashboard/dist/assets/CredentialsPage-Ikzsot0w.js +0 -2
- package/dashboard/dist/assets/CustomDurationPicker-CAninCbl.js +0 -2
- package/dashboard/dist/assets/DataTable-BDn1WBHS.js +0 -2
- package/dashboard/dist/assets/DataTable-BDn1WBHS.js.map +0 -1
- package/dashboard/dist/assets/EmptyState-2CmV-IaS.js +0 -2
- package/dashboard/dist/assets/EscalationsOverview-GXYFPASS.js +0 -2
- package/dashboard/dist/assets/EventTable-B01oJf6Y.js +0 -2
- package/dashboard/dist/assets/Field-DuFBAYhu.js +0 -2
- package/dashboard/dist/assets/Field-DuFBAYhu.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-Ck4K4rzu.js +0 -2
- package/dashboard/dist/assets/McpOverview-JkvRcX2e.js +0 -2
- package/dashboard/dist/assets/McpQueryDetailPage-CUMqhQdS.js +0 -2
- package/dashboard/dist/assets/McpQueryDetailPage-CUMqhQdS.js.map +0 -1
- package/dashboard/dist/assets/McpQueryPage-DRRhw4nN.js +0 -2
- package/dashboard/dist/assets/McpQueryPage-DRRhw4nN.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-CmPs5EvE.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-CmPs5EvE.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage-Dl5Y2u6k.js +0 -2
- package/dashboard/dist/assets/McpRunsPage-Dl5Y2u6k.js.map +0 -1
- package/dashboard/dist/assets/Modal-B4rbIVAn.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-B56il28q.js +0 -2
- package/dashboard/dist/assets/OperatorDashboard-B56il28q.js.map +0 -1
- package/dashboard/dist/assets/PageHeader-CpWFly5S.js +0 -2
- package/dashboard/dist/assets/PageHeader-CpWFly5S.js.map +0 -1
- package/dashboard/dist/assets/PriorityBadge-DfQY9St9.js +0 -2
- package/dashboard/dist/assets/ProcessDetailPage-CMLq4M7D.js +0 -2
- package/dashboard/dist/assets/ProcessDetailPage-CMLq4M7D.js.map +0 -1
- package/dashboard/dist/assets/ProcessesListPage-CZ_HF06v.js +0 -2
- package/dashboard/dist/assets/ProcessesListPage-CZ_HF06v.js.map +0 -1
- package/dashboard/dist/assets/RolePill-BTPa8L-P.js +0 -2
- package/dashboard/dist/assets/RolesPage-9grZW7yR.js +0 -2
- package/dashboard/dist/assets/RolesPage-9grZW7yR.js.map +0 -1
- package/dashboard/dist/assets/RowActions-Dg-Fsm5O.js +0 -2
- package/dashboard/dist/assets/SimpleMarkdown-CBlvaWP4.js +0 -4
- package/dashboard/dist/assets/SimpleMarkdown-CBlvaWP4.js.map +0 -1
- package/dashboard/dist/assets/StatCard-DlgF0CJC.js +0 -2
- package/dashboard/dist/assets/StatusBadge-TlC4jiig.js +0 -2
- package/dashboard/dist/assets/StatusBadge-TlC4jiig.js.map +0 -1
- package/dashboard/dist/assets/StickyPagination-F9FZsRy9.js +0 -2
- package/dashboard/dist/assets/SwimlaneTimeline-7SiwATsZ.js +0 -2
- package/dashboard/dist/assets/SwimlaneTimeline-7SiwATsZ.js.map +0 -1
- package/dashboard/dist/assets/TaskDetailPage-CbPVTakt.js +0 -2
- package/dashboard/dist/assets/TaskDetailPage-CbPVTakt.js.map +0 -1
- package/dashboard/dist/assets/TaskQueuePill-awmtb0qw.js +0 -2
- package/dashboard/dist/assets/TasksListPage-C_QF23c1.js +0 -2
- package/dashboard/dist/assets/TimeAgo-UPG6DoH8.js +0 -2
- package/dashboard/dist/assets/TimeAgo-UPG6DoH8.js.map +0 -1
- package/dashboard/dist/assets/TimestampCell-DoWMKg6w.js +0 -2
- package/dashboard/dist/assets/TimestampCell-DoWMKg6w.js.map +0 -1
- package/dashboard/dist/assets/UserName-DaP4YAKr.js +0 -2
- package/dashboard/dist/assets/VersionHistory-Bt7WBr6m.js +0 -5
- package/dashboard/dist/assets/VersionHistory-Bt7WBr6m.js.map +0 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-DjtAQ3hy.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-DjtAQ3hy.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-CCDSVaQj.js +0 -2
- package/dashboard/dist/assets/WorkflowPill-CCDSVaQj.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsDashboard-D8z9uBNB.js +0 -2
- package/dashboard/dist/assets/WorkflowsDashboard-D8z9uBNB.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsOverview-D9OzzQqw.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowDetailPage-DrDvvP62.js +0 -3
- package/dashboard/dist/assets/YamlWorkflowDetailPage-DrDvvP62.js.map +0 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-COqiNCQK.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-COqiNCQK.js.map +0 -1
- package/dashboard/dist/assets/constants-CgaZfe5d.js +0 -2
- package/dashboard/dist/assets/constants-CgaZfe5d.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-D6aqStaY.js +0 -2
- package/dashboard/dist/assets/escalation-qalymbKB.js +0 -2
- package/dashboard/dist/assets/escalation-qalymbKB.js.map +0 -1
- package/dashboard/dist/assets/format-gXZXQ-HJ.js +0 -2
- package/dashboard/dist/assets/format-gXZXQ-HJ.js.map +0 -1
- package/dashboard/dist/assets/helpers-0gSleuzT.js +0 -2
- package/dashboard/dist/assets/helpers-0gSleuzT.js.map +0 -1
- package/dashboard/dist/assets/index-BWvMHed7.js +0 -6
- package/dashboard/dist/assets/index-BWvMHed7.js.map +0 -1
- package/dashboard/dist/assets/index-BaszoPO_.css +0 -1
- package/dashboard/dist/assets/index-Cn2jyj9A.js +0 -2
- package/dashboard/dist/assets/index-Cn2jyj9A.js.map +0 -1
- package/dashboard/dist/assets/index-D8VH6K8B.js +0 -54
- package/dashboard/dist/assets/index-D8VH6K8B.js.map +0 -1
- package/dashboard/dist/assets/index-D9SYwJsi.js +0 -3
- package/dashboard/dist/assets/index-D9SYwJsi.js.map +0 -1
- package/dashboard/dist/assets/index-DTPzZr_X.js +0 -2
- package/dashboard/dist/assets/index-D_6AB5BE.js +0 -2
- package/dashboard/dist/assets/index-D_6AB5BE.js.map +0 -1
- package/dashboard/dist/assets/index-S9Ks2Lj2.js +0 -2
- package/dashboard/dist/assets/index-S9Ks2Lj2.js.map +0 -1
- package/dashboard/dist/assets/index-X85K5bHC.js +0 -17
- package/dashboard/dist/assets/index-rjmgHlSH.js +0 -2
- package/dashboard/dist/assets/index-rjmgHlSH.js.map +0 -1
- package/dashboard/dist/assets/mcp-blCW6IL7.js +0 -2
- package/dashboard/dist/assets/mcp-query-DoAyPbjC.js +0 -2
- package/dashboard/dist/assets/mcp-query-DoAyPbjC.js.map +0 -1
- package/dashboard/dist/assets/namespaces-BgbaC3ow.js +0 -2
- package/dashboard/dist/assets/settings-eBRSE0mQ.js +0 -2
- package/dashboard/dist/assets/tasks-tRqClPns.js +0 -2
- package/dashboard/dist/assets/vendor-icons-ZTAKVwGc.js.map +0 -1
- package/dashboard/dist/assets/vendor-query-B2UbickB.js +0 -18
- package/dashboard/dist/assets/vendor-query-B2UbickB.js.map +0 -1
- package/dashboard/dist/assets/vendor-react-Cw8Gy8NJ.js +0 -22
- package/dashboard/dist/assets/vendor-react-Cw8Gy8NJ.js.map +0 -1
- package/dashboard/dist/assets/yaml-workflows-BL4V5CQy.js +0 -2
- package/dashboard/dist/assets/yaml-workflows-BL4V5CQy.js.map +0 -1
- /package/build/{services → lib}/db/migrate.d.ts +0 -0
- /package/build/{services → lib}/events/index.d.ts +0 -0
- /package/build/{services → lib}/events/index.js +0 -0
- /package/build/{services → lib}/events/memory.d.ts +0 -0
- /package/build/{services → lib}/events/memory.js +0 -0
- /package/build/{services → lib}/events/nats.d.ts +0 -0
- /package/build/{services → lib}/events/nats.js +0 -0
- /package/build/{services → lib}/events/publish.d.ts +0 -0
- /package/build/{services → lib}/events/publish.js +0 -0
- /package/build/{services → lib}/events/socketio.d.ts +0 -0
- /package/build/{services → lib}/events/socketio.js +0 -0
- /package/build/{services → lib}/logger/index.d.ts +0 -0
- /package/build/{services → lib}/logger/index.js +0 -0
- /package/build/{services → lib}/logger/pino.d.ts +0 -0
- /package/build/{services → lib}/logger/pino.js +0 -0
- /package/build/{services → lib}/storage/index.d.ts +0 -0
- /package/build/{services → lib}/storage/index.js +0 -0
- /package/build/{services → lib}/storage/local.d.ts +0 -0
- /package/build/{services → lib}/storage/local.js +0 -0
- /package/build/{services → lib}/storage/s3.d.ts +0 -0
- /package/build/{services → lib}/storage/s3.js +0 -0
- /package/build/{services → lib}/storage/types.d.ts +0 -0
- /package/build/{services → lib}/storage/types.js +0 -0
- /package/build/{services → lib}/telemetry/index.d.ts +0 -0
- /package/build/{services → lib}/telemetry/index.js +0 -0
- /package/{services → lib}/db/README.md +0 -0
- /package/{services → lib}/db/schemas/001_schema.sql +0 -0
- /package/{services → lib}/db/schemas/002_seed.sql +0 -0
- /package/{services → lib}/db/schemas/003_workflow_discovery.sql +0 -0
- /package/{services → lib}/db/schemas/004_query_router.sql +0 -0
- /package/{services → lib}/db/schemas/005_triage_router.sql +0 -0
- /package/{services → lib}/db/schemas/006_oauth.sql +0 -0
- /package/{services → lib}/db/schemas/007_security.sql +0 -0
- /package/{services → lib}/db/schemas/008_bot_accounts.sql +0 -0
- /package/{services → lib}/db/schemas/009_audit_trail.sql +0 -0
- /package/{services → lib}/db/schemas/010_credential_providers.sql +0 -0
- /package/{services → lib}/db/schemas/011_system_workflow_configs.sql +0 -0
- /package/{services → lib}/db/schemas/012_drop_modality.sql +0 -0
- /package/{services → lib}/db/schemas/013_execute_as.sql +0 -0
- /package/{services → lib}/db/schemas/014_ephemeral_credentials.sql +0 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# OAuth, Delegation, and External MCP Server Authentication
|
|
2
|
+
|
|
3
|
+
Long Tail supports OAuth login for the dashboard, delegated authority for MCP tools acting on behalf of users, and service tokens for external MCP servers running in separate containers. This document covers the full chain from user authentication through tool-level credential delegation, and how to test it locally.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Three layers of authentication work together:
|
|
8
|
+
|
|
9
|
+
1. **Identity OAuth** — Users sign in to the dashboard with Google, GitHub, or Microsoft. The system issues a JWT (same as password login). OAuth tokens are stored encrypted for later use.
|
|
10
|
+
|
|
11
|
+
2. **Delegation tokens** — When a workflow calls an MCP tool on behalf of a user, it creates a short-lived, scoped JWT. The tool receives this token and can use it to access user-specific resources (like the user's Google API credentials).
|
|
12
|
+
|
|
13
|
+
3. **Service tokens** — External MCP servers authenticate to Long Tail with long-lived API keys. Combined with delegation tokens, they can act on behalf of users with least-privilege scoping.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
User logs in via OAuth
|
|
17
|
+
│
|
|
18
|
+
▼
|
|
19
|
+
JWT issued (same as password login)
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
Workflow started → envelope carries userId
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
Activity creates delegation token (scoped, 5-min TTL)
|
|
26
|
+
│
|
|
27
|
+
▼
|
|
28
|
+
MCP tool receives _auth.token in args
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
External server validates token, calls delegation API
|
|
32
|
+
│
|
|
33
|
+
▼
|
|
34
|
+
Gets user's fresh OAuth access token → calls external API
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## OAuth Login
|
|
38
|
+
|
|
39
|
+
### Supported Providers
|
|
40
|
+
|
|
41
|
+
- **Google** — OpenID Connect with PKCE
|
|
42
|
+
- **GitHub** — OAuth2 authorization code
|
|
43
|
+
- **Microsoft** — Entra ID with PKCE
|
|
44
|
+
- **Mock** — Test provider for local development (no real accounts needed)
|
|
45
|
+
|
|
46
|
+
### Configuration
|
|
47
|
+
|
|
48
|
+
Set environment variables for each provider you want to enable:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Encryption key for OAuth token storage (required, 32 bytes as hex)
|
|
52
|
+
OAUTH_ENCRYPTION_KEY=a1b2c3d4e5f6... # 64 hex characters
|
|
53
|
+
|
|
54
|
+
# Google
|
|
55
|
+
OAUTH_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
|
|
56
|
+
OAUTH_GOOGLE_CLIENT_SECRET=your-client-secret
|
|
57
|
+
|
|
58
|
+
# GitHub
|
|
59
|
+
OAUTH_GITHUB_CLIENT_ID=your-github-client-id
|
|
60
|
+
OAUTH_GITHUB_CLIENT_SECRET=your-github-client-secret
|
|
61
|
+
|
|
62
|
+
# Microsoft
|
|
63
|
+
OAUTH_MICROSOFT_CLIENT_ID=your-azure-app-id
|
|
64
|
+
OAUTH_MICROSOFT_CLIENT_SECRET=your-azure-secret
|
|
65
|
+
OAUTH_MICROSOFT_TENANT_ID=common # or your tenant ID
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
No environment variables set = no OAuth buttons shown on the login page. Password login always works.
|
|
69
|
+
|
|
70
|
+
### Startup Config
|
|
71
|
+
|
|
72
|
+
OAuth can also be configured programmatically:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
await start({
|
|
76
|
+
database: { connectionString: process.env.DATABASE_URL },
|
|
77
|
+
auth: {
|
|
78
|
+
secret: process.env.JWT_SECRET,
|
|
79
|
+
oauth: {
|
|
80
|
+
encryptionKey: process.env.OAUTH_ENCRYPTION_KEY,
|
|
81
|
+
autoProvision: true, // create user on first OAuth login
|
|
82
|
+
defaultRoleType: 'member', // role for auto-provisioned users
|
|
83
|
+
providers: [
|
|
84
|
+
{
|
|
85
|
+
provider: 'google',
|
|
86
|
+
clientId: process.env.OAUTH_GOOGLE_CLIENT_ID!,
|
|
87
|
+
clientSecret: process.env.OAUTH_GOOGLE_CLIENT_SECRET!,
|
|
88
|
+
scopes: ['openid', 'email', 'profile'],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### How It Works
|
|
97
|
+
|
|
98
|
+
1. The login page fetches available providers from `GET /api/auth/oauth/providers`.
|
|
99
|
+
2. User clicks "Sign in with Google" → browser redirects to `GET /api/auth/oauth/google`.
|
|
100
|
+
3. Backend generates CSRF state + PKCE code verifier, redirects to Google's consent screen.
|
|
101
|
+
4. Google redirects back to `GET /api/auth/oauth/google/callback` with an authorization code.
|
|
102
|
+
5. Backend exchanges the code for tokens, fetches user info (email, name).
|
|
103
|
+
6. If the user exists (matched by email or OAuth provider ID), they're logged in. If not and `autoProvision` is true, a new user is created.
|
|
104
|
+
7. OAuth tokens are encrypted (AES-256-GCM) and stored in `lt_oauth_tokens`.
|
|
105
|
+
8. A JWT is issued and the browser redirects to `/?token=<jwt>`.
|
|
106
|
+
9. The dashboard's `useOAuthCallback` hook picks up the token and completes login.
|
|
107
|
+
|
|
108
|
+
### Token Storage
|
|
109
|
+
|
|
110
|
+
OAuth access and refresh tokens are encrypted at rest using AES-256-GCM. The encryption key comes from `OAUTH_ENCRYPTION_KEY` (environment variable) or `auth.oauth.encryptionKey` (startup config).
|
|
111
|
+
|
|
112
|
+
The `lt_oauth_tokens` table stores one token set per user per provider. Tokens are automatically refreshed when expired (for providers that support refresh tokens).
|
|
113
|
+
|
|
114
|
+
## User Context Propagation
|
|
115
|
+
|
|
116
|
+
When a workflow is started via the API, the authenticated user's ID is injected into the envelope and propagated through two layers of `AsyncLocalStorage`:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
HTTP request (req.auth.userId)
|
|
120
|
+
→ LTEnvelope.lt.userId
|
|
121
|
+
→ OrchestratorContext.userId (for executeLT routing)
|
|
122
|
+
→ ToolContext.principal.id (for universal identity access)
|
|
123
|
+
→ Activities read via getToolContext()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The interceptor wraps every workflow in both `runWithOrchestratorContext` and `runWithToolContext`. The `ToolContext` resolves the user's roles from the database, mints a delegation token, and makes the full identity available to any activity — regardless of whether it was invoked as a proxy activity, an MCP server tool, or a YAML workflow worker.
|
|
127
|
+
|
|
128
|
+
For cron-triggered workflows (no HTTP request), `userId` is `undefined`. Activities that require user context should check for this and fail gracefully.
|
|
129
|
+
|
|
130
|
+
### ToolContext
|
|
131
|
+
|
|
132
|
+
The `ToolContext` is the universal identity object. Activities call `getToolContext()` to access identity without knowing how they were invoked:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { getToolContext } from './services/iam/context';
|
|
136
|
+
|
|
137
|
+
const ctx = getToolContext();
|
|
138
|
+
if (ctx) {
|
|
139
|
+
console.log(ctx.principal.id); // user or bot UUID
|
|
140
|
+
console.log(ctx.principal.type); // 'user' or 'bot'
|
|
141
|
+
console.log(ctx.principal.roles); // ['reviewer', 'engineer']
|
|
142
|
+
console.log(ctx.credentials.delegationToken); // scoped JWT
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The MCP client (`callServerTool`) also reads `ToolContext` automatically. When no explicit `authContext` is passed, it derives `_auth` from the ambient context. This closes the identity gap for YAML workflow workers, which previously had no auth propagation.
|
|
147
|
+
|
|
148
|
+
## Delegation Tokens
|
|
149
|
+
|
|
150
|
+
Delegation tokens are scoped, short-lived JWTs that authorize MCP tools to act on behalf of a user.
|
|
151
|
+
|
|
152
|
+
### Creating a Delegation Token
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { createDelegationToken } from './services/auth/delegation';
|
|
156
|
+
|
|
157
|
+
const token = createDelegationToken(
|
|
158
|
+
'user-123', // userId
|
|
159
|
+
['oauth:google:read', 'files:read'], // scopes
|
|
160
|
+
300, // TTL in seconds (default: 300, max: 3600)
|
|
161
|
+
{ workflowId: 'wf-abc', serverId: 'ext-server' }, // optional metadata
|
|
162
|
+
);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Token Structure
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"type": "delegation",
|
|
170
|
+
"sub": "user-123",
|
|
171
|
+
"scopes": ["oauth:google:read", "files:read"],
|
|
172
|
+
"workflowId": "wf-abc",
|
|
173
|
+
"serverId": "ext-server",
|
|
174
|
+
"iss": "long-tail",
|
|
175
|
+
"iat": 1711461600,
|
|
176
|
+
"exp": 1711461900
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### How Tools Receive Delegation Tokens
|
|
181
|
+
|
|
182
|
+
When a workflow activity calls an MCP tool, the framework automatically:
|
|
183
|
+
|
|
184
|
+
1. Reads `userId` from the `OrchestratorContext`.
|
|
185
|
+
2. Creates a delegation token with `['mcp:tool:call']` scope.
|
|
186
|
+
3. Passes it as `_auth: { userId, token }` in the tool's arguments.
|
|
187
|
+
|
|
188
|
+
Tools that don't need auth simply ignore the `_auth` field. External MCP servers extract `_auth.token` and use it to call back to Long Tail's delegation API.
|
|
189
|
+
|
|
190
|
+
### Validating a Delegation Token
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { validateDelegationToken, requireScope } from './services/auth/delegation';
|
|
194
|
+
|
|
195
|
+
const payload = validateDelegationToken(token);
|
|
196
|
+
requireScope(payload, 'oauth:google:read'); // throws if scope missing
|
|
197
|
+
console.log(payload.sub); // userId
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Delegation API
|
|
201
|
+
|
|
202
|
+
External MCP servers use these endpoints to access user-scoped resources:
|
|
203
|
+
|
|
204
|
+
### Get OAuth Access Token
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
GET /api/delegation/oauth/:provider/token
|
|
208
|
+
Authorization: Bearer <delegation-token>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Returns a fresh access token for the user identified in the delegation token. Requires scope `oauth:<provider>:read`.
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"access_token": "ya29.a0AfH6...",
|
|
216
|
+
"expires_at": "2024-03-26T18:00:00.000Z",
|
|
217
|
+
"scopes": ["openid", "email", "profile"],
|
|
218
|
+
"provider": "google"
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Validate Delegation Token
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
POST /api/delegation/validate
|
|
226
|
+
Authorization: Bearer <service-token>
|
|
227
|
+
Content-Type: application/json
|
|
228
|
+
|
|
229
|
+
{ "token": "<delegation-token>" }
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Returns the token's claims. Used by external servers to verify tokens without having `JWT_SECRET`.
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"valid": true,
|
|
237
|
+
"userId": "user-123",
|
|
238
|
+
"scopes": ["oauth:google:read"],
|
|
239
|
+
"workflowId": "wf-abc",
|
|
240
|
+
"expiresAt": "2024-03-26T17:05:00.000Z"
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Service Tokens
|
|
245
|
+
|
|
246
|
+
External MCP servers authenticate to Long Tail using service tokens — long-lived API keys prefixed with `lt_svc_`.
|
|
247
|
+
|
|
248
|
+
### Generating a Service Token
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
POST /api/mcp/servers/:id/service-token
|
|
252
|
+
Authorization: Bearer <admin-jwt>
|
|
253
|
+
|
|
254
|
+
{ "name": "ext-calendar-server", "scopes": ["delegation:validate"] }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Returns the raw token **once**. The system stores only a bcrypt hash.
|
|
258
|
+
|
|
259
|
+
### Using a Service Token
|
|
260
|
+
|
|
261
|
+
Include it as a Bearer token in requests to delegation endpoints:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
curl -H "Authorization: Bearer lt_svc_a1b2c3..." \
|
|
265
|
+
-H "Content-Type: application/json" \
|
|
266
|
+
-d '{"token": "<delegation-token>"}' \
|
|
267
|
+
http://localhost:3000/api/delegation/validate
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## External MCP Server Pattern
|
|
271
|
+
|
|
272
|
+
An external MCP server running in a separate container (or separate docker-compose) follows this pattern:
|
|
273
|
+
|
|
274
|
+
1. **Register** with Long Tail as an SSE-based MCP server.
|
|
275
|
+
2. **Receive a service token** from an admin.
|
|
276
|
+
3. **Accept tool calls** with `_auth.token` in the args.
|
|
277
|
+
4. **Validate** the delegation token against Long Tail's delegation API.
|
|
278
|
+
5. **Fetch** user-scoped credentials (OAuth tokens, files, etc.) via the delegation API.
|
|
279
|
+
6. **Execute** the operation and return results.
|
|
280
|
+
|
|
281
|
+
See `examples/external-mcp-server/` for a working example.
|
|
282
|
+
|
|
283
|
+
### Docker Compose Overlay
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Start the main stack + external MCP server
|
|
287
|
+
docker compose -f docker-compose.yml -f docker-compose.external.yml up -d --build
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
The external server connects to the same Docker network and calls back to `http://long-tail:3000`.
|
|
291
|
+
|
|
292
|
+
## Testing Locally
|
|
293
|
+
|
|
294
|
+
### 1. Generate an Encryption Key
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Generate a 32-byte hex key
|
|
298
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 2. Test with Mock OAuth Provider
|
|
302
|
+
|
|
303
|
+
The mock OAuth provider is a lightweight Express server that implements the OAuth2 authorization code flow without requiring real provider credentials. It auto-authorizes as a preconfigured test user.
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Start the stack with the mock OAuth provider
|
|
307
|
+
docker compose --profile test down -v
|
|
308
|
+
docker compose --profile test up -d --build
|
|
309
|
+
|
|
310
|
+
# Wait for services to be healthy
|
|
311
|
+
docker compose --profile test ps
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Set these environment variables on the `long-tail` service (add to docker-compose.yml or use `.env`):
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
OAUTH_ENCRYPTION_KEY=<your-64-hex-char-key>
|
|
318
|
+
OAUTH_MOCK_CLIENT_ID=test-client
|
|
319
|
+
OAUTH_MOCK_CLIENT_SECRET=test-secret
|
|
320
|
+
MOCK_OAUTH_AUTH_URL=http://mock-oauth:9080/authorize
|
|
321
|
+
MOCK_OAUTH_TOKEN_URL=http://mock-oauth:9080/token
|
|
322
|
+
MOCK_OAUTH_USERINFO_URL=http://mock-oauth:9080/userinfo
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Then:
|
|
326
|
+
|
|
327
|
+
1. Navigate to `http://localhost:3000/login`.
|
|
328
|
+
2. Click "Sign in with Mock (Test)".
|
|
329
|
+
3. The mock provider auto-authorizes and redirects back.
|
|
330
|
+
4. You land on the dashboard, logged in as `alice@test.local`.
|
|
331
|
+
|
|
332
|
+
### 3. Test the Full Delegation Chain
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
# 1. Log in (password or OAuth) and get a JWT
|
|
336
|
+
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/login \
|
|
337
|
+
-H 'Content-Type: application/json' \
|
|
338
|
+
-d '{"username":"superadmin","password":"l0ngt@1l"}' | jq -r .token)
|
|
339
|
+
|
|
340
|
+
# 2. Start an mcpQuery workflow (userId is injected into the envelope)
|
|
341
|
+
WORKFLOW_ID=$(curl -s -X POST http://localhost:3000/api/insight \
|
|
342
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
343
|
+
-H 'Content-Type: application/json' \
|
|
344
|
+
-d '{"prompt":"List all files","wait":false}' | jq -r .workflow_id)
|
|
345
|
+
|
|
346
|
+
echo "Workflow $WORKFLOW_ID started with userId in envelope"
|
|
347
|
+
|
|
348
|
+
# 3. The workflow's activities automatically create delegation tokens
|
|
349
|
+
# when calling MCP tools. Check logs for:
|
|
350
|
+
# [lt-mcp:...] tool call received _auth.userId = <user-id>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 4. Test External MCP Server Delegation
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# Start with external server overlay
|
|
357
|
+
docker compose -f docker-compose.yml -f docker-compose.external.yml up -d --build
|
|
358
|
+
|
|
359
|
+
# Generate a service token for the external server (requires admin JWT)
|
|
360
|
+
SERVICE_TOKEN=$(curl -s -X POST http://localhost:3000/api/mcp/servers/<server-id>/service-token \
|
|
361
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
362
|
+
-H 'Content-Type: application/json' \
|
|
363
|
+
-d '{"name":"ext-test","scopes":["delegation:validate"]}' | jq -r .rawToken)
|
|
364
|
+
|
|
365
|
+
# Create a delegation token manually (for testing)
|
|
366
|
+
DELEGATION=$(node -e "
|
|
367
|
+
const {createDelegationToken} = require('./services/auth/delegation');
|
|
368
|
+
console.log(createDelegationToken('$USER_ID', ['oauth:google:read'], 300));
|
|
369
|
+
")
|
|
370
|
+
|
|
371
|
+
# Call the external MCP server's tool
|
|
372
|
+
curl -X POST http://localhost:9090/tools/fetch_external_data \
|
|
373
|
+
-H 'Content-Type: application/json' \
|
|
374
|
+
-d "{
|
|
375
|
+
\"provider\": \"google\",
|
|
376
|
+
\"query\": \"my calendar events\",
|
|
377
|
+
\"_auth\": { \"token\": \"$DELEGATION\" }
|
|
378
|
+
}"
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### 5. Run Unit Tests
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
# Delegation token tests (9 tests)
|
|
385
|
+
npx vitest run tests/delegation-tokens.test.ts
|
|
386
|
+
|
|
387
|
+
# OAuth tests (28 tests)
|
|
388
|
+
npx vitest run tests/oauth
|
|
389
|
+
|
|
390
|
+
# All backend tests (487 tests)
|
|
391
|
+
npx vitest run
|
|
392
|
+
|
|
393
|
+
# Frontend tests (520 tests)
|
|
394
|
+
cd dashboard && npx vitest run
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Security Model
|
|
398
|
+
|
|
399
|
+
### Least Privilege
|
|
400
|
+
|
|
401
|
+
| Token Type | Lifetime | Scope | Who Creates | Who Consumes |
|
|
402
|
+
|---|---|---|---|---|
|
|
403
|
+
| User JWT | 24 hours | Full API access | Login endpoint | Dashboard, API routes |
|
|
404
|
+
| Bot API key | Long-lived | Full API access (RBAC-scoped) | Admin | Programmatic clients, CI/CD |
|
|
405
|
+
| Delegation token | 5 minutes | Specific scopes (e.g., `oauth:google:read`) | Workflow activities | MCP tools, delegation API |
|
|
406
|
+
| Service token | Long-lived | Server-specific (e.g., `delegation:validate`) | Admin | External MCP servers |
|
|
407
|
+
| OAuth access token | Provider-set (~1hr) | Provider scopes (e.g., `email`, `profile`) | OAuth flow | External APIs |
|
|
408
|
+
|
|
409
|
+
### Trust Boundaries
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
┌──────────────────────────────────────────────┐
|
|
413
|
+
│ Long Tail Core (trusted) │
|
|
414
|
+
│ - User JWTs signed with JWT_SECRET │
|
|
415
|
+
│ - Delegation tokens signed with JWT_SECRET │
|
|
416
|
+
│ - OAuth tokens encrypted with AES-256-GCM │
|
|
417
|
+
│ - Service token hashes stored with bcrypt │
|
|
418
|
+
└────────────────────────┬─────────────────────┘
|
|
419
|
+
│
|
|
420
|
+
Delegation API (scoped access)
|
|
421
|
+
│
|
|
422
|
+
┌────────────────────────▼─────────────────────┐
|
|
423
|
+
│ External MCP Server (semi-trusted) │
|
|
424
|
+
│ - Has service token (server identity) │
|
|
425
|
+
│ - Receives delegation tokens (user scoping) │
|
|
426
|
+
│ - Can only access scoped resources │
|
|
427
|
+
│ - Cannot forge or extend token permissions │
|
|
428
|
+
└──────────────────────────────────────────────┘
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### What Delegation Tokens Cannot Do
|
|
432
|
+
|
|
433
|
+
- Access resources outside their declared scopes
|
|
434
|
+
- Be used after expiry (5-minute default, 1-hour max)
|
|
435
|
+
- Be refreshed or extended (create a new one instead)
|
|
436
|
+
- Authenticate as a different user
|
|
437
|
+
- Access the Admin API or user management endpoints
|
|
438
|
+
|
|
439
|
+
## Database Tables
|
|
440
|
+
|
|
441
|
+
| Table | Purpose |
|
|
442
|
+
|---|---|
|
|
443
|
+
| `lt_oauth_tokens` | Encrypted per-user, per-provider OAuth tokens |
|
|
444
|
+
| `lt_service_tokens` | Hashed service tokens for external MCP servers |
|
|
445
|
+
| `lt_bot_api_keys` | Hashed API keys for bot accounts |
|
|
446
|
+
| `lt_users.account_type` | Distinguishes `'user'` from `'bot'` accounts |
|
|
447
|
+
| `lt_users.oauth_provider` | Identity link: which OAuth provider the user signed up with |
|
|
448
|
+
| `lt_tasks.initiated_by` | Audit: which user or bot initiated the task (FK to `lt_users`) |
|
|
449
|
+
| `lt_tasks.principal_type` | Audit: `'user'` or `'bot'` |
|
|
450
|
+
| `lt_escalations.created_by` | Audit: which user initiated the escalation |
|
|
451
|
+
| `lt_mcp_servers.required_scopes` | Declares what scopes a server needs from delegation tokens |
|
|
452
|
+
|
|
453
|
+
## Environment Variables Reference
|
|
454
|
+
|
|
455
|
+
| Variable | Required | Default | Purpose |
|
|
456
|
+
|---|---|---|---|
|
|
457
|
+
| `OAUTH_ENCRYPTION_KEY` | For OAuth | — | 32-byte hex key for token encryption |
|
|
458
|
+
| `OAUTH_GOOGLE_CLIENT_ID` | No | — | Google OAuth client ID |
|
|
459
|
+
| `OAUTH_GOOGLE_CLIENT_SECRET` | No | — | Google OAuth client secret |
|
|
460
|
+
| `OAUTH_GITHUB_CLIENT_ID` | No | — | GitHub OAuth client ID |
|
|
461
|
+
| `OAUTH_GITHUB_CLIENT_SECRET` | No | — | GitHub OAuth client secret |
|
|
462
|
+
| `OAUTH_MICROSOFT_CLIENT_ID` | No | — | Microsoft OAuth client ID |
|
|
463
|
+
| `OAUTH_MICROSOFT_CLIENT_SECRET` | No | — | Microsoft OAuth client secret |
|
|
464
|
+
| `OAUTH_MICROSOFT_TENANT_ID` | No | `common` | Azure AD tenant |
|
|
465
|
+
| `OAUTH_MOCK_CLIENT_ID` | No | — | Mock provider client ID (testing) |
|
|
466
|
+
| `OAUTH_MOCK_CLIENT_SECRET` | No | — | Mock provider client secret (testing) |
|
|
467
|
+
| `MOCK_OAUTH_AUTH_URL` | No | `http://localhost:9080/authorize` | Mock provider authorization URL |
|
|
468
|
+
| `MOCK_OAUTH_TOKEN_URL` | No | `http://localhost:9080/token` | Mock provider token URL |
|
|
469
|
+
| `MOCK_OAUTH_USERINFO_URL` | No | `http://localhost:9080/userinfo` | Mock provider userinfo URL |
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Telemetry
|
|
2
|
+
|
|
3
|
+
Long Tail instruments workflow execution through OpenTelemetry. HotMesh, the underlying workflow engine, creates spans for workflow triggers, activity calls, stream routing, and errors. These spans are exported automatically once a telemetry adapter registers a global `TracerProvider`. No manual span creation is required in workflow or activity code.
|
|
4
|
+
|
|
5
|
+
The system has three parts: an adapter interface, a singleton registry, and one or more adapter implementations. Long Tail ships with a Honeycomb adapter. You can write your own for any OTLP-compatible backend.
|
|
6
|
+
|
|
7
|
+
## Configuration via start()
|
|
8
|
+
|
|
9
|
+
The simplest way to enable telemetry is through the `start()` config:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { start } from '@hotmeshio/long-tail';
|
|
13
|
+
|
|
14
|
+
// Built-in Honeycomb adapter
|
|
15
|
+
await start({
|
|
16
|
+
database: { connectionString: process.env.DATABASE_URL },
|
|
17
|
+
workers: [ ... ],
|
|
18
|
+
telemetry: { honeycomb: { apiKey: process.env.HONEYCOMB_API_KEY } },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Custom adapter
|
|
22
|
+
await start({
|
|
23
|
+
database: { connectionString: process.env.DATABASE_URL },
|
|
24
|
+
workers: [ ... ],
|
|
25
|
+
telemetry: { adapter: new DatadogAdapter() },
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`start()` handles initialization order automatically — the telemetry adapter is connected before workers start, ensuring spans are captured from the first workflow execution.
|
|
30
|
+
|
|
31
|
+
## Adapter Interface
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import type { LTTelemetryAdapter } from '@hotmeshio/long-tail';
|
|
35
|
+
|
|
36
|
+
interface LTTelemetryAdapter {
|
|
37
|
+
/** Initialize the OTEL SDK and register the global TracerProvider */
|
|
38
|
+
connect(): Promise<void>;
|
|
39
|
+
/** Flush pending spans and shut down the exporter */
|
|
40
|
+
disconnect(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The interface is deliberately minimal. `connect()` starts the OpenTelemetry SDK and registers the global `TracerProvider`. `disconnect()` flushes buffered spans and shuts down the SDK. All instrumentation happens inside HotMesh via `@opentelemetry/api` — the adapter's only job is to provide the provider and exporter.
|
|
45
|
+
|
|
46
|
+
## Registry
|
|
47
|
+
|
|
48
|
+
`telemetryRegistry` is a singleton that holds one adapter. Unlike the event registry (which supports multiple adapters), telemetry uses a single adapter because OpenTelemetry permits only one global `TracerProvider` at a time.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { telemetryRegistry } from '@hotmeshio/long-tail';
|
|
52
|
+
|
|
53
|
+
telemetryRegistry.register(adapter); // store the adapter
|
|
54
|
+
await telemetryRegistry.connect(); // delegate to adapter.connect()
|
|
55
|
+
await telemetryRegistry.disconnect(); // delegate to adapter.disconnect()
|
|
56
|
+
telemetryRegistry.clear(); // remove the adapter (used in tests)
|
|
57
|
+
telemetryRegistry.hasAdapter; // boolean — true if an adapter is registered
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`connect()` is idempotent. Calling it twice has no effect. `register()` replaces any previously registered adapter.
|
|
61
|
+
|
|
62
|
+
## Initialization Order
|
|
63
|
+
|
|
64
|
+
The registry is simple, but initialization order matters.
|
|
65
|
+
|
|
66
|
+
The adapter must be registered and connected **before** workers start. HotMesh creates its tracers during worker initialization. If no `TracerProvider` is registered at that point, spans are silently discarded for the lifetime of the process.
|
|
67
|
+
|
|
68
|
+
`start()` handles this automatically — it connects the telemetry adapter before creating any workers. If you register the adapter programmatically instead, ensure you call `connect()` before starting workers.
|
|
69
|
+
|
|
70
|
+
## Built-in Honeycomb Adapter
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { telemetryRegistry, HoneycombTelemetryAdapter } from '@hotmeshio/long-tail';
|
|
74
|
+
|
|
75
|
+
telemetryRegistry.register(new HoneycombTelemetryAdapter({
|
|
76
|
+
apiKey: process.env.HONEYCOMB_API_KEY,
|
|
77
|
+
serviceName: 'my-app',
|
|
78
|
+
}));
|
|
79
|
+
await telemetryRegistry.connect();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Constructor Options
|
|
83
|
+
|
|
84
|
+
| Option | Type | Default | Description |
|
|
85
|
+
|--------|------|---------|-------------|
|
|
86
|
+
| `apiKey` | `string` | `process.env.HONEYCOMB_API_KEY` | Honeycomb API key. If empty, `connect()` logs a warning and returns without starting the SDK. |
|
|
87
|
+
| `serviceName` | `string` | `'long-tail'` | The `service.name` resource attribute sent with every span. |
|
|
88
|
+
| `endpoint` | `string` | `'https://api.honeycomb.io'` | OTLP endpoint. Override for Honeycomb EU or a local collector. |
|
|
89
|
+
|
|
90
|
+
The adapter uses `@opentelemetry/sdk-node` with `@opentelemetry/exporter-trace-otlp-proto` (HTTP). It sends traces to `{endpoint}/v1/traces` with the API key in the `x-honeycomb-team` header.
|
|
91
|
+
|
|
92
|
+
## Custom Adapter
|
|
93
|
+
|
|
94
|
+
Any class that implements `LTTelemetryAdapter` works. The pattern is the same regardless of backend: initialize a `NodeSDK` with the appropriate exporter in `connect()`, shut it down in `disconnect()`.
|
|
95
|
+
|
|
96
|
+
### Datadog Example
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
100
|
+
import type { LTTelemetryAdapter } from '@hotmeshio/long-tail';
|
|
101
|
+
|
|
102
|
+
class DatadogAdapter implements LTTelemetryAdapter {
|
|
103
|
+
private sdk: NodeSDK | null = null;
|
|
104
|
+
|
|
105
|
+
async connect() {
|
|
106
|
+
this.sdk = new NodeSDK({ /* Datadog exporter config */ });
|
|
107
|
+
this.sdk.start();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async disconnect() {
|
|
111
|
+
await this.sdk?.shutdown();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Register it the same way:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
telemetryRegistry.register(new DatadogAdapter());
|
|
120
|
+
await telemetryRegistry.connect();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## HMSH_TELEMETRY Environment Variable
|
|
124
|
+
|
|
125
|
+
The `HMSH_TELEMETRY` environment variable controls span verbosity at the HotMesh engine level. It determines which spans HotMesh creates, independent of which backend receives them.
|
|
126
|
+
|
|
127
|
+
| Value | Spans emitted |
|
|
128
|
+
|-------|---------------|
|
|
129
|
+
| `info` | Workflow triggers, worker lifecycle, errors |
|
|
130
|
+
| `debug` | Everything in `info`, plus every activity execution |
|
|
131
|
+
| *(unset)* | No spans created |
|
|
132
|
+
|
|
133
|
+
Set this on the worker container. The API container does not execute workflows and does not need it.
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
HMSH_TELEMETRY=info # production — trigger and error spans
|
|
137
|
+
HMSH_TELEMETRY=debug # development — every activity call
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Pino and OTEL Correlation
|
|
141
|
+
|
|
142
|
+
When using both the telemetry adapter and the Pino logging adapter, add `@opentelemetry/instrumentation-pino` to your OTEL SDK configuration. This injects `trace_id` and `span_id` fields into every Pino log line, correlating logs with distributed traces in your observability backend.
|
|
143
|
+
|
|
144
|
+
The instrumentation must be included in the `NodeSDK` setup inside your telemetry adapter's `connect()` method — it hooks into Pino at the SDK level, not through Long Tail's logger registry.
|