deepline 0.3.89 → 0.3.90

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.
Files changed (211) hide show
  1. package/contracts/install-commands.json +29 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +120 -37
  3. package/dist/bundling-sources/sdk/src/index.ts +4 -0
  4. package/dist/bundling-sources/sdk/src/pagination.ts +25 -0
  5. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
  6. package/dist/bundling-sources/sdk/src/release.ts +16 -9
  7. package/dist/bundling-sources/sdk/src/types.ts +23 -0
  8. package/dist/bundling-sources/shared_libs/monitors/analytics-public.ts +10 -0
  9. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +3 -0
  10. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +4 -4
  11. package/dist/bundling-sources/shared_libs/monitors/inventory-reconciliation.ts +59 -0
  12. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +7 -9
  13. package/dist/bundling-sources/shared_libs/monitors/package.json +7 -0
  14. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +44 -2
  15. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +2 -2
  16. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +2 -2
  17. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +1 -1
  18. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +245 -0
  19. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-message.ts +38 -0
  20. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-ack-probe.ts +94 -0
  21. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-delivery.ts +60 -0
  22. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue.ts +60 -0
  23. package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +1 -1
  24. package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +2 -2
  25. package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +1 -1
  26. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +1 -1
  27. package/dist/bundling-sources/shared_libs/observability/build-context.ts +13 -0
  28. package/dist/bundling-sources/shared_libs/observability/log-metadata.ts +160 -0
  29. package/dist/bundling-sources/shared_libs/observability/request-context.ts +68 -0
  30. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +654 -0
  31. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +35 -0
  32. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +5 -0
  33. package/dist/bundling-sources/shared_libs/play-data-plane/neon-constants.ts +9 -0
  34. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +272 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +45 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +66 -1
  37. package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +0 -1
  38. package/dist/bundling-sources/shared_libs/play-runtime/bounceban-batching.ts +137 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +779 -140
  40. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +46 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/daytona-payload-contract.ts +68 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +103 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +725 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +29 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +23 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-invocation-fence.ts +442 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +3 -3
  48. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +18 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +9 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +1 -1
  51. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +1 -1
  52. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +66 -0
  53. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +145 -0
  54. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/ports.ts +21 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/postgres-store.ts +170 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +1322 -0
  57. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +2 -2
  58. package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +1 -1
  59. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +112 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +8 -0
  61. package/dist/bundling-sources/shared_libs/play-runtime/perf-trace.ts +127 -0
  62. package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +5 -0
  63. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +24 -1
  64. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +56 -0
  65. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +13 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/job.ts +41 -0
  67. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/ports.ts +17 -0
  68. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +54 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/contracts.ts +114 -0
  70. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/engine-suspension.ts +108 -0
  71. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/index.ts +36 -0
  72. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/job.ts +97 -0
  73. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/ports.ts +104 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/postgres-fence-adapter.ts +263 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +64 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/contracts.ts +29 -0
  77. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +56 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/index.ts +15 -0
  79. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/job.ts +65 -0
  80. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/ports.ts +17 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +42 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/index.ts +17 -0
  83. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +142 -0
  84. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/ports.ts +42 -0
  85. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/postgres-adapter.ts +102 -0
  86. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +60 -0
  87. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/index.ts +16 -0
  88. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +78 -0
  89. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +54 -0
  90. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +71 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +4 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +2 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +5 -8
  94. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +3 -5
  95. package/dist/bundling-sources/shared_libs/play-runtime/run-identity.ts +168 -0
  96. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +72 -9
  97. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +6 -12
  98. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +19 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/bundle.ts +0 -1
  100. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +14 -44
  101. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +57 -205
  102. package/dist/bundling-sources/shared_libs/play-runtime/runtime-authority.ts +201 -0
  103. package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +6 -0
  104. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +67 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/runtime-release-environment.ts +2 -0
  106. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-contract.ts +68 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +14 -2
  108. package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +108 -0
  109. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
  110. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +3 -0
  111. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
  112. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-deadline-reconciliation.ts +88 -0
  113. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +124 -0
  114. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-run-task.ts +68 -0
  115. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +193 -0
  116. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-lifecycle.ts +269 -0
  117. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-suffix.ts +73 -0
  118. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +6642 -0
  119. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +897 -0
  120. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-metrics.ts +120 -0
  121. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +76 -0
  122. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +476 -0
  123. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +47 -0
  124. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +147 -0
  125. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/index.ts +27 -0
  126. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/lazy.ts +50 -0
  127. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/play-run-recovery.ts +98 -0
  128. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-budget-state.ts +260 -0
  129. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +1416 -0
  130. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +1255 -0
  131. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +942 -0
  132. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +14636 -0
  133. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +888 -0
  134. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +355 -0
  135. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +46 -0
  136. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runner-push.ts +60 -0
  137. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-api-origin.ts +33 -0
  138. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-gateway-health.ts +64 -0
  139. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +835 -0
  140. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +1218 -0
  141. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-operation.ts +207 -0
  142. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-scheduler-schema.ts +10 -0
  143. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-capacity.ts +123 -0
  144. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-launch-read-observability.ts +78 -0
  145. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +169 -0
  146. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/terminal-contract.ts +20 -0
  147. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-queue-metrics.ts +34 -0
  148. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +249 -0
  149. package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +7 -0
  150. package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +296 -0
  151. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/native-batch.ts +3 -3
  152. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +20 -1
  153. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +60 -15
  154. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +20 -0
  155. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +12 -0
  156. package/dist/bundling-sources/shared_libs/play-runtime/vercel-protection.ts +14 -1
  157. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +165 -0
  158. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +15 -23
  159. package/dist/bundling-sources/shared_libs/play-runtime/workflow-executor-auth.ts +169 -0
  160. package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +122 -0
  161. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +2 -0
  162. package/dist/bundling-sources/shared_libs/plays/contracts.ts +2 -0
  163. package/dist/bundling-sources/shared_libs/plays/deployment-status.ts +1 -1
  164. package/dist/bundling-sources/shared_libs/plays/docflow.ts +1 -1
  165. package/dist/bundling-sources/shared_libs/plays/play-grep-search.ts +39 -0
  166. package/dist/bundling-sources/shared_libs/plays/share/copy.ts +271 -0
  167. package/dist/bundling-sources/shared_libs/plays/share/metrics.ts +140 -0
  168. package/dist/bundling-sources/shared_libs/plays/share/public-read-model.ts +86 -0
  169. package/dist/bundling-sources/shared_libs/plays/share/seo-quality.ts +181 -0
  170. package/dist/bundling-sources/shared_libs/plays/share/static-pipeline-summary.ts +658 -0
  171. package/dist/bundling-sources/shared_libs/plays/share/types.ts +197 -0
  172. package/dist/bundling-sources/shared_libs/plays/slack-hitl-timeout-error.ts +37 -0
  173. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +6 -1
  174. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
  175. package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +7 -1
  176. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +3 -2
  177. package/dist/bundling-sources/shared_libs/product-notifications/overflow.ts +18 -0
  178. package/dist/bundling-sources/shared_libs/product-notifications/rolling-limit.ts +24 -0
  179. package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +624 -0
  180. package/dist/bundling-sources/shared_libs/product-notifications/slack-payload.ts +140 -0
  181. package/dist/bundling-sources/shared_libs/product-notifications/slack-transport.ts +75 -0
  182. package/dist/bundling-sources/shared_libs/runtime-env.ts +6 -0
  183. package/dist/bundling-sources/shared_libs/security/email-blacklist.ts +42 -0
  184. package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +10 -3
  185. package/dist/bundling-sources/shared_libs/security/slack-sanitize.ts +133 -0
  186. package/dist/cli/getting-started.d.mts +52 -0
  187. package/dist/cli/getting-started.d.ts +52 -0
  188. package/dist/cli/getting-started.js +65 -0
  189. package/dist/cli/getting-started.mjs +36 -0
  190. package/dist/cli/index.d.mts +9 -0
  191. package/dist/cli/index.d.ts +9 -0
  192. package/dist/cli/index.js +545 -264
  193. package/dist/cli/index.mjs +543 -271
  194. package/dist/{compiler-manifest-DsLbQaew.d.mts → compiler-manifest-BaJfE-5H.d.mts} +5 -3
  195. package/dist/{compiler-manifest-DsLbQaew.d.ts → compiler-manifest-BaJfE-5H.d.ts} +5 -3
  196. package/dist/index.d.mts +81 -148
  197. package/dist/index.d.ts +81 -148
  198. package/dist/index.js +83 -26
  199. package/dist/index.mjs +83 -26
  200. package/dist/install-integrity.json +130 -2
  201. package/dist/monitor-fleet-contract.d.mts +138 -0
  202. package/dist/monitor-fleet-contract.d.ts +138 -0
  203. package/dist/monitor-fleet-contract.js +404 -0
  204. package/dist/monitor-fleet-contract.mjs +367 -0
  205. package/dist/plays/bundle-play-file.d.mts +2 -2
  206. package/dist/plays/bundle-play-file.d.ts +2 -2
  207. package/dist/release.d.mts +255 -0
  208. package/dist/release.d.ts +255 -0
  209. package/dist/release.js +215 -0
  210. package/dist/release.mjs +188 -0
  211. package/package.json +21 -4
@@ -0,0 +1,624 @@
1
+ import { isSyntheticActorEmail } from '@deepline/auth/synthetic-identity';
2
+ import { getCurrentRequestMetadata } from '../observability/log-metadata';
3
+ import { getRuntimeEnv } from '../play-runtime/runtime-env';
4
+ import { removeHttpHeadersFromSlackPayload } from '../security/slack-sanitize';
5
+ import { buildSlackActivityPayload, type SlackPayload } from './slack-payload';
6
+ import {
7
+ postMessageToSlack,
8
+ type SlackMessageOptions,
9
+ } from './slack-transport';
10
+
11
+ export type SlackChannelKey =
12
+ | 'user_signup'
13
+ | 'session_activity'
14
+ | 'error_activity'
15
+ | 'daily_activity_summary'
16
+ | 'integration_requests'
17
+ | 'deploy_events'
18
+ | 'provider_health'
19
+ | 'provider_alerts'
20
+ | 'sdk_cli_activity'
21
+ | 'sdk_cli_errors'
22
+ | 'sdk_cli_feedback'
23
+ | 'dashboard_feedback'
24
+ | 'python_cli_feedback'
25
+ | 'python_cli_session'
26
+ | 'monitor_activity'
27
+ | 'monitor_error_activity'
28
+ | 'plain_thread_activity';
29
+
30
+ export type SlackPayloadEnricher = (
31
+ payload: SlackPayload,
32
+ ) => SlackPayload | Promise<SlackPayload>;
33
+
34
+ export type SlackDeliveryOptions = {
35
+ enrichPayload?: SlackPayloadEnricher;
36
+ postMessage?: (
37
+ token: string,
38
+ channelId: string,
39
+ text: string,
40
+ options?: SlackMessageOptions,
41
+ ) => Promise<void>;
42
+ };
43
+
44
+ type ResolvedRequestMetadata = {
45
+ requestId: string | null;
46
+ requestPath: string | null;
47
+ };
48
+
49
+ const CHANNEL_WEBHOOK_ENV: Partial<Record<SlackChannelKey, string>> = {
50
+ session_activity: 'SLACK_SESSION_ACTIVITY_WEBHOOK_URL',
51
+ error_activity: 'SLACK_ERROR_ACTIVITY_WEBHOOK_URL',
52
+ daily_activity_summary: 'SLACK_DAILY_ACTIVITY_SUMMARY_WEBHOOK_URL',
53
+ integration_requests: 'SLACK_INTEGRATION_REQUEST_WEBHOOK_URL',
54
+ deploy_events: 'SLACK_DEV_WEBHOOK_URL',
55
+ provider_health: 'SLACK_PROVIDER_HEALTH_WEBHOOK_URL',
56
+ provider_alerts: 'SLACK_PROVIDER_ALERTS_WEBHOOK_URL',
57
+ monitor_activity: 'SLACK_MONITOR_ACTIVITY_WEBHOOK_URL',
58
+ monitor_error_activity: 'SLACK_MONITOR_ERROR_ACTIVITY_WEBHOOK_URL',
59
+ plain_thread_activity: 'SLACK_PLAIN_THREAD_ACTIVITY_WEBHOOK_URL',
60
+ };
61
+
62
+ const CHANNEL_WEBHOOK_FALLBACK_ENVS: Partial<
63
+ Record<SlackChannelKey, string[]>
64
+ > = {
65
+ deploy_events: ['SLACK_INTERNAL_BOTS_WEBHOOK_URL'],
66
+ };
67
+
68
+ const SLACK_DEEPLINE_REPORTING_BOT_TOKEN_ENV =
69
+ 'SLACK_DEEPLINE_REPORTING_BOT_TOKEN';
70
+ const SLACK_PROVIDER_ALERTS_CHANNEL_ID_ENV = 'SLACK_PROVIDER_ALERTS_CHANNEL_ID';
71
+ const SLACK_ERROR_ACTIVITY_CHANNEL_ID_ENV = 'SLACK_ERROR_ACTIVITY_CHANNEL_ID';
72
+ const SLACK_USER_SIGNUP_CHANNEL_ID_ENV = 'SLACK_USER_SIGNUP_CHANNEL_ID';
73
+ const SLACK_MONITOR_ACTIVITY_CHANNEL_ID_ENV =
74
+ 'SLACK_MONITOR_ACTIVITY_CHANNEL_ID';
75
+ const SLACK_MONITOR_ERROR_ACTIVITY_CHANNEL_ID_ENV =
76
+ 'SLACK_MONITOR_ERROR_ACTIVITY_CHANNEL_ID';
77
+ const DEFAULT_PROVIDER_ALERTS_CHANNEL_ID = 'C0B4QRC8NEM';
78
+ const DEFAULT_USER_SIGNUP_CHANNEL_ID = 'C0AGWVD2TNK';
79
+ const DEFAULT_MONITOR_ACTIVITY_CHANNEL_ID = 'C0BDRFY7NE7';
80
+ const DEFAULT_MONITOR_ERROR_ACTIVITY_CHANNEL_ID = 'C0BDGCEMLBZ';
81
+
82
+ export const SDK_CLI_ACTIVITY_SLACK_CHANNEL_ID = 'C0B7D7DB40Y';
83
+ export const SDK_CLI_ERRORS_SLACK_CHANNEL_ID = 'C0B6JUJ9QJW';
84
+ export const SDK_CLI_FEEDBACK_SLACK_CHANNEL_ID = 'C0B63EX130F';
85
+ export const DASHBOARD_FEEDBACK_SLACK_CHANNEL_ID =
86
+ SDK_CLI_FEEDBACK_SLACK_CHANNEL_ID;
87
+ export const PYTHON_CLI_FEEDBACK_SLACK_CHANNEL_ID = 'C0AFL96TPA8';
88
+ export const PYTHON_CLI_SESSION_SLACK_CHANNEL_ID = 'C0AJ6MEEL8Y';
89
+
90
+ const BLOCKED_SLACK_EMAIL_DOMAINS = [
91
+ 'getaero.io',
92
+ 'deepline.com',
93
+ 'deepline.local',
94
+ ];
95
+ const BLOCKED_SLACK_ACTOR_EMAILS = ['ci-auth@example.com'];
96
+ const DEFAULT_TIMEOUT_MS = 2500;
97
+ const VERCEL_LOGS_BASE_URL =
98
+ 'https://vercel.com/aero-team-0f650658/deepline-api/logs';
99
+ const CHANNEL_ALERT_LEVEL: Record<
100
+ SlackChannelKey,
101
+ 'error' | 'warning' | 'info'
102
+ > = {
103
+ user_signup: 'info',
104
+ session_activity: 'info',
105
+ error_activity: 'error',
106
+ daily_activity_summary: 'info',
107
+ integration_requests: 'info',
108
+ deploy_events: 'info',
109
+ provider_health: 'warning',
110
+ provider_alerts: 'error',
111
+ sdk_cli_activity: 'info',
112
+ sdk_cli_errors: 'error',
113
+ sdk_cli_feedback: 'info',
114
+ dashboard_feedback: 'info',
115
+ python_cli_feedback: 'info',
116
+ python_cli_session: 'info',
117
+ monitor_activity: 'info',
118
+ monitor_error_activity: 'error',
119
+ plain_thread_activity: 'info',
120
+ };
121
+
122
+ function normalizeText(value: unknown): string {
123
+ if (value === null || value === undefined) return '';
124
+ return String(value).trim();
125
+ }
126
+
127
+ function assertUnreachable(value: never): never {
128
+ throw new Error(`Unexpected Slack channel: ${String(value)}`);
129
+ }
130
+
131
+ function getSlackChannelEnvironmentRequirement(
132
+ channel: SlackChannelKey,
133
+ ): 'prod' | 'all' {
134
+ switch (channel) {
135
+ case 'user_signup':
136
+ case 'sdk_cli_activity':
137
+ case 'sdk_cli_errors':
138
+ return 'prod';
139
+ case 'session_activity':
140
+ case 'error_activity':
141
+ case 'daily_activity_summary':
142
+ case 'integration_requests':
143
+ case 'deploy_events':
144
+ case 'provider_alerts':
145
+ case 'provider_health':
146
+ case 'sdk_cli_feedback':
147
+ case 'dashboard_feedback':
148
+ case 'python_cli_feedback':
149
+ case 'python_cli_session':
150
+ case 'monitor_activity':
151
+ case 'monitor_error_activity':
152
+ case 'plain_thread_activity':
153
+ return 'all';
154
+ default:
155
+ return assertUnreachable(channel);
156
+ }
157
+ }
158
+
159
+ function resolveTimeoutMs(): number {
160
+ const raw = Number(process.env.SLACK_EVENTS_TIMEOUT_MS);
161
+ if (!Number.isFinite(raw) || raw <= 0) return DEFAULT_TIMEOUT_MS;
162
+ return Math.floor(raw);
163
+ }
164
+
165
+ function resolveWebhookUrl(channel: SlackChannelKey): string | null {
166
+ const envName = CHANNEL_WEBHOOK_ENV[channel];
167
+ if (!envName) return null;
168
+ const primary = process.env[envName]?.trim();
169
+ if (primary) return primary;
170
+ for (const fallbackEnvName of CHANNEL_WEBHOOK_FALLBACK_ENVS[channel] ?? []) {
171
+ const fallback = process.env[fallbackEnvName]?.trim();
172
+ if (fallback) return fallback;
173
+ }
174
+ return null;
175
+ }
176
+
177
+ function requireWebhookUrl(channel: SlackChannelKey): string {
178
+ const envName = CHANNEL_WEBHOOK_ENV[channel];
179
+ if (!envName) {
180
+ throw new Error(`Slack channel ${channel} requires bot delivery.`);
181
+ }
182
+ const url = resolveWebhookUrl(channel);
183
+ if (!url) throw new Error(`Missing ${envName}.`);
184
+ return url;
185
+ }
186
+
187
+ function isBotOnlySlackChannel(channel: SlackChannelKey): boolean {
188
+ return (
189
+ channel === 'user_signup' ||
190
+ channel === 'sdk_cli_activity' ||
191
+ channel === 'sdk_cli_errors' ||
192
+ channel === 'sdk_cli_feedback' ||
193
+ channel === 'dashboard_feedback' ||
194
+ channel === 'python_cli_feedback' ||
195
+ channel === 'python_cli_session'
196
+ );
197
+ }
198
+
199
+ function resolveBotChannel(
200
+ channel: SlackChannelKey,
201
+ ): { token: string; channelId: string } | null {
202
+ const token = process.env[SLACK_DEEPLINE_REPORTING_BOT_TOKEN_ENV]?.trim();
203
+ if (!token) return null;
204
+
205
+ switch (channel) {
206
+ case 'error_activity': {
207
+ // This is an explicit production cutover, not a global behavior change
208
+ // whenever a local test or Preview happens to have a reporting token.
209
+ const channelId =
210
+ process.env[SLACK_ERROR_ACTIVITY_CHANNEL_ID_ENV]?.trim();
211
+ if (!channelId) return null;
212
+ return {
213
+ token,
214
+ channelId,
215
+ };
216
+ }
217
+ case 'user_signup':
218
+ return {
219
+ token,
220
+ channelId:
221
+ process.env[SLACK_USER_SIGNUP_CHANNEL_ID_ENV]?.trim() ||
222
+ DEFAULT_USER_SIGNUP_CHANNEL_ID,
223
+ };
224
+ case 'provider_alerts':
225
+ return {
226
+ token,
227
+ channelId:
228
+ process.env[SLACK_PROVIDER_ALERTS_CHANNEL_ID_ENV]?.trim() ||
229
+ DEFAULT_PROVIDER_ALERTS_CHANNEL_ID,
230
+ };
231
+ case 'monitor_activity':
232
+ return {
233
+ token,
234
+ channelId:
235
+ process.env[SLACK_MONITOR_ACTIVITY_CHANNEL_ID_ENV]?.trim() ||
236
+ DEFAULT_MONITOR_ACTIVITY_CHANNEL_ID,
237
+ };
238
+ case 'monitor_error_activity':
239
+ return {
240
+ token,
241
+ channelId:
242
+ process.env[SLACK_MONITOR_ERROR_ACTIVITY_CHANNEL_ID_ENV]?.trim() ||
243
+ DEFAULT_MONITOR_ERROR_ACTIVITY_CHANNEL_ID,
244
+ };
245
+ case 'sdk_cli_activity':
246
+ return { token, channelId: SDK_CLI_ACTIVITY_SLACK_CHANNEL_ID };
247
+ case 'sdk_cli_errors':
248
+ return { token, channelId: SDK_CLI_ERRORS_SLACK_CHANNEL_ID };
249
+ case 'sdk_cli_feedback':
250
+ return { token, channelId: SDK_CLI_FEEDBACK_SLACK_CHANNEL_ID };
251
+ case 'dashboard_feedback':
252
+ return { token, channelId: DASHBOARD_FEEDBACK_SLACK_CHANNEL_ID };
253
+ case 'python_cli_feedback':
254
+ return { token, channelId: PYTHON_CLI_FEEDBACK_SLACK_CHANNEL_ID };
255
+ case 'python_cli_session':
256
+ return { token, channelId: PYTHON_CLI_SESSION_SLACK_CHANNEL_ID };
257
+ default:
258
+ return null;
259
+ }
260
+ }
261
+
262
+ function isSlackChannelUnavailableError(error: unknown): boolean {
263
+ const message = error instanceof Error ? error.message : String(error);
264
+ return (
265
+ message.includes('channel_not_found') || message.includes('not_in_channel')
266
+ );
267
+ }
268
+
269
+ async function postSlackWebhook(
270
+ url: string,
271
+ payload: SlackPayload,
272
+ ): Promise<void> {
273
+ const controller = new AbortController();
274
+ const timeout = setTimeout(() => controller.abort(), resolveTimeoutMs());
275
+ try {
276
+ const response = await fetch(url, {
277
+ method: 'POST',
278
+ headers: { 'Content-Type': 'application/json' },
279
+ body: JSON.stringify(payload),
280
+ signal: controller.signal,
281
+ });
282
+ if (!response.ok) {
283
+ const details = await response.text();
284
+ throw new Error(
285
+ `Slack webhook failed: ${details || response.statusText}`,
286
+ );
287
+ }
288
+ } finally {
289
+ clearTimeout(timeout);
290
+ }
291
+ }
292
+
293
+ function normalizeMetadataField(value: unknown): string | null {
294
+ if (typeof value !== 'string') return null;
295
+ const text = value.trim();
296
+ return text.length > 0 ? text : null;
297
+ }
298
+
299
+ function coalesceRequestMetadata(...candidates: unknown[]): string | null {
300
+ for (const candidate of candidates) {
301
+ const normalized = normalizeMetadataField(candidate);
302
+ if (normalized) return normalized;
303
+ }
304
+ return null;
305
+ }
306
+
307
+ function resolveRequestMetadataFromPayload(
308
+ payload: SlackPayload,
309
+ ): ResolvedRequestMetadata {
310
+ const metadata = getCurrentRequestMetadata();
311
+ return {
312
+ requestId: coalesceRequestMetadata(
313
+ metadata.requestId,
314
+ metadata.request_id,
315
+ payload.requestId,
316
+ payload.request_id,
317
+ ),
318
+ requestPath: coalesceRequestMetadata(
319
+ metadata.request_path,
320
+ metadata.requestPath,
321
+ payload.requestPath,
322
+ payload.request_path,
323
+ ),
324
+ };
325
+ }
326
+
327
+ export function buildVercelLogsUrlForRequest(input: {
328
+ requestId: string;
329
+ requestPath?: string | null;
330
+ level?: 'error' | 'warning' | 'info';
331
+ }): string {
332
+ const requestId = normalizeText(input.requestId);
333
+ const requestPath = normalizeText(input.requestPath);
334
+ const level = normalizeText(input.level);
335
+ const search = [
336
+ level ? `level:${level}` : '',
337
+ requestPath ? `requestPath:${requestPath}` : '',
338
+ requestId,
339
+ ]
340
+ .filter(Boolean)
341
+ .join(' ');
342
+ return `${VERCEL_LOGS_BASE_URL}?search=${encodeURIComponent(search)}`;
343
+ }
344
+
345
+ function buildVercelLogsContextBlock(
346
+ requestId: string,
347
+ vercelLogsUrl: string,
348
+ ): Record<string, unknown> {
349
+ return {
350
+ type: 'section',
351
+ text: {
352
+ type: 'mrkdwn',
353
+ text: `\`request_id\`: \`${requestId}\` · <${vercelLogsUrl}|Vercel logs>`,
354
+ },
355
+ };
356
+ }
357
+
358
+ function hasVercelLogsLink(
359
+ blocks: Array<Record<string, unknown>> | undefined,
360
+ ): boolean {
361
+ return (blocks ?? []).some((block) => {
362
+ const serialized = JSON.stringify(block);
363
+ return (
364
+ serialized.includes('Vercel logs') ||
365
+ serialized.includes('vercelLogsUrl') ||
366
+ serialized.includes('selectedLogId')
367
+ );
368
+ });
369
+ }
370
+
371
+ function attachVercelLogsToPayload(
372
+ payload: SlackPayload,
373
+ channel: SlackChannelKey,
374
+ ): SlackPayload {
375
+ if (
376
+ channel === 'plain_thread_activity' ||
377
+ normalizeText(payload.vercelLogsUrl)
378
+ ) {
379
+ return payload;
380
+ }
381
+
382
+ const { requestId, requestPath } = resolveRequestMetadataFromPayload(payload);
383
+ if (!requestId) return payload;
384
+
385
+ const vercelLogsUrl = buildVercelLogsUrlForRequest({
386
+ requestId,
387
+ requestPath,
388
+ level: CHANNEL_ALERT_LEVEL[channel],
389
+ });
390
+ const nextPayload = {
391
+ ...payload,
392
+ requestId,
393
+ request_id: requestId,
394
+ requestPath: requestPath ?? payload.requestPath ?? null,
395
+ request_path: requestPath ?? payload.request_path ?? null,
396
+ vercelLogsUrl,
397
+ } as SlackPayload;
398
+
399
+ if (
400
+ Array.isArray(nextPayload.blocks) &&
401
+ !hasVercelLogsLink(nextPayload.blocks)
402
+ ) {
403
+ nextPayload.blocks = [
404
+ ...nextPayload.blocks,
405
+ buildVercelLogsContextBlock(requestId, vercelLogsUrl),
406
+ ];
407
+ return nextPayload;
408
+ }
409
+
410
+ const baseText = normalizeText(payload.text);
411
+ if (baseText && !baseText.includes('Vercel logs')) {
412
+ nextPayload.text = `${baseText} · Vercel Logs: ${vercelLogsUrl}`;
413
+ }
414
+ return nextPayload;
415
+ }
416
+
417
+ export function extractActorEmail(payload: SlackPayload): string | null {
418
+ const raw = payload.email ?? payload.actorEmail;
419
+ if (typeof raw !== 'string') return null;
420
+ const trimmed = raw.trim();
421
+ return trimmed.length > 0 ? trimmed : null;
422
+ }
423
+
424
+ export function isBlockedInternalActor(payload: SlackPayload): boolean {
425
+ const email = extractActorEmail(payload);
426
+ if (!email) return false;
427
+ const normalizedEmail = email.toLowerCase();
428
+ if (BLOCKED_SLACK_ACTOR_EMAILS.includes(normalizedEmail)) return true;
429
+ const domain = normalizedEmail.split('@')[1];
430
+ return domain ? BLOCKED_SLACK_EMAIL_DOMAINS.includes(domain) : false;
431
+ }
432
+
433
+ function truncateSlackDispatchValue(value: unknown): string | null {
434
+ const text = normalizeText(value);
435
+ if (!text) return null;
436
+ return text.length > 1000 ? `${text.slice(0, 1000)}...` : text;
437
+ }
438
+
439
+ function compactSlackDispatchPayload(
440
+ channel: SlackChannelKey,
441
+ payload: SlackPayload,
442
+ delivery: 'bot' | 'webhook',
443
+ ): Record<string, unknown> {
444
+ const requestMetadata = resolveRequestMetadataFromPayload(payload);
445
+ const blockCount = Array.isArray(payload.blocks) ? payload.blocks.length : 0;
446
+ const fieldNames = [
447
+ 'orgId',
448
+ 'org_id',
449
+ 'userId',
450
+ 'user_id',
451
+ 'email',
452
+ 'actorEmail',
453
+ 'provider',
454
+ 'integration',
455
+ 'operation',
456
+ 'code',
457
+ 'errorCategory',
458
+ 'error_category',
459
+ 'credentialOwner',
460
+ 'credential_owner',
461
+ 'status',
462
+ 'route',
463
+ 'sessionId',
464
+ 'session_id',
465
+ 'runId',
466
+ 'run_id',
467
+ 'cliVersionStatus',
468
+ ];
469
+ const fields: Record<string, unknown> = {};
470
+ for (const name of fieldNames) {
471
+ const value = payload[name];
472
+ if (
473
+ typeof value === 'string' ||
474
+ typeof value === 'number' ||
475
+ typeof value === 'boolean' ||
476
+ value === null
477
+ ) {
478
+ fields[name] = value;
479
+ }
480
+ }
481
+
482
+ return removeHttpHeadersFromSlackPayload({
483
+ tag: 'slack_event_dispatch',
484
+ channel,
485
+ alertLevel: CHANNEL_ALERT_LEVEL[channel],
486
+ delivery,
487
+ source: payload.source,
488
+ text: truncateSlackDispatchValue(payload.text),
489
+ requestedAt: payload.requestedAt ?? null,
490
+ requestId: requestMetadata.requestId,
491
+ requestPath: requestMetadata.requestPath,
492
+ vercelLogsUrl: truncateSlackDispatchValue(payload.vercelLogsUrl),
493
+ hasBlocks: blockCount > 0,
494
+ blockCount,
495
+ fields,
496
+ }) as Record<string, unknown>;
497
+ }
498
+
499
+ function logSlackEventDispatch(
500
+ channel: SlackChannelKey,
501
+ payload: SlackPayload,
502
+ delivery: 'bot' | 'webhook',
503
+ ): void {
504
+ console.info(
505
+ '[slack-events] dispatch',
506
+ compactSlackDispatchPayload(channel, payload, delivery),
507
+ );
508
+ }
509
+
510
+ function messageOptions(payload: SlackPayload) {
511
+ return Array.isArray(payload.blocks)
512
+ ? {
513
+ blocks: payload.blocks,
514
+ unfurlLinks: payload.unfurl_links ?? false,
515
+ unfurlMedia: payload.unfurl_media ?? false,
516
+ }
517
+ : undefined;
518
+ }
519
+
520
+ export async function sendSlackEvent(
521
+ channel: SlackChannelKey,
522
+ payload: SlackPayload,
523
+ options: SlackDeliveryOptions = {},
524
+ ): Promise<void> {
525
+ if (
526
+ getSlackChannelEnvironmentRequirement(channel) === 'prod' &&
527
+ getRuntimeEnv() !== 'prod'
528
+ ) {
529
+ return;
530
+ }
531
+ if (isSyntheticActorEmail(extractActorEmail(payload))) return;
532
+ if (!payload.bypassInternalActorBlock && isBlockedInternalActor(payload)) {
533
+ return;
534
+ }
535
+
536
+ const sanitizedPayload = removeHttpHeadersFromSlackPayload(
537
+ payload,
538
+ ) as SlackPayload;
539
+ const enrichedPayload = attachVercelLogsToPayload(sanitizedPayload, channel);
540
+ const normalized = enrichedPayload.blocks
541
+ ? {
542
+ ...enrichedPayload,
543
+ requestedAt: enrichedPayload.requestedAt ?? new Date().toISOString(),
544
+ }
545
+ : buildSlackActivityPayload({
546
+ source: enrichedPayload.source,
547
+ activityTitle: 'You have a new activity:',
548
+ activityPrimary:
549
+ normalizeText(enrichedPayload.text) || 'Activity update',
550
+ fields: [],
551
+ fallbackText: enrichedPayload.text,
552
+ requestedAt: enrichedPayload.requestedAt,
553
+ extra: enrichedPayload,
554
+ });
555
+ const versionedNormalized = options.enrichPayload
556
+ ? await options.enrichPayload(normalized)
557
+ : normalized;
558
+ const sanitizedNormalized = removeHttpHeadersFromSlackPayload({
559
+ unfurl_links: false,
560
+ unfurl_media: false,
561
+ ...versionedNormalized,
562
+ }) as SlackPayload;
563
+ const postMessage = options.postMessage ?? postMessageToSlack;
564
+
565
+ const botChannel = resolveBotChannel(channel);
566
+ if (botChannel) {
567
+ try {
568
+ await postMessage(
569
+ botChannel.token,
570
+ botChannel.channelId,
571
+ sanitizedNormalized.text,
572
+ messageOptions(sanitizedNormalized),
573
+ );
574
+ logSlackEventDispatch(channel, sanitizedNormalized, 'bot');
575
+ return;
576
+ } catch (error) {
577
+ if (
578
+ channel === 'sdk_cli_feedback' &&
579
+ isSlackChannelUnavailableError(error)
580
+ ) {
581
+ await postMessage(
582
+ botChannel.token,
583
+ SDK_CLI_ACTIVITY_SLACK_CHANNEL_ID,
584
+ sanitizedNormalized.text,
585
+ messageOptions(sanitizedNormalized),
586
+ );
587
+ logSlackEventDispatch(channel, sanitizedNormalized, 'bot');
588
+ return;
589
+ }
590
+ if (isBotOnlySlackChannel(channel)) throw error;
591
+ const webhookUrl = resolveWebhookUrl(channel);
592
+ if (!webhookUrl) throw error;
593
+ await postSlackWebhook(webhookUrl, sanitizedNormalized);
594
+ logSlackEventDispatch(channel, sanitizedNormalized, 'webhook');
595
+ return;
596
+ }
597
+ }
598
+
599
+ if (isBotOnlySlackChannel(channel)) {
600
+ throw new Error(`Missing ${SLACK_DEEPLINE_REPORTING_BOT_TOKEN_ENV}.`);
601
+ }
602
+ await postSlackWebhook(requireWebhookUrl(channel), sanitizedNormalized);
603
+ logSlackEventDispatch(channel, sanitizedNormalized, 'webhook');
604
+ }
605
+
606
+ export async function sendSlackEventSafe(
607
+ channel: SlackChannelKey,
608
+ payload: SlackPayload,
609
+ options: SlackDeliveryOptions = {},
610
+ ): Promise<boolean> {
611
+ try {
612
+ await sendSlackEvent(channel, payload, options);
613
+ return true;
614
+ } catch (error) {
615
+ const message = error instanceof Error ? error.message : String(error);
616
+ if (message.startsWith('Missing SLACK_')) return false;
617
+ console.warn('Slack event send failed.', {
618
+ channel,
619
+ source: payload.source,
620
+ error: message,
621
+ });
622
+ return false;
623
+ }
624
+ }