eve 0.13.5 → 0.13.6

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 (107) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/src/channel/send.d.ts +3 -1
  3. package/dist/src/channel/send.js +1 -1
  4. package/dist/src/channel/types.d.ts +6 -0
  5. package/dist/src/chunks/{use-eve-agent-_dbX0ASK.js → use-eve-agent-8X2UMr8q.js} +26 -2
  6. package/dist/src/chunks/{use-eve-agent-BjAM8_a3.js → use-eve-agent-9ZNiSFMb.js} +26 -2
  7. package/dist/src/cli/dev/tui/blocks.d.ts +1 -1
  8. package/dist/src/cli/dev/tui/blocks.js +1 -1
  9. package/dist/src/cli/dev/tui/prompt-command-handler.d.ts +5 -1
  10. package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
  11. package/dist/src/cli/dev/tui/prompt-commands.d.ts +7 -7
  12. package/dist/src/cli/dev/tui/prompt-commands.js +2 -2
  13. package/dist/src/cli/dev/tui/remote-auth-command.d.ts +11 -0
  14. package/dist/src/cli/dev/tui/remote-auth-command.js +3 -0
  15. package/dist/src/cli/dev/tui/remote-auth-result.d.ts +5 -0
  16. package/dist/src/cli/dev/tui/remote-auth-result.js +2 -1
  17. package/dist/src/cli/dev/tui/remote-auth.d.ts +30 -0
  18. package/dist/src/cli/dev/tui/remote-auth.js +1 -0
  19. package/dist/src/cli/dev/tui/remote-connection-probe.d.ts +3 -1
  20. package/dist/src/cli/dev/tui/remote-connection-probe.js +1 -1
  21. package/dist/src/cli/dev/tui/remote-connection-types.d.ts +2 -1
  22. package/dist/src/cli/dev/tui/remote-connection.js +1 -1
  23. package/dist/src/cli/dev/tui/runner.d.ts +18 -1
  24. package/dist/src/cli/dev/tui/runner.js +1 -1
  25. package/dist/src/cli/dev/tui/setup-commands.d.ts +4 -4
  26. package/dist/src/cli/dev/tui/setup-commands.js +2 -2
  27. package/dist/src/cli/dev/tui/setup-issues.d.ts +1 -1
  28. package/dist/src/cli/dev/tui/setup-issues.js +1 -1
  29. package/dist/src/cli/dev/tui/status-line.d.ts +6 -14
  30. package/dist/src/cli/dev/tui/status-line.js +1 -1
  31. package/dist/src/cli/dev/tui/terminal-renderer.d.ts +8 -1
  32. package/dist/src/cli/dev/tui/terminal-renderer.js +9 -9
  33. package/dist/src/cli/dev/tui/test/index.d.ts +1 -0
  34. package/dist/src/cli/dev/tui/test/index.js +1 -1
  35. package/dist/src/cli/dev/tui/tui.d.ts +1 -1
  36. package/dist/src/cli/dev/tui/tui.js +1 -1
  37. package/dist/src/cli/dev/tui/vercel-trusted-sources.js +1 -1
  38. package/dist/src/cli/run.js +1 -1
  39. package/dist/src/client/agent-info-error.d.ts +17 -0
  40. package/dist/src/client/agent-info-error.js +1 -0
  41. package/dist/src/client/client.d.ts +4 -0
  42. package/dist/src/client/client.js +1 -1
  43. package/dist/src/client/index.d.ts +1 -0
  44. package/dist/src/client/index.js +1 -1
  45. package/dist/src/client/ndjson.js +3 -3
  46. package/dist/src/context/keys.d.ts +1 -0
  47. package/dist/src/context/keys.js +1 -1
  48. package/dist/src/evals/cli/eval-client.js +1 -1
  49. package/dist/src/execution/delegated-parent-notification.js +1 -1
  50. package/dist/src/execution/durable-session-store.js +1 -1
  51. package/dist/src/execution/eve-workflow-attributes.d.ts +8 -0
  52. package/dist/src/execution/eve-workflow-attributes.js +1 -1
  53. package/dist/src/execution/ndjson-stream.d.ts +19 -0
  54. package/dist/src/execution/ndjson-stream.js +3 -0
  55. package/dist/src/execution/runtime-context.js +1 -1
  56. package/dist/src/execution/subagent-adapter.js +1 -1
  57. package/dist/src/execution/turn-workflow.js +1 -1
  58. package/dist/src/execution/workflow-entry.js +1 -1
  59. package/dist/src/execution/workflow-runtime.d.ts +1 -1
  60. package/dist/src/execution/workflow-runtime.js +1 -3
  61. package/dist/src/execution/workflow-steps.js +1 -1
  62. package/dist/src/internal/application/package.js +1 -1
  63. package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
  64. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  65. package/dist/src/internal/workflow/configure-world.js +1 -1
  66. package/dist/src/internal/workflow/queue-namespace.d.ts +0 -1
  67. package/dist/src/internal/workflow/queue-namespace.js +1 -1
  68. package/dist/src/internal/workflow/runtime.d.ts +4 -0
  69. package/dist/src/internal/workflow/runtime.js +1 -0
  70. package/dist/src/internal/workflow-bundle/builder-support.js +6 -6
  71. package/dist/src/internal/workflow-bundle/builder.js +2 -2
  72. package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
  73. package/dist/src/public/channels/github/dispatch.d.ts +22 -1
  74. package/dist/src/public/channels/github/dispatch.js +1 -1
  75. package/dist/src/public/channels/github/githubChannel.d.ts +21 -3
  76. package/dist/src/public/channels/github/githubChannel.js +1 -1
  77. package/dist/src/public/channels/github/inbound.d.ts +46 -1
  78. package/dist/src/public/channels/github/inbound.js +2 -2
  79. package/dist/src/public/channels/github/index.d.ts +1 -1
  80. package/dist/src/public/channels/github/state.d.ts +3 -1
  81. package/dist/src/public/channels/github/state.js +1 -1
  82. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  83. package/dist/src/runtime/connections/callback-route.js +1 -1
  84. package/dist/src/runtime/session-callback-route.js +1 -1
  85. package/dist/src/services/dev-client/request-headers.d.ts +2 -0
  86. package/dist/src/services/dev-client/request-headers.js +1 -1
  87. package/dist/src/services/dev-client/vercel-auth-error.d.ts +12 -14
  88. package/dist/src/services/dev-client/vercel-auth-error.js +9 -2
  89. package/dist/src/setup/flows/install-vercel-cli.d.ts +1 -1
  90. package/dist/src/setup/flows/login.d.ts +3 -1
  91. package/dist/src/setup/flows/login.js +1 -1
  92. package/dist/src/setup/scaffold/create/project.js +1 -1
  93. package/dist/src/setup/vercel-deployment.d.ts +12 -5
  94. package/dist/src/setup/vercel-deployment.js +1 -1
  95. package/dist/src/setup/vercel-project-api.d.ts +13 -2
  96. package/dist/src/setup/vercel-project-api.js +1 -1
  97. package/dist/src/setup/vercel-project.d.ts +5 -1
  98. package/dist/src/setup/vercel-project.js +0 -0
  99. package/dist/src/setup/verified-remote-client.js +1 -1
  100. package/dist/src/svelte/index.js +1 -1
  101. package/dist/src/svelte/use-eve-agent.js +1 -1
  102. package/dist/src/vue/index.js +1 -1
  103. package/dist/src/vue/use-eve-agent.js +1 -1
  104. package/docs/channels/github.mdx +13 -1
  105. package/docs/channels/slack.mdx +1 -1
  106. package/docs/guides/dev-tui.md +22 -12
  107. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import{resolvePackageSourceDirectoryPath,resolveWorkflowModulePath}from"#internal/application/package.js";import{dirname,join,relative,resolve}from"node:path";import{cp,mkdir,readFile,rm,writeFile}from"node:fs/promises";import{normalizeEsmImportSpecifier}from"#internal/application/import-specifier.js";import{EVE_WORKFLOW_QUEUE_NAMESPACE}from"#internal/workflow/queue-namespace.js";import{buildWithNitroRolldown,getSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{prepareEveVersionedCacheDirectory,writeEveVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{WORKFLOW_BUILDER_DEFERRED_PACKAGES,WORKFLOW_STEP_EXTERNAL_PACKAGES,copyNitroFunctionDirectory,createWorkflowFunctionEnvironment,retargetNitroFunctionDirectoryToWorkflowRoute}from"#internal/workflow-bundle/vercel-workflow-output.js";import{WORKFLOW_QUEUE_TRIGGER,detectWorkflowPatterns}from"#internal/workflow-bundle/workflow-builders.js";import{Buffer}from"node:buffer";import{WORKFLOW_VIRTUAL_ENTRY_ID,atomicWriteFile,bundleFinalWorkflowOutput,collectWorkflowInputFiles,convertClassesManifest,convertStepsManifest,convertWorkflowsManifest,createEvePackageImportsPlugin,createWorkflowImport,createWorkflowNodeBuiltinGuardPlugin,createWorkflowPseudoPackagePlugin,createWorkflowTransformPlugin,createWorkflowVirtualEntryPlugin}from"#internal/workflow-bundle/builder-support.js";import{writeNitroStepEntrypoint}from"#internal/workflow-bundle/nitro-step-entry.js";const workflowBundleBuildLocks=new Map;var WorkflowBundleBuilder=class{#e;#t;config;#n=new WeakMap;constructor(t){let n=[resolvePackageSourceDirectoryPath(`src/execution`)];t.includeTestFixtures===!0&&n.push(resolvePackageSourceDirectoryPath(`src/internal/testing`)),this.config={buildTarget:`standalone`,dirs:n,externalPackages:[...WORKFLOW_STEP_EXTERNAL_PACKAGES,...WORKFLOW_BUILDER_DEFERRED_PACKAGES],projectRoot:t.appRoot,watch:t.watch,workingDir:t.rootDir},this.#e=t.compiledArtifactsBootstrapPath,this.#t=t.outDir}async build(e={}){let t=(workflowBundleBuildLocks.get(this.#t)??Promise.resolve()).then(()=>this.#r(e));workflowBundleBuildLocks.set(this.#t,t.catch(()=>{})),await t}async#r(i){await prepareEveVersionedCacheDirectory(this.#t);let a=await this.#i();if(a.length===0)throw Error(`Expected the execution workflow source file under "${resolvePackageSourceDirectoryPath(`src/execution`)}".`);let o=await this.findTsConfigPath();await mkdir(this.#t,{recursive:!0});let c=await this.discoverEntries(a,this.#t,o),l=join(this.#t,`workflows.mjs`),{manifest:u}=await this.createWorkflowsBundle({discoveredEntries:c,keepInterimBundleContext:!1,outfile:l,bundleFinalOutput:!1,format:`esm`,inputFiles:a,tsconfigPath:o}),d=join(this.#t,`steps.mjs`),f=await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:d,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,workingDir:this.config.workingDir}),p=i.nitroStepOutfile;p!==void 0&&p!==d&&await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:p,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,workingDir:this.config.workingDir}),await addStepRegistrationsImport(l,d),await rewriteWorkflowRuntimeImports(l),await rewriteWorkflowCodeLiteral(l);let m=i.nitroWorkflowOutfile;m!==void 0&&m!==l&&(await mkdir(dirname(m),{recursive:!0}),await mirrorFileBypassingUnlink(l,m),p!==void 0&&(await addStepRegistrationsImport(m,p),await rewriteWorkflowRuntimeImports(m),await rewriteWorkflowCodeLiteral(m))),await this.createManifest({workflowBundlePath:join(this.#t,`workflows.mjs`),manifestDir:this.#t,manifest:{steps:{...f.steps,...u.steps},workflows:{...f.workflows,...u.workflows},classes:{...f.classes,...u.classes}}}),await writeEveVersionedCacheMetadata(this.#t)}get transformProjectRoot(){return this.config.projectRoot??this.config.workingDir}async findTsConfigPath(){let e=this.config.workingDir;for(;;){for(let t of[`tsconfig.json`,`jsconfig.json`]){let n=join(e,t);try{return await readFile(n),n}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}}let t=dirname(e);if(t===e)return;e=t}}async getInputFiles(){let e=this.config.dirs.map(e=>resolve(this.config.workingDir,e));return(await Promise.all(e.map(e=>collectWorkflowInputFiles(e)))).flat()}async discoverEntries(e,t,n){let r=this.#n.get(e);if(r!==void 0)return r;let i={discoveredSerdeFiles:[],discoveredSteps:[],discoveredWorkflows:[]};for(let t of e){let e=detectWorkflowPatterns(await readFile(t,`utf8`));e.hasUseStep&&i.discoveredSteps.push(t),e.hasUseWorkflow&&i.discoveredWorkflows.push(t),e.hasSerde&&i.discoveredSerdeFiles.push(t)}return this.#n.set(e,i),i}async createWorkflowsBundle({bundleFinalOutput:e=!0,discoveredEntries:t,format:r=`cjs`,inputFiles:i,keepInterimBundleContext:a=this.config.watch,outfile:o,tsconfigPath:s}){let c=t??await this.discoverEntries(i,dirname(o),s),l=[...c.discoveredWorkflows].sort(),u=new Set(l),d=[...c.discoveredSerdeFiles].sort().filter(e=>!u.has(e)),f={},h=[...l.map(e=>createWorkflowImport(e,this.config.workingDir)),...d.map(e=>createWorkflowImport(e,this.config.workingDir))].join(`
2
- `);return await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:getSingleRolldownChunk(await buildWithNitroRolldown({cwd:this.config.workingDir,input:WORKFLOW_VIRTUAL_ENTRY_ID,platform:`neutral`,plugins:[createWorkflowVirtualEntryPlugin(h),createWorkflowPseudoPackagePlugin(),createEvePackageImportsPlugin(this.config.workingDir,{workflowCondition:!0}),createWorkflowTransformPlugin({manifest:f,projectRoot:this.transformProjectRoot,sideEffectFiles:[...l,...d],workingDir:this.config.workingDir}),createWorkflowNodeBuiltinGuardPlugin()],resolve:{conditionNames:[`eve-source`,`workflow`,`node`,`import`,`default`],extensions:[`.ts`,`.tsx`,`.mts`,`.cts`,`.js`,`.jsx`,`.mjs`,`.cjs`],mainFields:[`module`,`main`]},tsconfig:s??!1,write:!1,output:{banner:`globalThis.__private_workflows = new Map();`,codeSplitting:!1,comments:!1,format:`cjs`,sourcemap:`inline`}}),`intermediate workflow bundle for "${o}"`).code,format:r,outfile:o,workingDir:this.config.workingDir}),a?{bundleFinal:async t=>{await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:t,format:r,outfile:o,workingDir:this.config.workingDir})},interimBundleCtx:void 0,manifest:f}:{manifest:f}}async createManifest({manifest:e,manifestDir:t}){let n={version:`1.0.0`,steps:convertStepsManifest(e.steps),workflows:convertWorkflowsManifest(e.workflows),classes:convertClassesManifest(e.classes)},i=JSON.stringify(n,null,2);return await mkdir(t,{recursive:!0}),await writeFile(join(t,`manifest.json`),i),i}async buildVercelOutput(e){await this.build();let t=join(this.#t,`vercel-build-output`,`functions`,`.well-known`,`workflow`,`v1`),n=join(t,`flow.func`),i=join(e.outputDir,`functions`,`.well-known`,`workflow`,`v1`),a=join(e.flowNitroOutputDir,`functions`,`__server.func`),c=join(e.flowNitroOutputDir,`functions`,`.well-known`,`workflow`,`v1`,`flow.func`),u=join(i,`flow.func`),d=join(i,`step.func`),f=join(i,`webhook`,`[token].func`);await copyNitroFunctionDirectory({fallbackPath:a,sourcePath:c,targetPath:n}),await Promise.all([this.#a(n,{experimentalTriggers:Array.from([WORKFLOW_QUEUE_TRIGGER]),maxDuration:`max`,runtime:e.runtime??null,shouldAddHelpers:!1}),cp(join(this.#t,`manifest.json`),join(t,`manifest.json`))]),await retargetNitroFunctionDirectoryToWorkflowRoute({functionDirectoryPath:n,workflowRoutePath:`/.well-known/workflow/v1/flow`}),await Promise.all([rm(u,{force:!0,recursive:!0}),rm(d,{force:!0,recursive:!0}),rm(f,{force:!0,recursive:!0})]),await mkdir(i,{recursive:!0}),await Promise.all([cp(n,u,{recursive:!0}),cp(join(t,`manifest.json`),join(i,`manifest.json`))])}async#i(){return[...await this.getInputFiles(),this.#e]}async#a(e,t){let n=join(e,`.vc-config.json`),i=await this.#o(n),a={...i};a.environment=createWorkflowFunctionEnvironment(i.environment),t.runtime!==null&&(a.runtime=t.runtime),t.maxDuration!==void 0&&(a.maxDuration=t.maxDuration),t.shouldAddHelpers!==void 0&&(a.shouldAddHelpers=t.shouldAddHelpers),t.shouldAddSourcemapSupport!==void 0&&(a.shouldAddSourcemapSupport=t.shouldAddSourcemapSupport),t.experimentalTriggers!==void 0&&(a.experimentalTriggers=[...t.experimentalTriggers]),await writeFile(n,`${JSON.stringify(a,null,2)}\n`)}async#o(e){try{let t=JSON.parse(await readFile(e,`utf8`));if(typeof t==`object`&&t)return t}catch{}return{}}};async function addStepRegistrationsImport(e,t){let r=await readTextFileIfPresent(e);if(r===null||r.includes(`__eveWorkflowStepsRegistered`))return;let i=createRelativeImportSpecifier(dirname(e),t),a=[`import { __steps_registered as __eveWorkflowStepsRegistered } from ${JSON.stringify(i)};`,`void __eveWorkflowStepsRegistered;`,``].join(`
1
+ import{resolvePackageSourceDirectoryPath,resolveWorkflowModulePath}from"#internal/application/package.js";import{dirname,join,relative,resolve}from"node:path";import{cp,mkdir,readFile,rm,writeFile}from"node:fs/promises";import{normalizeEsmImportSpecifier}from"#internal/application/import-specifier.js";import{buildWithNitroRolldown,getSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{prepareEveVersionedCacheDirectory,writeEveVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{WORKFLOW_BUILDER_DEFERRED_PACKAGES,WORKFLOW_STEP_EXTERNAL_PACKAGES,copyNitroFunctionDirectory,createWorkflowFunctionEnvironment,retargetNitroFunctionDirectoryToWorkflowRoute}from"#internal/workflow-bundle/vercel-workflow-output.js";import{EVE_WORKFLOW_QUEUE_NAMESPACE}from"#internal/workflow/queue-namespace.js";import{WORKFLOW_QUEUE_TRIGGER,detectWorkflowPatterns}from"#internal/workflow-bundle/workflow-builders.js";import{Buffer}from"node:buffer";import{WORKFLOW_VIRTUAL_ENTRY_ID,atomicWriteFile,bundleFinalWorkflowOutput,collectWorkflowInputFiles,convertClassesManifest,convertStepsManifest,convertWorkflowsManifest,createEvePackageImportsPlugin,createWorkflowImport,createWorkflowNodeBuiltinGuardPlugin,createWorkflowPseudoPackagePlugin,createWorkflowTransformPlugin,createWorkflowVirtualEntryPlugin}from"#internal/workflow-bundle/builder-support.js";import{writeNitroStepEntrypoint}from"#internal/workflow-bundle/nitro-step-entry.js";const workflowBundleBuildLocks=new Map;var WorkflowBundleBuilder=class{#e;#t;config;#n=new WeakMap;constructor(t){let n=[resolvePackageSourceDirectoryPath(`src/execution`)];t.includeTestFixtures===!0&&n.push(resolvePackageSourceDirectoryPath(`src/internal/testing`)),this.config={buildTarget:`standalone`,dirs:n,externalPackages:[...WORKFLOW_STEP_EXTERNAL_PACKAGES,...WORKFLOW_BUILDER_DEFERRED_PACKAGES],projectRoot:t.appRoot,watch:t.watch,workingDir:t.rootDir},this.#e=t.compiledArtifactsBootstrapPath,this.#t=t.outDir}async build(e={}){let t=(workflowBundleBuildLocks.get(this.#t)??Promise.resolve()).then(()=>this.#r(e));workflowBundleBuildLocks.set(this.#t,t.catch(()=>{})),await t}async#r(i){await prepareEveVersionedCacheDirectory(this.#t);let a=await this.#i();if(a.length===0)throw Error(`Expected the execution workflow source file under "${resolvePackageSourceDirectoryPath(`src/execution`)}".`);let o=await this.findTsConfigPath();await mkdir(this.#t,{recursive:!0});let c=await this.discoverEntries(a,this.#t,o),l=join(this.#t,`workflows.mjs`),{manifest:u}=await this.createWorkflowsBundle({discoveredEntries:c,keepInterimBundleContext:!1,outfile:l,bundleFinalOutput:!1,format:`esm`,inputFiles:a,tsconfigPath:o}),d=join(this.#t,`steps.mjs`),f=await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:d,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,workingDir:this.config.workingDir}),p=i.nitroStepOutfile;p!==void 0&&p!==d&&await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:p,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,workingDir:this.config.workingDir}),await addStepRegistrationsImport(l,d),await rewriteWorkflowRuntimeImports(l),await rewriteWorkflowCodeLiteral(l);let g=i.nitroWorkflowOutfile;g!==void 0&&g!==l&&(await mkdir(dirname(g),{recursive:!0}),await mirrorFileBypassingUnlink(l,g),p!==void 0&&(await addStepRegistrationsImport(g,p),await rewriteWorkflowRuntimeImports(g),await rewriteWorkflowCodeLiteral(g))),await this.createManifest({workflowBundlePath:join(this.#t,`workflows.mjs`),manifestDir:this.#t,manifest:{steps:{...f.steps,...u.steps},workflows:{...f.workflows,...u.workflows},classes:{...f.classes,...u.classes}}}),await writeEveVersionedCacheMetadata(this.#t)}get transformProjectRoot(){return this.config.projectRoot??this.config.workingDir}async findTsConfigPath(){let e=this.config.workingDir;for(;;){for(let t of[`tsconfig.json`,`jsconfig.json`]){let n=join(e,t);try{return await readFile(n),n}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}}let t=dirname(e);if(t===e)return;e=t}}async getInputFiles(){let e=this.config.dirs.map(e=>resolve(this.config.workingDir,e));return(await Promise.all(e.map(e=>collectWorkflowInputFiles(e)))).flat()}async discoverEntries(e,t,n){let r=this.#n.get(e);if(r!==void 0)return r;let i={discoveredSerdeFiles:[],discoveredSteps:[],discoveredWorkflows:[]};for(let t of e){let e=detectWorkflowPatterns(await readFile(t,`utf8`));e.hasUseStep&&i.discoveredSteps.push(t),e.hasUseWorkflow&&i.discoveredWorkflows.push(t),e.hasSerde&&i.discoveredSerdeFiles.push(t)}return this.#n.set(e,i),i}async createWorkflowsBundle({bundleFinalOutput:e=!0,discoveredEntries:t,format:r=`cjs`,inputFiles:i,keepInterimBundleContext:a=this.config.watch,outfile:o,tsconfigPath:s}){let c=t??await this.discoverEntries(i,dirname(o),s),l=[...c.discoveredWorkflows].sort(),u=new Set(l),d=[...c.discoveredSerdeFiles].sort().filter(e=>!u.has(e)),m={},h=[...l.map(e=>createWorkflowImport(e,this.config.workingDir)),...d.map(e=>createWorkflowImport(e,this.config.workingDir))].join(`
2
+ `);return await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:getSingleRolldownChunk(await buildWithNitroRolldown({cwd:this.config.workingDir,input:WORKFLOW_VIRTUAL_ENTRY_ID,platform:`neutral`,plugins:[createWorkflowVirtualEntryPlugin(h),createWorkflowPseudoPackagePlugin(),createEvePackageImportsPlugin(this.config.workingDir,{workflowCondition:!0}),createWorkflowTransformPlugin({manifest:m,projectRoot:this.transformProjectRoot,sideEffectFiles:[...l,...d],workingDir:this.config.workingDir}),createWorkflowNodeBuiltinGuardPlugin()],resolve:{conditionNames:[`eve-source`,`workflow`,`node`,`import`,`default`],extensions:[`.ts`,`.tsx`,`.mts`,`.cts`,`.js`,`.jsx`,`.mjs`,`.cjs`],mainFields:[`module`,`main`]},tsconfig:s??!1,write:!1,output:{banner:`globalThis.__private_workflows = new Map();`,codeSplitting:!1,comments:!1,format:`cjs`,sourcemap:`inline`}}),`intermediate workflow bundle for "${o}"`).code,format:r,outfile:o,workingDir:this.config.workingDir}),a?{bundleFinal:async t=>{await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:t,format:r,outfile:o,workingDir:this.config.workingDir})},interimBundleCtx:void 0,manifest:m}:{manifest:m}}async createManifest({manifest:e,manifestDir:t}){let n={version:`1.0.0`,steps:convertStepsManifest(e.steps),workflows:convertWorkflowsManifest(e.workflows),classes:convertClassesManifest(e.classes)},i=JSON.stringify(n,null,2);return await mkdir(t,{recursive:!0}),await writeFile(join(t,`manifest.json`),i),i}async buildVercelOutput(e){await this.build();let t=join(this.#t,`vercel-build-output`,`functions`,`.well-known`,`workflow`,`v1`),n=join(t,`flow.func`),i=join(e.outputDir,`functions`,`.well-known`,`workflow`,`v1`),a=join(e.flowNitroOutputDir,`functions`,`__server.func`),c=join(e.flowNitroOutputDir,`functions`,`.well-known`,`workflow`,`v1`,`flow.func`),u=join(i,`flow.func`),d=join(i,`step.func`),f=join(i,`webhook`,`[token].func`);await copyNitroFunctionDirectory({fallbackPath:a,sourcePath:c,targetPath:n}),await Promise.all([this.#a(n,{experimentalTriggers:Array.from([WORKFLOW_QUEUE_TRIGGER]),maxDuration:`max`,runtime:e.runtime??null,shouldAddHelpers:!1}),cp(join(this.#t,`manifest.json`),join(t,`manifest.json`))]),await retargetNitroFunctionDirectoryToWorkflowRoute({functionDirectoryPath:n,workflowRoutePath:`/.well-known/workflow/v1/flow`}),await Promise.all([rm(u,{force:!0,recursive:!0}),rm(d,{force:!0,recursive:!0}),rm(f,{force:!0,recursive:!0})]),await mkdir(i,{recursive:!0}),await Promise.all([cp(n,u,{recursive:!0}),cp(join(t,`manifest.json`),join(i,`manifest.json`))])}async#i(){return[...await this.getInputFiles(),this.#e]}async#a(e,t){let n=join(e,`.vc-config.json`),i=await this.#o(n),a={...i};a.environment=createWorkflowFunctionEnvironment(i.environment),t.runtime!==null&&(a.runtime=t.runtime),t.maxDuration!==void 0&&(a.maxDuration=t.maxDuration),t.shouldAddHelpers!==void 0&&(a.shouldAddHelpers=t.shouldAddHelpers),t.shouldAddSourcemapSupport!==void 0&&(a.shouldAddSourcemapSupport=t.shouldAddSourcemapSupport),t.experimentalTriggers!==void 0&&(a.experimentalTriggers=[...t.experimentalTriggers]),await writeFile(n,`${JSON.stringify(a,null,2)}\n`)}async#o(e){try{let t=JSON.parse(await readFile(e,`utf8`));if(typeof t==`object`&&t)return t}catch{}return{}}};async function addStepRegistrationsImport(e,t){let r=await readTextFileIfPresent(e);if(r===null||r.includes(`__eveWorkflowStepsRegistered`))return;let i=createRelativeImportSpecifier(dirname(e),t),a=[`import { __steps_registered as __eveWorkflowStepsRegistered } from ${JSON.stringify(i)};`,`void __eveWorkflowStepsRegistered;`,``].join(`
3
3
  `),o=r.match(/^import\s.+?;\n/m);if(o===null||o.index===void 0){await atomicWriteFile(e,`${a}${r}`);return}let s=o.index+o[0].length;await atomicWriteFile(e,`${r.slice(0,s)}${a}${r.slice(s)}`)}async function rewriteWorkflowRuntimeImports(e){let n=await readTextFileIfPresent(e);if(n===null)return;let r=n;for(let e of[`workflow`,`workflow/api`,`workflow/internal/builtins`,`workflow/internal/private`,`workflow/runtime`]){let n=normalizeImportSpecifierPath(resolveWorkflowModulePath(e));r=replaceStringLiteralSpecifier(r,e,n)}r!==n&&await atomicWriteFile(e,r)}async function rewriteWorkflowCodeLiteral(e){let t=await readTextFileIfPresent(e);if(t===null)return;let n=`;\n\nexport const POST = workflowEntrypoint(workflowCode, { namespace: ${JSON.stringify(EVE_WORKFLOW_QUEUE_NAMESPACE)} });`,r=t.indexOf(`const workflowCode = `),i=t.lastIndexOf(n);if(r===-1||i===-1||i<=r)return;let a=r+21,o=t.slice(a,i);if(!o.trimStart().startsWith("`"))return;let s=decodeWorkflowCodeTemplateLiteral(o,e),c=`${t.slice(0,a)}${encodeWorkflowCodeLiteral(s)}${t.slice(i)}`;c!==t&&await atomicWriteFile(e,c)}function encodeWorkflowCodeLiteral(e){let t=Buffer.from(e,`utf8`).toString(`base64`).match(/.{1,16384}/g)??[``];return`Buffer.from(${JSON.stringify(t)}.join(""), "base64").toString("utf8")`}function decodeWorkflowCodeTemplateLiteral(e,t){let n=e.trim();if(!n.startsWith("`")||!n.endsWith("`"))throw Error(`Expected generated workflow code literal in "${t}" to be a template.`);let r=n.slice(1,-1),i=``;for(let e=0;e<r.length;e+=1){let t=r[e];if(t!==`\\`){i+=t;continue}let n=r[e+1];if(n===`\\`||n==="`"||n===`$`){i+=n,e+=1;continue}i+=t}return i}function replaceStringLiteralSpecifier(e,t,n){return e.replaceAll(JSON.stringify(t),JSON.stringify(n)).replaceAll(`'${t}'`,JSON.stringify(n))}function normalizeImportSpecifierPath(e){return normalizeEsmImportSpecifier(e)}function createRelativeImportSpecifier(e,t){let n=relative(e,t).replaceAll(`\\`,`/`);return n.startsWith(`.`)?n:`./${n}`}async function readTextFileIfPresent(e){try{return await readFile(e,`utf8`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}}async function readBinaryFileIfPresent(e){try{return await readFile(e)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}}async function mirrorFileBypassingUnlink(e,t){let n=await readFile(e),r=await readBinaryFileIfPresent(t);r!==null&&r.equals(n)||await atomicWriteFile(t,n)}export{WorkflowBundleBuilder};
@@ -1,3 +1,3 @@
1
- import{basename,dirname,extname,join,relative}from"node:path";import{cp,mkdir,readFile,readdir,realpath,rename,rm,symlink,writeFile}from"node:fs/promises";import{EVE_WORKFLOW_QUEUE_NAMESPACE,WORKFLOW_QUEUE_NAMESPACE_ENV}from"#internal/workflow/queue-namespace.js";import{buildWithNitroRolldown,getSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{EVE_SHARED_SERVER_FUNCTION_PATH,applyEveServiceRoutePrefixWrapper,isEveVercelFunctionPath,normalizeEveVercelRoutes}from"#internal/workflow-bundle/eve-service-route-output.js";const WORKFLOW_STEP_EXTERNAL_PACKAGES=[`@mongodb-js/zstd`,`just-bash`,`microsandbox`,`node-liblzma`],WORKFLOW_BUILDER_DEFERRED_PACKAGES=[`@chat-adapter/slack`,`chat`];function createWorkflowFunctionEnvironment(e){let t={};return isRecord(e)&&Object.assign(t,e),t.NODE_OPTIONS=`--experimental-require-module`,t[WORKFLOW_QUEUE_NAMESPACE_ENV]=EVE_WORKFLOW_QUEUE_NAMESPACE,t}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function prepareVercelFunctionDirectory(e){await rm(e,{force:!0,recursive:!0}),await mkdir(e,{recursive:!0})}async function resolveNitroFunctionDirectory(e){try{return await realpath(e.sourcePath)}catch{return await realpath(e.fallbackPath)}}async function copyNitroFunctionDirectory(e){let t=await resolveNitroFunctionDirectory({fallbackPath:e.fallbackPath,sourcePath:e.sourcePath});await prepareVercelFunctionDirectory(e.targetPath),await cp(t,e.targetPath,{dereference:!0,recursive:!0})}async function normalizeEveVercelFunctionOutput(e,t={}){let n=join(e,`functions`),i=await prepareSharedEveServerFunction(n);i!==null&&(t.servicePrefix!==void 0&&await applyEveServiceRoutePrefixWrapper(i,t.servicePrefix),await repointEveFunctionSymlinksInDirectory(n,i)),await pruneNonEveFunctionEntries(n,n),await pruneNonEveVercelRoutes(e,t.servicePrefix)}async function prepareSharedEveServerFunction(e){let n=join(e,`__server.func`),i=join(e,EVE_SHARED_SERVER_FUNCTION_PATH),s;try{s=await realpath(n)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}let c=`${i}.eve-staging`;return await mkdir(dirname(i),{recursive:!0}),await rm(c,{force:!0,recursive:!0}),await cp(s,c,{dereference:!0,recursive:!0}),await rm(i,{force:!0,recursive:!0}),await rename(c,i),i}async function repointEveFunctionSymlinksInDirectory(e,t,n=e){let a;try{a=await readdir(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(a.map(async a=>{let o=join(e,a.name),s=normalizeVercelOutputPath(relative(n,o));if(a.isSymbolicLink()){a.name.endsWith(`.func`)&&isEveVercelFunctionPath(s)&&await repointFunctionSymlink(o,t);return}a.isDirectory()&&!a.name.endsWith(`.func`)&&await repointEveFunctionSymlinksInDirectory(o,t,n)}))}async function repointFunctionSymlink(e,n){await rm(e,{force:!0,recursive:!0}),await symlink(normalizeVercelOutputPath(relative(dirname(e),n)),e,`dir`)}async function pruneNonEveFunctionEntries(e,t){let n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(n.map(async n=>{let a=join(t,n.name),o=normalizeVercelOutputPath(relative(e,a));if(n.name.endsWith(`.func`)){isEveVercelFunctionPath(o)||await rm(a,{force:!0,recursive:!0});return}n.isDirectory()&&await pruneNonEveFunctionEntries(e,a)}))}async function pruneNonEveVercelRoutes(e,t){let n=join(e,`config.json`),i;try{i=JSON.parse(await readFile(n,`utf8`))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}!isRecord(i)||!Array.isArray(i.routes)||(i.routes=normalizeEveVercelRoutes(i.routes,t),await writeFile(n,`${JSON.stringify(i,null,2)}\n`))}function normalizeVercelOutputPath(e){return e.replaceAll(`\\`,`/`)}async function emitBundledWorkflowFunctionDirectory(e){await prepareVercelFunctionDirectory(e.targetPath);let n=await emitBundledWorkflowPluginModules({build:buildWithNitroRolldown,pluginPaths:e.pluginPaths??[],targetPath:e.targetPath}),i=join(dirname(e.bundlePath),`__eve_workflow_function_entry.js`),a=getSingleRolldownChunk(await buildWithNitroRolldown({cwd:dirname(e.bundlePath),input:i,platform:`node`,plugins:[createVirtualModulePlugin({id:i,moduleType:`js`,source:createWorkflowFunctionEntrypointSource({bundlePath:e.bundlePath,pluginModulePaths:n})})],write:!1,output:{codeSplitting:!1,comments:!1,format:`cjs`,sourcemap:!1}}),`Vercel workflow function for "${e.bundlePath}"`);await Promise.all([writeFile(join(e.targetPath,`index.js`),a.code),writeFile(join(e.targetPath,`package.json`),`${JSON.stringify({type:`commonjs`},null,2)}\n`),writeFile(join(e.targetPath,`.vc-config.json`),`${JSON.stringify({environment:createWorkflowFunctionEnvironment(),handler:`index.js`,launcherType:`Nodejs`,supportsResponseStreaming:!0},null,2)}\n`)])}async function emitBundledWorkflowPluginModules(e){return await Promise.all(e.pluginPaths.map(async(t,n)=>{let i=getSingleRolldownChunk(await e.build({input:t,platform:`node`,write:!1,output:{codeSplitting:!1,comments:!1,format:`esm`,sourcemap:!1}}),`workflow plugin for "${t}"`),a=`__eve_workflow_plugin_${n}.mjs`;return await writeFile(join(e.targetPath,a),i.code),`./${a}`}))}function createVirtualModulePlugin(e){return{name:`eve-virtual-module`,resolveId(t){return t===e.id?e.id:void 0},load(t){return t===e.id?{code:e.source,moduleType:e.moduleType}:void 0}}}function toRelativeImportPath(e){let t=relative(e.fromDirectoryPath,e.toFilePath).replaceAll(`\\`,`/`);return t.startsWith(`.`)?t:`./${t}`}function normalizeImportSpecifierPath(e){return e.replaceAll(`\\`,`/`)}function createWorkflowFunctionEntrypointSource(t){let n=t.pluginModulePaths.map(e=>normalizeImportSpecifierPath(e)),r=n.length>0;return[`const { POST } = require(${JSON.stringify(`./${basename(t.bundlePath)}`)});`,...r?[`const workflowPluginModulePaths = ${JSON.stringify(n)};`,``,`let workflowPluginPromise;`,``,`async function loadWorkflowPlugins() {`,` if (workflowPluginPromise == null) {`,` workflowPluginPromise = (async () => {`,` for (const pluginPath of workflowPluginModulePaths) {`,` await import(pluginPath);`,` }`,` })();`,` }`,` return await workflowPluginPromise;`,`}`]:[],``,`const DEFAULT_WORKFLOW_REQUEST_ORIGIN = "https://workflow.invalid";`,``,`function getHeader(headers, name) {`,` if (headers === null || headers === undefined) {`,` return undefined;`,` }`,` if (typeof headers.get === "function") {`,` const value = headers.get(name);`,` return typeof value === "string" && value.length > 0 ? value : undefined;`,` }`,` if (typeof headers !== "object") {`,` return undefined;`,` }`,` const record = headers;`,` const lowerName = name.toLowerCase();`,` for (const [key, value] of Object.entries(record)) {`,` if (key.toLowerCase() !== lowerName || value === undefined) {`,` continue;`,` }`,` if (Array.isArray(value)) {`,` return value.find((item) => typeof item === "string" && item.length > 0);`,` }`,` return typeof value === "string" && value.length > 0 ? value : undefined;`,` }`,` return undefined;`,`}`,``,`function createHeaders(headers) {`,` const normalized = new Headers();`,` if (headers === null || headers === undefined) {`,` return normalized;`,` }`,` if (headers instanceof Headers) {`,` return headers;`,` }`,` if (typeof headers.forEach === "function" && typeof headers.entries === "function") {`,` for (const [key, value] of headers.entries()) {`,` normalized.append(key, value);`,` }`,` return normalized;`,` }`,` for (const [key, value] of Object.entries(headers)) {`,` if (value === undefined) {`,` continue;`,` }`,` if (Array.isArray(value)) {`,` for (const item of value) {`,` normalized.append(key, String(item));`,` }`,` continue;`,` }`,` normalized.set(key, String(value));`,` }`,` return normalized;`,`}`,``,`function toAbsoluteWorkflowUrl(request) {`,` const url = typeof request?.url === "string" ? request.url : "/";`,` if (/^https?:\\/\\//.test(url)) {`,` return url;`,` }`,` const host = getHeader(request?.headers, "x-forwarded-host") ?? getHeader(request?.headers, "host");`,` const protocolHeader = getHeader(request?.headers, "x-forwarded-proto");`,` const protocol = protocolHeader === "http" || protocolHeader === "https" ? protocolHeader : "https";`,` const origin = typeof host === "string" && host.length > 0 ? protocol + "://" + host : DEFAULT_WORKFLOW_REQUEST_ORIGIN;`,` return new URL(url, origin).toString();`,`}`,``,`function normalizeWorkflowRequest(request) {`,` if (request instanceof Request) {`,` if (/^https?:\\/\\//.test(request.url)) {`,` return request;`,` }`,` return new Request(toAbsoluteWorkflowUrl(request), request);`,` }`,` const method = typeof request?.method === "string" ? request.method : "GET";`,` const headers = createHeaders(request?.headers);`,` const init = {`,` headers,`,` method,`,` };`,` if (method !== "GET" && method !== "HEAD") {`,` const body = request?.body ?? (request !== null && typeof request === "object" && typeof request.pipe === "function" ? request : undefined);`,` if (body !== undefined) {`,` init.body = body;`,` init.duplex = "half";`,` }`,` }`,` return new Request(toAbsoluteWorkflowUrl(request), init);`,`}`,``,`module.exports = async function handleWorkflowFunctionRequest(requestContext) {`,` const request =`,` requestContext !== null && typeof requestContext === "object" && "req" in requestContext`,` ? requestContext.req`,` : requestContext;`,...r?[` await loadWorkflowPlugins();`]:[],` return await POST(normalizeWorkflowRequest(request));`,`};`,``].join(`
1
+ import{basename,dirname,extname,join,relative}from"node:path";import{cp,mkdir,readFile,readdir,realpath,rename,rm,symlink,writeFile}from"node:fs/promises";import{buildWithNitroRolldown,getSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{EVE_SHARED_SERVER_FUNCTION_PATH,applyEveServiceRoutePrefixWrapper,isEveVercelFunctionPath,normalizeEveVercelRoutes}from"#internal/workflow-bundle/eve-service-route-output.js";const WORKFLOW_STEP_EXTERNAL_PACKAGES=[`@mongodb-js/zstd`,`just-bash`,`microsandbox`,`node-liblzma`],WORKFLOW_BUILDER_DEFERRED_PACKAGES=[`@chat-adapter/slack`,`chat`];function createWorkflowFunctionEnvironment(e){let t={};return isRecord(e)&&Object.assign(t,e),t.NODE_OPTIONS=`--experimental-require-module`,t}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function prepareVercelFunctionDirectory(e){await rm(e,{force:!0,recursive:!0}),await mkdir(e,{recursive:!0})}async function resolveNitroFunctionDirectory(e){try{return await realpath(e.sourcePath)}catch{return await realpath(e.fallbackPath)}}async function copyNitroFunctionDirectory(e){let t=await resolveNitroFunctionDirectory({fallbackPath:e.fallbackPath,sourcePath:e.sourcePath});await prepareVercelFunctionDirectory(e.targetPath),await cp(t,e.targetPath,{dereference:!0,recursive:!0})}async function normalizeEveVercelFunctionOutput(e,t={}){let n=join(e,`functions`),i=await prepareSharedEveServerFunction(n);i!==null&&(t.servicePrefix!==void 0&&await applyEveServiceRoutePrefixWrapper(i,t.servicePrefix),await repointEveFunctionSymlinksInDirectory(n,i)),await pruneNonEveFunctionEntries(n,n),await pruneNonEveVercelRoutes(e,t.servicePrefix)}async function prepareSharedEveServerFunction(e){let n=join(e,`__server.func`),i=join(e,EVE_SHARED_SERVER_FUNCTION_PATH),s;try{s=await realpath(n)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}let c=`${i}.eve-staging`;return await mkdir(dirname(i),{recursive:!0}),await rm(c,{force:!0,recursive:!0}),await cp(s,c,{dereference:!0,recursive:!0}),await rm(i,{force:!0,recursive:!0}),await rename(c,i),i}async function repointEveFunctionSymlinksInDirectory(e,t,n=e){let a;try{a=await readdir(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(a.map(async a=>{let o=join(e,a.name),s=normalizeVercelOutputPath(relative(n,o));if(a.isSymbolicLink()){a.name.endsWith(`.func`)&&isEveVercelFunctionPath(s)&&await repointFunctionSymlink(o,t);return}a.isDirectory()&&!a.name.endsWith(`.func`)&&await repointEveFunctionSymlinksInDirectory(o,t,n)}))}async function repointFunctionSymlink(e,n){await rm(e,{force:!0,recursive:!0}),await symlink(normalizeVercelOutputPath(relative(dirname(e),n)),e,`dir`)}async function pruneNonEveFunctionEntries(e,t){let n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(n.map(async n=>{let a=join(t,n.name),o=normalizeVercelOutputPath(relative(e,a));if(n.name.endsWith(`.func`)){isEveVercelFunctionPath(o)||await rm(a,{force:!0,recursive:!0});return}n.isDirectory()&&await pruneNonEveFunctionEntries(e,a)}))}async function pruneNonEveVercelRoutes(e,t){let n=join(e,`config.json`),i;try{i=JSON.parse(await readFile(n,`utf8`))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}!isRecord(i)||!Array.isArray(i.routes)||(i.routes=normalizeEveVercelRoutes(i.routes,t),await writeFile(n,`${JSON.stringify(i,null,2)}\n`))}function normalizeVercelOutputPath(e){return e.replaceAll(`\\`,`/`)}async function emitBundledWorkflowFunctionDirectory(e){await prepareVercelFunctionDirectory(e.targetPath);let n=await emitBundledWorkflowPluginModules({build:buildWithNitroRolldown,pluginPaths:e.pluginPaths??[],targetPath:e.targetPath}),i=join(dirname(e.bundlePath),`__eve_workflow_function_entry.js`),a=getSingleRolldownChunk(await buildWithNitroRolldown({cwd:dirname(e.bundlePath),input:i,platform:`node`,plugins:[createVirtualModulePlugin({id:i,moduleType:`js`,source:createWorkflowFunctionEntrypointSource({bundlePath:e.bundlePath,pluginModulePaths:n})})],write:!1,output:{codeSplitting:!1,comments:!1,format:`cjs`,sourcemap:!1}}),`Vercel workflow function for "${e.bundlePath}"`);await Promise.all([writeFile(join(e.targetPath,`index.js`),a.code),writeFile(join(e.targetPath,`package.json`),`${JSON.stringify({type:`commonjs`},null,2)}\n`),writeFile(join(e.targetPath,`.vc-config.json`),`${JSON.stringify({environment:createWorkflowFunctionEnvironment(),handler:`index.js`,launcherType:`Nodejs`,supportsResponseStreaming:!0},null,2)}\n`)])}async function emitBundledWorkflowPluginModules(e){return await Promise.all(e.pluginPaths.map(async(t,n)=>{let i=getSingleRolldownChunk(await e.build({input:t,platform:`node`,write:!1,output:{codeSplitting:!1,comments:!1,format:`esm`,sourcemap:!1}}),`workflow plugin for "${t}"`),a=`__eve_workflow_plugin_${n}.mjs`;return await writeFile(join(e.targetPath,a),i.code),`./${a}`}))}function createVirtualModulePlugin(e){return{name:`eve-virtual-module`,resolveId(t){return t===e.id?e.id:void 0},load(t){return t===e.id?{code:e.source,moduleType:e.moduleType}:void 0}}}function toRelativeImportPath(e){let t=relative(e.fromDirectoryPath,e.toFilePath).replaceAll(`\\`,`/`);return t.startsWith(`.`)?t:`./${t}`}function normalizeImportSpecifierPath(e){return e.replaceAll(`\\`,`/`)}function createWorkflowFunctionEntrypointSource(t){let n=t.pluginModulePaths.map(e=>normalizeImportSpecifierPath(e)),r=n.length>0;return[`const { POST } = require(${JSON.stringify(`./${basename(t.bundlePath)}`)});`,...r?[`const workflowPluginModulePaths = ${JSON.stringify(n)};`,``,`let workflowPluginPromise;`,``,`async function loadWorkflowPlugins() {`,` if (workflowPluginPromise == null) {`,` workflowPluginPromise = (async () => {`,` for (const pluginPath of workflowPluginModulePaths) {`,` await import(pluginPath);`,` }`,` })();`,` }`,` return await workflowPluginPromise;`,`}`]:[],``,`const DEFAULT_WORKFLOW_REQUEST_ORIGIN = "https://workflow.invalid";`,``,`function getHeader(headers, name) {`,` if (headers === null || headers === undefined) {`,` return undefined;`,` }`,` if (typeof headers.get === "function") {`,` const value = headers.get(name);`,` return typeof value === "string" && value.length > 0 ? value : undefined;`,` }`,` if (typeof headers !== "object") {`,` return undefined;`,` }`,` const record = headers;`,` const lowerName = name.toLowerCase();`,` for (const [key, value] of Object.entries(record)) {`,` if (key.toLowerCase() !== lowerName || value === undefined) {`,` continue;`,` }`,` if (Array.isArray(value)) {`,` return value.find((item) => typeof item === "string" && item.length > 0);`,` }`,` return typeof value === "string" && value.length > 0 ? value : undefined;`,` }`,` return undefined;`,`}`,``,`function createHeaders(headers) {`,` const normalized = new Headers();`,` if (headers === null || headers === undefined) {`,` return normalized;`,` }`,` if (headers instanceof Headers) {`,` return headers;`,` }`,` if (typeof headers.forEach === "function" && typeof headers.entries === "function") {`,` for (const [key, value] of headers.entries()) {`,` normalized.append(key, value);`,` }`,` return normalized;`,` }`,` for (const [key, value] of Object.entries(headers)) {`,` if (value === undefined) {`,` continue;`,` }`,` if (Array.isArray(value)) {`,` for (const item of value) {`,` normalized.append(key, String(item));`,` }`,` continue;`,` }`,` normalized.set(key, String(value));`,` }`,` return normalized;`,`}`,``,`function toAbsoluteWorkflowUrl(request) {`,` const url = typeof request?.url === "string" ? request.url : "/";`,` if (/^https?:\\/\\//.test(url)) {`,` return url;`,` }`,` const host = getHeader(request?.headers, "x-forwarded-host") ?? getHeader(request?.headers, "host");`,` const protocolHeader = getHeader(request?.headers, "x-forwarded-proto");`,` const protocol = protocolHeader === "http" || protocolHeader === "https" ? protocolHeader : "https";`,` const origin = typeof host === "string" && host.length > 0 ? protocol + "://" + host : DEFAULT_WORKFLOW_REQUEST_ORIGIN;`,` return new URL(url, origin).toString();`,`}`,``,`function normalizeWorkflowRequest(request) {`,` if (request instanceof Request) {`,` if (/^https?:\\/\\//.test(request.url)) {`,` return request;`,` }`,` return new Request(toAbsoluteWorkflowUrl(request), request);`,` }`,` const method = typeof request?.method === "string" ? request.method : "GET";`,` const headers = createHeaders(request?.headers);`,` const init = {`,` headers,`,` method,`,` };`,` if (method !== "GET" && method !== "HEAD") {`,` const body = request?.body ?? (request !== null && typeof request === "object" && typeof request.pipe === "function" ? request : undefined);`,` if (body !== undefined) {`,` init.body = body;`,` init.duplex = "half";`,` }`,` }`,` return new Request(toAbsoluteWorkflowUrl(request), init);`,`}`,``,`module.exports = async function handleWorkflowFunctionRequest(requestContext) {`,` const request =`,` requestContext !== null && typeof requestContext === "object" && "req" in requestContext`,` ? requestContext.req`,` : requestContext;`,...r?[` await loadWorkflowPlugins();`]:[],` return await POST(normalizeWorkflowRequest(request));`,`};`,``].join(`
2
2
  `)}function createRoutedNitroEntrypoint(e){return[`import nitroHandler from ${JSON.stringify(e.delegateImportPath)};`,``,`function invokeNitroHandler(request, context) {`,` if (typeof nitroHandler === "function") {`,` return nitroHandler(request, context);`,` }`,``,` if (nitroHandler !== null && typeof nitroHandler === "object" && "fetch" in nitroHandler) {`,` const fetch = nitroHandler.fetch;`,` if (typeof fetch === "function") {`,` return fetch.call(nitroHandler, request, context);`,` }`,` }`,``,` throw new TypeError("Expected Nitro handler to export a function or an object with fetch(request, context).");`,`}`,``,`const workflowRoutePath = ${JSON.stringify(e.workflowRoutePath)};`,``,`function rewriteRequestToWorkflowRoute(request) {`,` const sourceUrl = new URL(request.url);`,` const routedUrl = new URL(workflowRoutePath, sourceUrl);`,` routedUrl.search = sourceUrl.search;`,` return new Request(routedUrl, request);`,`}`,``,`export default {`,` fetch(request, context) {`,` return invokeNitroHandler(rewriteRequestToWorkflowRoute(request), context);`,` },`,`};`,``].join(`
3
3
  `)}async function readVercelHandlerPath(e){try{let t=JSON.parse(await readFile(join(e,`.vc-config.json`),`utf8`));if(typeof t.handler==`string`&&t.handler.length>0)return t.handler}catch{}return`index.mjs`}async function retargetNitroFunctionDirectoryToWorkflowRoute(e){let i=await readVercelHandlerPath(e.functionDirectoryPath),a=join(e.functionDirectoryPath,i),o=dirname(a),s=extname(i),c=join(o,`__eve_nitro_handler__${s.length>0?s:`.mjs`}`),l=toRelativeImportPath({fromDirectoryPath:o,toFilePath:c});await rename(a,c),await writeFile(a,createRoutedNitroEntrypoint({delegateImportPath:l,workflowRoutePath:e.workflowRoutePath}))}export{WORKFLOW_BUILDER_DEFERRED_PACKAGES,WORKFLOW_STEP_EXTERNAL_PACKAGES,copyNitroFunctionDirectory,createWorkflowFunctionEnvironment,emitBundledWorkflowFunctionDirectory,normalizeEveVercelFunctionOutput,prepareVercelFunctionDirectory,retargetNitroFunctionDirectoryToWorkflowRoute};
@@ -1,4 +1,4 @@
1
- import { type GitHubIssueCommentEvent, type GitHubIssueWebhookEvent, type GitHubPullRequestReviewCommentEvent, type GitHubPullRequestWebhookEvent } from "#public/channels/github/inbound.js";
1
+ import { type GitHubCheckRunWebhookEvent, type GitHubCheckSuiteWebhookEvent, type GitHubIssueCommentEvent, type GitHubIssueWebhookEvent, type GitHubPullRequestReviewCommentEvent, type GitHubPullRequestWebhookEvent, type GitHubWorkflowRunWebhookEvent } from "#public/channels/github/inbound.js";
2
2
  import { type GitHubChannelState } from "#public/channels/github/state.js";
3
3
  import type { GitHubChannelConfig } from "#public/channels/github/githubChannel.js";
4
4
  import type { SendFn } from "#public/definitions/defineChannel.js";
@@ -32,3 +32,24 @@ export declare function dispatchPullRequest(input: {
32
32
  readonly handler: NonNullable<GitHubChannelConfig["onPullRequest"]>;
33
33
  readonly send: SendFn<GitHubChannelState>;
34
34
  }): Promise<void>;
35
+ /** Dispatches an opt-in check-suite webhook event into the runtime. */
36
+ export declare function dispatchCheckSuite(input: {
37
+ readonly config: GitHubChannelConfig;
38
+ readonly event: GitHubCheckSuiteWebhookEvent;
39
+ readonly handler: NonNullable<GitHubChannelConfig["onCheckSuite"]>;
40
+ readonly send: SendFn<GitHubChannelState>;
41
+ }): Promise<void>;
42
+ /** Dispatches an opt-in check-run webhook event into the runtime. */
43
+ export declare function dispatchCheckRun(input: {
44
+ readonly config: GitHubChannelConfig;
45
+ readonly event: GitHubCheckRunWebhookEvent;
46
+ readonly handler: NonNullable<GitHubChannelConfig["onCheckRun"]>;
47
+ readonly send: SendFn<GitHubChannelState>;
48
+ }): Promise<void>;
49
+ /** Dispatches an opt-in workflow-run webhook event into the runtime. */
50
+ export declare function dispatchWorkflowRun(input: {
51
+ readonly config: GitHubChannelConfig;
52
+ readonly event: GitHubWorkflowRunWebhookEvent;
53
+ readonly handler: NonNullable<GitHubChannelConfig["onWorkflowRun"]>;
54
+ readonly send: SendFn<GitHubChannelState>;
55
+ }): Promise<void>;
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{extractGitHubCommentTrigger,formatGitHubContextBlock,prependGitHubContext}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{buildGitHubPullRequestContext,mergeGitHubContext}from"#public/channels/github/pr-context.js";import{continuationTokenFromState,stateFromIssueCommentEvent,stateFromIssueEvent,stateFromPullRequestEvent,stateFromPullRequestReviewCommentEvent}from"#public/channels/github/state.js";const log=createLogger(`github.dispatch`);async function dispatchIssueComment(e){if(isIgnoredInboundComment(e.event.comment.body,e.event.comment.author,e.botName))return;let t=buildInboundContext(e.config,e.event);await dispatchCommentTurn({body:e.event.comment.body,botName:e.botName,commentUrl:e.event.comment.htmlUrl,event:e.event,handlerResult:()=>e.handler(t,toGitHubComment(e.event.comment)),config:e.config,send:e.send,state:stateFromIssueCommentEvent(e.event)})}async function dispatchPullRequestReviewComment(e){if(isIgnoredInboundComment(e.event.comment.body,e.event.comment.author,e.botName))return;let t=buildInboundContext(e.config,e.event);await dispatchCommentTurn({body:e.event.comment.body,botName:e.botName,commentUrl:e.event.comment.htmlUrl,event:e.event,handlerResult:()=>e.handler(t,toGitHubComment(e.event.comment)),config:e.config,send:e.send,state:stateFromPullRequestReviewCommentEvent(e.event)})}async function dispatchIssue(e){let t=buildInboundContext(e.config,e.event);await dispatchWebhookEventTurn({config:e.config,event:e.event,handlerResult:()=>e.handler(t,e.event.issue),message:formatIssueEventMessage(e.event),send:e.send,state:stateFromIssueEvent(e.event)})}async function dispatchPullRequest(e){let t=buildInboundContext(e.config,e.event);await dispatchWebhookEventTurn({config:e.config,event:e.event,handlerResult:()=>e.handler(t,e.event.pullRequest),message:formatPullRequestEventMessage(e.event),send:e.send,state:stateFromPullRequestEvent(e.event)})}async function dispatchWebhookEventTurn(e){let t=await runInboundHandler({event:e.event,handlerResult:e.handlerResult});t!=null&&await sendGitHubTurn({auth:t.auth,event:e.event,message:e.message,context:mergeGitHubContext({github:await buildPullRequestContext(e.config,e.state,e.event.delivery.id),hook:t.context}),send:e.send,state:e.state})}async function dispatchCommentTurn(e){let t=await runInboundHandler({event:e.event,handlerResult:e.handlerResult});if(t==null)return;let r=extractGitHubCommentTrigger({body:e.body,botName:e.botName})?.message??e.body.trim();await sendGitHubTurn({auth:t.auth,commentUrl:e.commentUrl,event:e.event,message:r,context:mergeGitHubContext({github:await buildPullRequestContext(e.config,e.state,e.event.delivery.id),hook:t.context}),send:e.send,state:e.state})}async function runInboundHandler(e){try{return await e.handlerResult()}catch(n){logError(log,`GitHub inbound handler failed`,n,{deliveryId:e.event.delivery.id});return}}async function sendGitHubTurn(e){let n=formatGitHubContextBlock({deliveryId:e.event.delivery.id,commentUrl:e.commentUrl,headSha:e.state.headSha,issueNumber:e.state.issueNumber,pullRequestNumber:e.state.pullRequestNumber,repository:e.event.repository,sender:e.event.sender}),i=prependGitHubContext(e.message,n);try{await e.send({message:i,context:e.context},{auth:e.auth,continuationToken:continuationTokenFromState(e.state),state:e.state})}catch(n){logError(log,e.logMessage??`GitHub delivery failed`,n,{deliveryId:e.event.delivery.id})}}async function buildPullRequestContext(e,n,r){try{return await buildGitHubPullRequestContext({api:e.api,baseSha:n.baseSha,config:e.pullRequestContext,credentials:e.credentials,headSha:n.headSha,installationId:n.installationId??void 0,owner:n.owner,pullRequestNumber:n.pullRequestNumber,repo:n.repo})}catch(e){logError(log,`GitHub pull-request context failed — swallowed`,e,{deliveryId:r});return}}function buildInboundContext(e,t){let n=buildGitHubBinding({config:e,state:t.kind===`issue_comment`?stateFromIssueCommentEvent(t):t.kind===`issues`?stateFromIssueEvent(t):t.kind===`pull_request`?stateFromPullRequestEvent(t):stateFromPullRequestReviewCommentEvent(t)});return{conversation:t.conversation,delivery:t.delivery,github:n.github,repository:t.repository,sender:t.sender,thread:n.thread}}function toGitHubComment(e){return{author:e.author,body:e.body,htmlUrl:e.htmlUrl,id:e.id,raw:e.raw,url:e.url}}function formatIssueEventMessage(e){let t=readString(e.issue.raw.title);return`Issue ${e.issue.action}: #${e.issue.issueNumber}${t?` ${t}`:``}`}function formatPullRequestEventMessage(e){let t=readString(e.pullRequest.raw.title);return`Pull request ${e.pullRequest.action}: #${e.pullRequest.pullRequestNumber}${t?` ${t}`:``}`}function isIgnoredInboundComment(e,t,n){if(e.includes(`<!-- eve:github:`)||t?.type===`Bot`)return!0;let r=n?`${n}[bot]`.toLowerCase():``;return r.length>0&&t?.login.toLowerCase()===r}function readString(e){return typeof e==`string`&&e.trim().length>0?e.trim():void 0}export{dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment};
1
+ import{createLogger,logError}from"#internal/logging.js";import{extractGitHubCommentTrigger,formatGitHubContextBlock,prependGitHubContext}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{buildGitHubPullRequestContext,mergeGitHubContext}from"#public/channels/github/pr-context.js";import{continuationTokenFromState,stateFromCiEvent,stateFromIssueCommentEvent,stateFromIssueEvent,stateFromPullRequestEvent,stateFromPullRequestReviewCommentEvent}from"#public/channels/github/state.js";const log=createLogger(`github.dispatch`);async function dispatchIssueComment(e){if(isIgnoredInboundComment(e.event.comment.body,e.event.comment.author,e.botName))return;let t=buildInboundContext(e.config,e.event);await dispatchCommentTurn({body:e.event.comment.body,botName:e.botName,commentUrl:e.event.comment.htmlUrl,event:e.event,handlerResult:()=>e.handler(t,toGitHubComment(e.event.comment)),config:e.config,send:e.send,state:stateFromIssueCommentEvent(e.event)})}async function dispatchPullRequestReviewComment(e){if(isIgnoredInboundComment(e.event.comment.body,e.event.comment.author,e.botName))return;let t=buildInboundContext(e.config,e.event);await dispatchCommentTurn({body:e.event.comment.body,botName:e.botName,commentUrl:e.event.comment.htmlUrl,event:e.event,handlerResult:()=>e.handler(t,toGitHubComment(e.event.comment)),config:e.config,send:e.send,state:stateFromPullRequestReviewCommentEvent(e.event)})}async function dispatchIssue(e){let t=buildInboundContext(e.config,e.event);await dispatchWebhookEventTurn({config:e.config,event:e.event,handlerResult:()=>e.handler(t,e.event.issue),message:formatIssueEventMessage(e.event),send:e.send,state:stateFromIssueEvent(e.event)})}async function dispatchPullRequest(e){let t=buildInboundContext(e.config,e.event);await dispatchWebhookEventTurn({config:e.config,event:e.event,handlerResult:()=>e.handler(t,e.event.pullRequest),message:formatPullRequestEventMessage(e.event),send:e.send,state:stateFromPullRequestEvent(e.event)})}async function dispatchCheckSuite(e){await dispatchCiEvent({...e,ci:e.event.checkSuite,handlerResult:t=>e.handler(t,e.event.checkSuite),label:`Check suite`})}async function dispatchCheckRun(e){await dispatchCiEvent({...e,ci:e.event.checkRun,handlerResult:t=>e.handler(t,e.event.checkRun),label:`Check run`})}async function dispatchWorkflowRun(e){await dispatchCiEvent({...e,ci:e.event.workflowRun,handlerResult:t=>e.handler(t,e.event.workflowRun),label:`Workflow run`})}async function dispatchCiEvent(e){let t=stateFromCiEvent(e.event),n=buildInboundContext(e.config,e.event);if(t.pullRequestNumber===null){await runInboundHandler({event:e.event,handlerResult:()=>e.handlerResult(n)})!=null&&log.warn(`GitHub CI event cannot dispatch without an associated pull request`,{deliveryId:e.event.delivery.id,event:e.event.kind});return}await dispatchWebhookEventTurn({config:e.config,event:e.event,handlerResult:()=>e.handlerResult(n),message:formatCiEventMessage(e.label,e.ci),send:e.send,state:t})}async function dispatchWebhookEventTurn(e){let t=await runInboundHandler({event:e.event,handlerResult:e.handlerResult});t!=null&&await sendGitHubTurn({auth:t.auth,event:e.event,message:e.message,context:mergeGitHubContext({github:await buildPullRequestContext(e.config,e.state,e.event.delivery.id),hook:t.context}),send:e.send,state:e.state})}async function dispatchCommentTurn(e){let t=await runInboundHandler({event:e.event,handlerResult:e.handlerResult});if(t==null)return;let r=extractGitHubCommentTrigger({body:e.body,botName:e.botName})?.message??e.body.trim();await sendGitHubTurn({auth:t.auth,commentUrl:e.commentUrl,event:e.event,message:r,context:mergeGitHubContext({github:await buildPullRequestContext(e.config,e.state,e.event.delivery.id),hook:t.context}),send:e.send,state:e.state})}async function runInboundHandler(e){try{return await e.handlerResult()}catch(n){logError(log,`GitHub inbound handler failed`,n,{deliveryId:e.event.delivery.id});return}}async function sendGitHubTurn(e){let n=formatGitHubContextBlock({deliveryId:e.event.delivery.id,commentUrl:e.commentUrl,headSha:e.state.headSha,issueNumber:e.state.issueNumber,pullRequestNumber:e.state.pullRequestNumber,repository:e.event.repository,sender:e.event.sender}),i=prependGitHubContext(e.message,n);try{await e.send({message:i,context:e.context},{auth:e.auth,continuationToken:continuationTokenFromState(e.state),state:e.state})}catch(n){logError(log,e.logMessage??`GitHub delivery failed`,n,{deliveryId:e.event.delivery.id})}}async function buildPullRequestContext(e,n,r){try{return await buildGitHubPullRequestContext({api:e.api,baseSha:n.baseSha,config:e.pullRequestContext,credentials:e.credentials,headSha:n.headSha,installationId:n.installationId??void 0,owner:n.owner,pullRequestNumber:n.pullRequestNumber,repo:n.repo})}catch(e){logError(log,`GitHub pull-request context failed — swallowed`,e,{deliveryId:r});return}}function buildInboundContext(e,t){let n=buildGitHubBinding({config:e,state:t.kind===`check_suite`||t.kind===`check_run`||t.kind===`workflow_run`?stateFromCiEvent(t):t.kind===`issue_comment`?stateFromIssueCommentEvent(t):t.kind===`issues`?stateFromIssueEvent(t):t.kind===`pull_request`?stateFromPullRequestEvent(t):stateFromPullRequestReviewCommentEvent(t)});return{conversation:t.conversation,delivery:t.delivery,github:n.github,repository:t.repository,sender:t.sender,thread:n.thread}}function toGitHubComment(e){return{author:e.author,body:e.body,htmlUrl:e.htmlUrl,id:e.id,raw:e.raw,url:e.url}}function formatIssueEventMessage(e){let t=readString(e.issue.raw.title);return`Issue ${e.issue.action}: #${e.issue.issueNumber}${t?` ${t}`:``}`}function formatPullRequestEventMessage(e){let t=readString(e.pullRequest.raw.title);return`Pull request ${e.pullRequest.action}: #${e.pullRequest.pullRequestNumber}${t?` ${t}`:``}`}function formatCiEventMessage(e,t){let n=t.conclusion??t.status;return`${e} ${t.action}: ${ciEventId(t)}${n?` (${n})`:``}`}function ciEventId(e){return`checkSuiteId`in e?e.checkSuiteId:`checkRunId`in e?e.checkRunId:e.workflowRunId}function isIgnoredInboundComment(e,t,n){if(e.includes(`<!-- eve:github:`)||t?.type===`Bot`)return!0;let r=n?`${n}[bot]`.toLowerCase():``;return r.length>0&&t?.login.toLowerCase()===r}function readString(e){return typeof e==`string`&&e.trim().length>0?e.trim():void 0}export{dispatchCheckRun,dispatchCheckSuite,dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment,dispatchWorkflowRun};
@@ -5,7 +5,7 @@ import type { HandleMessageStreamEvent } from "#protocol/message.js";
5
5
  import { type GitHubHandle, type GitHubThread } from "#public/channels/github/binding.js";
6
6
  import { type GitHubApiOptions } from "#public/channels/github/api.js";
7
7
  import type { GitHubChannelCredentials } from "#public/channels/github/auth.js";
8
- import { type GitHubComment, type GitHubConversationRef, type GitHubDelivery, type GitHubIssueEvent, type GitHubPullRequestEvent, type GitHubRepositoryRef, type GitHubUser } from "#public/channels/github/inbound.js";
8
+ import { type GitHubCheckRunEvent, type GitHubCheckSuiteEvent, type GitHubComment, type GitHubConversationRef, type GitHubDelivery, type GitHubIssueEvent, type GitHubPullRequestEvent, type GitHubRepositoryRef, type GitHubUser, type GitHubWorkflowRunEvent } from "#public/channels/github/inbound.js";
9
9
  import { type GitHubChannelState } from "#public/channels/github/state.js";
10
10
  import type { GitHubPullRequestContextConfig } from "#public/channels/github/pr-context.js";
11
11
  import { type Channel } from "#public/definitions/defineChannel.js";
@@ -63,8 +63,8 @@ export type GitHubInboundResult = {
63
63
  readonly context?: readonly string[];
64
64
  } | null;
65
65
  /**
66
- * Return type of the `onComment`/`onIssue`/`onPullRequest` hooks: a
67
- * {@link GitHubInboundResult} or a promise for one.
66
+ * Return type of GitHub inbound hooks: a {@link GitHubInboundResult} or a
67
+ * promise for one.
68
68
  */
69
69
  export type GitHubInboundResultOrPromise = GitHubInboundResult | Promise<GitHubInboundResult>;
70
70
  type GitHubEventHandler<T extends HandleMessageStreamEvent["type"]> = (data: EventData<T>, channel: GitHubEventContext, ctx: SessionContext) => void | Promise<void>;
@@ -107,6 +107,18 @@ export interface GitHubChannelConfig {
107
107
  * mention gate.
108
108
  */
109
109
  onComment?(ctx: GitHubInboundContext, comment: GitHubComment): GitHubInboundResultOrPromise;
110
+ /**
111
+ * Opt-in handler for `check_suite` webhook events. There is no default
112
+ * dispatch. A dispatched turn is anchored to the first associated pull
113
+ * request.
114
+ */
115
+ onCheckSuite?(ctx: GitHubInboundContext, checkSuite: GitHubCheckSuiteEvent): GitHubInboundResultOrPromise;
116
+ /**
117
+ * Opt-in handler for `check_run` webhook events. There is no default
118
+ * dispatch. A dispatched turn is anchored to the first associated pull
119
+ * request.
120
+ */
121
+ onCheckRun?(ctx: GitHubInboundContext, checkRun: GitHubCheckRunEvent): GitHubInboundResultOrPromise;
110
122
  /**
111
123
  * Opt-in handler for `issues` webhook events. There is no default dispatch;
112
124
  * define this to act on issues (e.g. `issue.action === "opened"`).
@@ -117,6 +129,12 @@ export interface GitHubChannelConfig {
117
129
  * dispatch; define this to act on PRs (e.g. `pullRequest.action === "opened"`).
118
130
  */
119
131
  onPullRequest?(ctx: GitHubInboundContext, pullRequest: GitHubPullRequestEvent): GitHubInboundResultOrPromise;
132
+ /**
133
+ * Opt-in handler for `workflow_run` webhook events. There is no default
134
+ * dispatch. A dispatched turn is anchored to the first associated pull
135
+ * request.
136
+ */
137
+ onWorkflowRun?(ctx: GitHubInboundContext, workflowRun: GitHubWorkflowRunEvent): GitHubInboundResultOrPromise;
120
138
  }
121
139
  /** Concrete return type of {@link githubChannel}. */
122
140
  export interface GitHubChannel extends Channel<GitHubChannelState, GitHubReceiveTarget> {
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{getGitHubRepository}from"#public/channels/github/api.js";import{parseGitHubWebhookEvent}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromReceiveTarget}from"#public/channels/github/state.js";import{GITHUB_CHANNEL_DEFAULT_ROUTE}from"#public/channels/github/constants.js";import{createDefaultEvents,defaultOnComment}from"#public/channels/github/defaults.js";import{dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment}from"#public/channels/github/dispatch.js";import{verifyGitHubRequest}from"#public/channels/github/verify.js";const log=createLogger(`github.channel`);function githubChannel(e={}){let s=e.botName??process.env.GITHUB_APP_SLUG,u={botName:s},d={...createDefaultEvents({api:e.api,credentials:e.credentials,progress:e.progress}),...e.events};return defineChannel({kindHint:`github`,state:initialGitHubState(),context(t,n){return rebuildGitHubContext(t,n,e)},routes:[POST(e.route??GITHUB_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let a=await verifyInbound(t,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseGitHubWebhookEvent({body:a,contentType:t.headers.get(`content-type`)??void 0,headers:t.headers})}catch(e){return log.warn(`inbound GitHub body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`ping`?jsonOk({ok:!0}):o.kind===`issue_comment`&&o.action===`created`?(r(dispatchIssueComment({botName:s,config:e,event:o,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):o.kind===`pull_request_review_comment`&&o.action===`created`?(r(dispatchPullRequestReviewComment({botName:s,config:e,event:o,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):o.kind===`issues`&&e.onIssue!==void 0?(r(dispatchIssue({config:e,event:o,handler:e.onIssue,send:n})),jsonOk({ok:!0})):o.kind===`pull_request`&&e.onPullRequest!==void 0?(r(dispatchPullRequest({config:e,event:o,handler:e.onPullRequest,send:n})),jsonOk({ok:!0})):jsonOk({ignored:!0,ok:!0})})],async receive(t,{send:n}){let i=t.target,s=readNonEmptyString(i.owner),c=readNonEmptyString(i.repo);if(s===void 0||c===void 0)throw Error(`githubChannel().receive requires target.owner and target.repo.`);if([i.issueNumber!==void 0,i.pullRequestNumber!==void 0].filter(Boolean).length!==1)throw Error(`githubChannel().receive requires exactly one of issueNumber or pullRequestNumber.`);let l=stateFromReceiveTarget({target:i,owner:s,repo:c,repositoryId:i.repositoryId??(await getGitHubRepository({api:e.api,credentials:e.credentials,installationId:i.installationId,owner:s,repo:c})).id});if(i.initialMessage!==void 0){let{thread:t}=buildGitHubBinding({config:e,state:l});await t.post(i.initialMessage)}return n(t.message,{auth:t.auth,continuationToken:continuationTokenFromState(l),state:l})},events:d})}function rebuildGitHubContext(e,t,n){let r=buildGitHubBinding({config:n,state:e});return{conversation:conversationFromState(e),github:r.github,repository:r.github.repository,state:e,thread:r.thread}}async function verifyInbound(e,t){try{return await verifyGitHubRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`github inbound verification failed`,{error:e}),null}}function readNonEmptyString(e){return typeof e==`string`&&e.length>0?e:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{githubChannel};
1
+ import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{getGitHubRepository}from"#public/channels/github/api.js";import{parseGitHubWebhookEvent}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromReceiveTarget}from"#public/channels/github/state.js";import{GITHUB_CHANNEL_DEFAULT_ROUTE}from"#public/channels/github/constants.js";import{createDefaultEvents,defaultOnComment}from"#public/channels/github/defaults.js";import{dispatchCheckRun,dispatchCheckSuite,dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment,dispatchWorkflowRun}from"#public/channels/github/dispatch.js";import{verifyGitHubRequest}from"#public/channels/github/verify.js";const log=createLogger(`github.channel`);function githubChannel(e={}){let s=e.botName??process.env.GITHUB_APP_SLUG,u={botName:s},d={...createDefaultEvents({api:e.api,credentials:e.credentials,progress:e.progress}),...e.events};return defineChannel({kindHint:`github`,state:initialGitHubState(),context(t,n){return rebuildGitHubContext(t,n,e)},routes:[POST(e.route??GITHUB_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let a=await verifyInbound(t,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseGitHubWebhookEvent({body:a,contentType:t.headers.get(`content-type`)??void 0,headers:t.headers})}catch(e){return log.warn(`inbound GitHub body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`ping`?jsonOk({ok:!0}):o.kind===`issue_comment`&&o.action===`created`?(r(dispatchIssueComment({botName:s,config:e,event:o,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):o.kind===`pull_request_review_comment`&&o.action===`created`?(r(dispatchPullRequestReviewComment({botName:s,config:e,event:o,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):o.kind===`issues`&&e.onIssue!==void 0?(r(dispatchIssue({config:e,event:o,handler:e.onIssue,send:n})),jsonOk({ok:!0})):o.kind===`pull_request`&&e.onPullRequest!==void 0?(r(dispatchPullRequest({config:e,event:o,handler:e.onPullRequest,send:n})),jsonOk({ok:!0})):o.kind===`check_suite`&&e.onCheckSuite!==void 0?(r(dispatchCheckSuite({config:e,event:o,handler:e.onCheckSuite,send:n})),jsonOk({ok:!0})):o.kind===`check_run`&&e.onCheckRun!==void 0?(r(dispatchCheckRun({config:e,event:o,handler:e.onCheckRun,send:n})),jsonOk({ok:!0})):o.kind===`workflow_run`&&e.onWorkflowRun!==void 0?(r(dispatchWorkflowRun({config:e,event:o,handler:e.onWorkflowRun,send:n})),jsonOk({ok:!0})):jsonOk({ignored:!0,ok:!0})})],async receive(t,{send:n}){let i=t.target,s=readNonEmptyString(i.owner),c=readNonEmptyString(i.repo);if(s===void 0||c===void 0)throw Error(`githubChannel().receive requires target.owner and target.repo.`);if([i.issueNumber!==void 0,i.pullRequestNumber!==void 0].filter(Boolean).length!==1)throw Error(`githubChannel().receive requires exactly one of issueNumber or pullRequestNumber.`);let l=stateFromReceiveTarget({target:i,owner:s,repo:c,repositoryId:i.repositoryId??(await getGitHubRepository({api:e.api,credentials:e.credentials,installationId:i.installationId,owner:s,repo:c})).id});if(i.initialMessage!==void 0){let{thread:t}=buildGitHubBinding({config:e,state:l});await t.post(i.initialMessage)}return n(t.message,{auth:t.auth,continuationToken:continuationTokenFromState(l),state:l})},events:d})}function rebuildGitHubContext(e,t,n){let r=buildGitHubBinding({config:n,state:e});return{conversation:conversationFromState(e),github:r.github,repository:r.github.repository,state:e,thread:r.thread}}async function verifyInbound(e,t){try{return await verifyGitHubRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`github inbound verification failed`,{error:e}),null}}function readNonEmptyString(e){return typeof e==`string`&&e.length>0?e:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{githubChannel};
@@ -86,6 +86,34 @@ export interface GitHubPullRequestEvent {
86
86
  readonly pullRequestNumber: number;
87
87
  readonly raw: JsonObject;
88
88
  }
89
+ /** GitHub App identity attached to CI webhook payloads. */
90
+ export interface GitHubAppRef {
91
+ readonly slug: string | null;
92
+ }
93
+ /** Common fields normalized from GitHub CI webhook payloads. */
94
+ export interface GitHubCiEvent {
95
+ readonly action: string;
96
+ readonly app: GitHubAppRef;
97
+ readonly conclusion: string | null;
98
+ readonly headSha: string | null;
99
+ readonly pullRequests: readonly number[];
100
+ readonly raw: JsonObject;
101
+ readonly status: string | null;
102
+ }
103
+ /** Normalized `check_suite` webhook payload. */
104
+ export interface GitHubCheckSuiteEvent extends GitHubCiEvent {
105
+ readonly checkSuiteId: number;
106
+ }
107
+ /** Normalized `check_run` webhook payload. */
108
+ export interface GitHubCheckRunEvent extends GitHubCiEvent {
109
+ readonly checkRunId: number;
110
+ }
111
+ /** Normalized `workflow_run` webhook payload. */
112
+ export interface GitHubWorkflowRunEvent extends GitHubCiEvent {
113
+ readonly workflowRunId: number;
114
+ }
115
+ /** Normalized payload accepted by one of the GitHub CI event hooks. */
116
+ export type GitHubCiPayload = GitHubCheckRunEvent | GitHubCheckSuiteEvent | GitHubWorkflowRunEvent;
89
117
  export interface GitHubPingEvent extends GitHubInboundEventBase {
90
118
  readonly kind: "ping";
91
119
  }
@@ -128,6 +156,23 @@ export interface GitHubPullRequestWebhookEvent extends GitHubInboundEventBase {
128
156
  readonly kind: "pull_request";
129
157
  readonly pullRequest: GitHubPullRequestEvent;
130
158
  }
159
+ export interface GitHubCheckSuiteWebhookEvent extends GitHubInboundEventBase {
160
+ readonly checkSuite: GitHubCheckSuiteEvent;
161
+ readonly conversation: GitHubConversationRef;
162
+ readonly kind: "check_suite";
163
+ }
164
+ export interface GitHubCheckRunWebhookEvent extends GitHubInboundEventBase {
165
+ readonly checkRun: GitHubCheckRunEvent;
166
+ readonly conversation: GitHubConversationRef;
167
+ readonly kind: "check_run";
168
+ }
169
+ export interface GitHubWorkflowRunWebhookEvent extends GitHubInboundEventBase {
170
+ readonly conversation: GitHubConversationRef;
171
+ readonly kind: "workflow_run";
172
+ readonly workflowRun: GitHubWorkflowRunEvent;
173
+ }
174
+ /** Parsed CI webhook envelopes consumed by the GitHub channel. */
175
+ export type GitHubCiWebhookEvent = GitHubCheckRunWebhookEvent | GitHubCheckSuiteWebhookEvent | GitHubWorkflowRunWebhookEvent;
131
176
  interface GitHubInboundEventBase {
132
177
  readonly delivery: GitHubDelivery;
133
178
  readonly installationId: number | undefined;
@@ -136,7 +181,7 @@ interface GitHubInboundEventBase {
136
181
  readonly sender: GitHubUser;
137
182
  }
138
183
  /** Parsed GitHub webhook event shape consumed by the channel. */
139
- export type GitHubInboundEvent = GitHubIssueCommentEvent | GitHubIssueWebhookEvent | GitHubPingEvent | GitHubPullRequestReviewCommentEvent | GitHubPullRequestWebhookEvent;
184
+ export type GitHubInboundEvent = GitHubCheckRunWebhookEvent | GitHubCheckSuiteWebhookEvent | GitHubIssueCommentEvent | GitHubIssueWebhookEvent | GitHubPingEvent | GitHubPullRequestReviewCommentEvent | GitHubPullRequestWebhookEvent | GitHubWorkflowRunWebhookEvent;
140
185
  /** Parsed mention trigger for a bot-directed GitHub comment. */
141
186
  export interface GitHubCommentTrigger {
142
187
  readonly kind: "mention";
@@ -1,2 +1,2 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";function githubContinuationToken(e){return e.conversationKind===`issue`?`repo:${e.repositoryId}:issue:${requiredNumber(e.issueNumber,`issueNumber`)}`:e.conversationKind===`pull_request`?`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}`:`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}:review-comment:${requiredNumber(e.reviewThreadRootCommentId,`reviewThreadRootCommentId`)}`}function shouldDispatchGitHubComment(e){return isIgnoredGitHubComment(e.body,e.author,e.botName)?!1:extractGitHubCommentTrigger(e)!==null}function extractGitHubCommentTrigger(e){let t=e.botName?.trim();if(!t)return null;let n=RegExp(`@${escapeRegExp(t)}(?=$|[^A-Za-z0-9_-])`,`iu`).exec(e.body);if(n===null)return null;let r=n.index,i=r+n[0].length;return{kind:`mention`,message:`${e.body.slice(0,r)}${e.body.slice(i)}`.trim(),token:n[0]}}function parseGitHubWebhookEvent(e){let t=e.headers.get(`x-github-event`)??``,n=e.headers.get(`x-github-delivery`)??``;if(!t||!n)return null;let r=decodePayload(e.body,e.contentType),i=normalizeRepository(r.repository),a=normalizeUser(r.sender);if(i===null||a===void 0)return null;let o={delivery:{event:t,hookId:e.headers.get(`x-github-hook-id`)??void 0,id:n},installationId:readInstallationId(r.installation),raw:r,repository:i,sender:a};return t===`ping`?{...o,kind:`ping`}:t===`issue_comment`?parseIssueCommentEvent(o):t===`pull_request_review_comment`?parsePullRequestReviewCommentEvent(o):t===`issues`?parseIssueEvent(o):t===`pull_request`?parsePullRequestEvent(o):null}function formatGitHubContextBlock(e){return[`<github_context>`,`repository: ${e.repository.fullName}`,`repository_id: ${e.repository.id}`,...e.issueNumber!==void 0&&e.issueNumber!==null?[`issue_number: ${e.issueNumber}`]:[],...e.pullRequestNumber!==void 0&&e.pullRequestNumber!==null?[`pull_request_number: ${e.pullRequestNumber}`]:[],`sender: ${e.sender.login}`,`sender_type: ${e.sender.type}`,...e.commentUrl?[`comment_url: ${e.commentUrl}`]:[],...e.headSha?[`head_sha: ${e.headSha}`]:[],`delivery_id: ${e.deliveryId}`,`</github_context>`].join(`
2
- `)}function prependGitHubContext(e,t){return typeof e==`string`?e.length>0?`${t}\n\n${e}`:t:[{text:t,type:`text`},...e]}function parseIssueCommentEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,a=typeof r?.number==`number`?r.number:void 0;if(i===null||r===null||a===void 0)return null;let o=isObject(r.pull_request)?a:null,s=readAction(n.raw),c={author:normalizeUser(i.user),body:typeof i.body==`string`?i.body:``,htmlUrl:typeof i.html_url==`string`?i.html_url:void 0,id:typeof i.id==`number`?i.id:0,issueNumber:a,pullRequestNumber:o,raw:i,url:typeof i.url==`string`?i.url:void 0};return{...n,action:s,baseRef:null,baseSha:null,comment:c,conversation:{issueNumber:a,kind:o===null?`issue`:`pull_request`,pullRequestNumber:o},defaultBranch:null,headRef:null,headSha:null,kind:`issue_comment`}}function parsePullRequestReviewCommentEvent(n){let r=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,i=isObject(n.raw.pull_request)?n.raw.pull_request:null,a=typeof i?.number==`number`?i.number:void 0;if(r===null||a===void 0)return null;let o=typeof r.id==`number`?r.id:0,s=typeof r.in_reply_to_id==`number`?r.in_reply_to_id:null,c={author:normalizeUser(r.user),body:typeof r.body==`string`?r.body:``,htmlUrl:typeof r.html_url==`string`?r.html_url:void 0,id:o,inReplyToId:s,pullRequestNumber:a,raw:r,reviewThreadRootCommentId:s??o,url:typeof r.url==`string`?r.url:void 0};return{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(i),baseSha:readPullRequestBaseSha(i),comment:c,conversation:{issueNumber:null,kind:`review_thread`,pullRequestNumber:a},defaultBranch:readPullRequestDefaultBranch(i),headRef:readPullRequestHeadRef(i),headSha:readPullRequestHeadSha(i),kind:`pull_request_review_comment`}}function parseIssueEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),conversation:{issueNumber:i,kind:`issue`,pullRequestNumber:null},issue:{action:readAction(n.raw),issueNumber:i,raw:parseJsonObject(r)},kind:`issues`}}function parsePullRequestEvent(n){let r=isObject(n.raw.pull_request)?n.raw.pull_request:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(r),baseSha:readPullRequestBaseSha(r),conversation:{issueNumber:null,kind:`pull_request`,pullRequestNumber:i},defaultBranch:readPullRequestDefaultBranch(r),headRef:readPullRequestHeadRef(r),headSha:readPullRequestHeadSha(r),kind:`pull_request`,pullRequest:{action:readAction(n.raw),headSha:readPullRequestHeadSha(r),pullRequestNumber:i,raw:parseJsonObject(r)}}}function decodePayload(e,n){if(n?.includes(`application/x-www-form-urlencoded`)===!0){let n=new URLSearchParams(e).get(`payload`)??``;return parseJsonObject(JSON.parse(n))}return parseJsonObject(JSON.parse(e))}function normalizeRepository(t){if(!isObject(t))return null;let n=typeof t.full_name==`string`?t.full_name:``,[r=``,i=``]=n.split(`/`),a=isObject(t.owner)?t.owner:{},o=typeof a.login==`string`?a.login:r,s=typeof t.name==`string`?t.name:i,c=typeof t.id==`number`?t.id:0;return!o||!s?null:{fullName:n||`${o}/${s}`,id:c,name:s,owner:o,private:t.private===!0}}function normalizeUser(t){if(!isObject(t))return;let n=typeof t.login==`string`?t.login:``;if(n)return{htmlUrl:typeof t.html_url==`string`?t.html_url:void 0,id:typeof t.id==`number`?t.id:0,login:n,type:typeof t.type==`string`?t.type:`User`,url:typeof t.url==`string`?t.url:void 0}}function readInstallationId(t){if(isObject(t))return typeof t.id==`number`?t.id:void 0}function readAction(e){return typeof e.action==`string`?e.action:``}function readPullRequestHeadSha(t){let n=isObject(t?.head)?t.head:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestHeadRef(t){let n=isObject(t?.head)?t.head:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseRef(t){let n=isObject(t?.base)?t.base:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseSha(t){let n=isObject(t?.base)?t.base:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestDefaultBranch(t){let n=isObject(t?.base)?t.base:null,r=isObject(n?.repo)?n.repo:null;return typeof r?.default_branch==`string`?r.default_branch:null}function isIgnoredGitHubComment(e,t,n){if(e.includes(`<!-- eve:github:`))return!0;if(t===void 0)return!1;if(t.type===`Bot`)return!0;let r=n?`${n}[bot]`.toLowerCase():``;return r.length>0&&t.login.toLowerCase()===r}function requiredNumber(e,t){if(typeof e==`number`&&Number.isFinite(e))return e;throw Error(`githubContinuationToken requires ${t}.`)}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{extractGitHubCommentTrigger,formatGitHubContextBlock,githubContinuationToken,parseGitHubWebhookEvent,prependGitHubContext,shouldDispatchGitHubComment};
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";function githubContinuationToken(e){return e.conversationKind===`issue`?`repo:${e.repositoryId}:issue:${requiredNumber(e.issueNumber,`issueNumber`)}`:e.conversationKind===`pull_request`?`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}`:`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}:review-comment:${requiredNumber(e.reviewThreadRootCommentId,`reviewThreadRootCommentId`)}`}function shouldDispatchGitHubComment(e){return isIgnoredGitHubComment(e.body,e.author,e.botName)?!1:extractGitHubCommentTrigger(e)!==null}function extractGitHubCommentTrigger(e){let t=e.botName?.trim();if(!t)return null;let n=RegExp(`@${escapeRegExp(t)}(?=$|[^A-Za-z0-9_-])`,`iu`).exec(e.body);if(n===null)return null;let r=n.index,i=r+n[0].length;return{kind:`mention`,message:`${e.body.slice(0,r)}${e.body.slice(i)}`.trim(),token:n[0]}}function parseGitHubWebhookEvent(e){let t=e.headers.get(`x-github-event`)??``,n=e.headers.get(`x-github-delivery`)??``;if(!t||!n)return null;let r=decodePayload(e.body,e.contentType),i=normalizeRepository(r.repository),a=normalizeUser(r.sender);if(i===null||a===void 0)return null;let o={delivery:{event:t,hookId:e.headers.get(`x-github-hook-id`)??void 0,id:n},installationId:readInstallationId(r.installation),raw:r,repository:i,sender:a};return t===`ping`?{...o,kind:`ping`}:t===`issue_comment`?parseIssueCommentEvent(o):t===`pull_request_review_comment`?parsePullRequestReviewCommentEvent(o):t===`issues`?parseIssueEvent(o):t===`pull_request`?parsePullRequestEvent(o):t===`check_suite`?parseCheckSuiteEvent(o):t===`check_run`?parseCheckRunEvent(o):t===`workflow_run`?parseWorkflowRunEvent(o):null}function formatGitHubContextBlock(e){return[`<github_context>`,`repository: ${e.repository.fullName}`,`repository_id: ${e.repository.id}`,...e.issueNumber!==void 0&&e.issueNumber!==null?[`issue_number: ${e.issueNumber}`]:[],...e.pullRequestNumber!==void 0&&e.pullRequestNumber!==null?[`pull_request_number: ${e.pullRequestNumber}`]:[],`sender: ${e.sender.login}`,`sender_type: ${e.sender.type}`,...e.commentUrl?[`comment_url: ${e.commentUrl}`]:[],...e.headSha?[`head_sha: ${e.headSha}`]:[],`delivery_id: ${e.deliveryId}`,`</github_context>`].join(`
2
+ `)}function prependGitHubContext(e,t){return typeof e==`string`?e.length>0?`${t}\n\n${e}`:t:[{text:t,type:`text`},...e]}function parseIssueCommentEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,a=typeof r?.number==`number`?r.number:void 0;if(i===null||r===null||a===void 0)return null;let o=isObject(r.pull_request)?a:null,s=readAction(n.raw),c={author:normalizeUser(i.user),body:typeof i.body==`string`?i.body:``,htmlUrl:typeof i.html_url==`string`?i.html_url:void 0,id:typeof i.id==`number`?i.id:0,issueNumber:a,pullRequestNumber:o,raw:i,url:typeof i.url==`string`?i.url:void 0};return{...n,action:s,baseRef:null,baseSha:null,comment:c,conversation:{issueNumber:a,kind:o===null?`issue`:`pull_request`,pullRequestNumber:o},defaultBranch:null,headRef:null,headSha:null,kind:`issue_comment`}}function parsePullRequestReviewCommentEvent(n){let r=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,i=isObject(n.raw.pull_request)?n.raw.pull_request:null,a=typeof i?.number==`number`?i.number:void 0;if(r===null||a===void 0)return null;let o=typeof r.id==`number`?r.id:0,s=typeof r.in_reply_to_id==`number`?r.in_reply_to_id:null,c={author:normalizeUser(r.user),body:typeof r.body==`string`?r.body:``,htmlUrl:typeof r.html_url==`string`?r.html_url:void 0,id:o,inReplyToId:s,pullRequestNumber:a,raw:r,reviewThreadRootCommentId:s??o,url:typeof r.url==`string`?r.url:void 0};return{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(i),baseSha:readPullRequestBaseSha(i),comment:c,conversation:{issueNumber:null,kind:`review_thread`,pullRequestNumber:a},defaultBranch:readPullRequestDefaultBranch(i),headRef:readPullRequestHeadRef(i),headSha:readPullRequestHeadSha(i),kind:`pull_request_review_comment`}}function parseIssueEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),conversation:{issueNumber:i,kind:`issue`,pullRequestNumber:null},issue:{action:readAction(n.raw),issueNumber:i,raw:parseJsonObject(r)},kind:`issues`}}function parsePullRequestEvent(n){let r=isObject(n.raw.pull_request)?n.raw.pull_request:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(r),baseSha:readPullRequestBaseSha(r),conversation:{issueNumber:null,kind:`pull_request`,pullRequestNumber:i},defaultBranch:readPullRequestDefaultBranch(r),headRef:readPullRequestHeadRef(r),headSha:readPullRequestHeadSha(r),kind:`pull_request`,pullRequest:{action:readAction(n.raw),headSha:readPullRequestHeadSha(r),pullRequestNumber:i,raw:parseJsonObject(r)}}}function parseCheckSuiteEvent(e){let t=readEventObject(e.raw.check_suite);if(t===null)return null;let n=readId(t);if(n===null)return null;let r=normalizeCiEvent(e.raw,t,normalizeApp(t.app));return{...e,checkSuite:{...r,checkSuiteId:n},conversation:ciConversation(r.pullRequests),kind:`check_suite`}}function parseCheckRunEvent(e){let t=readEventObject(e.raw.check_run);if(t===null)return null;let n=readId(t);if(n===null)return null;let r=normalizeCiEvent(e.raw,t,normalizeApp(t.app));return{...e,checkRun:{...r,checkRunId:n},conversation:ciConversation(r.pullRequests),kind:`check_run`}}function parseWorkflowRunEvent(e){let t=readEventObject(e.raw.workflow_run);if(t===null)return null;let n=readId(t);if(n===null)return null;let r=normalizeCiEvent(e.raw,t,{slug:`github-actions`});return{...e,conversation:ciConversation(r.pullRequests),kind:`workflow_run`,workflowRun:{...r,workflowRunId:n}}}function normalizeCiEvent(e,t,n){return{action:readAction(e),app:n,conclusion:readNullableString(t.conclusion),headSha:readNullableString(t.head_sha),pullRequests:readPullRequestNumbers(t.pull_requests),raw:t,status:readNullableString(t.status)}}function readEventObject(n){return isObject(n)?parseJsonObject(n):null}function readId(e){return typeof e.id==`number`?e.id:null}function normalizeApp(t){return{slug:isObject(t)&&typeof t.slug==`string`?t.slug:null}}function readNullableString(e){return typeof e==`string`?e:null}function readPullRequestNumbers(t){return Array.isArray(t)?t.flatMap(t=>isObject(t)&&typeof t.number==`number`?[t.number]:[]):[]}function ciConversation(e){return{issueNumber:null,kind:`pull_request`,pullRequestNumber:e[0]??null}}function decodePayload(e,n){if(n?.includes(`application/x-www-form-urlencoded`)===!0){let n=new URLSearchParams(e).get(`payload`)??``;return parseJsonObject(JSON.parse(n))}return parseJsonObject(JSON.parse(e))}function normalizeRepository(t){if(!isObject(t))return null;let n=typeof t.full_name==`string`?t.full_name:``,[r=``,i=``]=n.split(`/`),a=isObject(t.owner)?t.owner:{},o=typeof a.login==`string`?a.login:r,s=typeof t.name==`string`?t.name:i,c=typeof t.id==`number`?t.id:0;return!o||!s?null:{fullName:n||`${o}/${s}`,id:c,name:s,owner:o,private:t.private===!0}}function normalizeUser(t){if(!isObject(t))return;let n=typeof t.login==`string`?t.login:``;if(n)return{htmlUrl:typeof t.html_url==`string`?t.html_url:void 0,id:typeof t.id==`number`?t.id:0,login:n,type:typeof t.type==`string`?t.type:`User`,url:typeof t.url==`string`?t.url:void 0}}function readInstallationId(t){if(isObject(t))return typeof t.id==`number`?t.id:void 0}function readAction(e){return typeof e.action==`string`?e.action:``}function readPullRequestHeadSha(t){let n=isObject(t?.head)?t.head:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestHeadRef(t){let n=isObject(t?.head)?t.head:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseRef(t){let n=isObject(t?.base)?t.base:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseSha(t){let n=isObject(t?.base)?t.base:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestDefaultBranch(t){let n=isObject(t?.base)?t.base:null,r=isObject(n?.repo)?n.repo:null;return typeof r?.default_branch==`string`?r.default_branch:null}function isIgnoredGitHubComment(e,t,n){if(e.includes(`<!-- eve:github:`))return!0;if(t===void 0)return!1;if(t.type===`Bot`)return!0;let r=n?`${n}[bot]`.toLowerCase():``;return r.length>0&&t.login.toLowerCase()===r}function requiredNumber(e,t){if(typeof e==`number`&&Number.isFinite(e))return e;throw Error(`githubContinuationToken requires ${t}.`)}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{extractGitHubCommentTrigger,formatGitHubContextBlock,githubContinuationToken,parseGitHubWebhookEvent,prependGitHubContext,shouldDispatchGitHubComment};
@@ -2,7 +2,7 @@ export { GitHubApiError, type GitHubApiMethod, type GitHubApiOptions, type GitHu
2
2
  export { type GitHubHandle, type GitHubThread } from "#public/channels/github/binding.js";
3
3
  export { type GitHubAppId, type GitHubChannelCredentials, type GitHubInstallationToken, type GitHubPrivateKey, type GitHubWebhookSecret, } from "#public/channels/github/auth.js";
4
4
  export { defaultGitHubAuth } from "#public/channels/github/defaults.js";
5
- export { type GitHubComment, type GitHubConversationKind, type GitHubConversationRef, type GitHubDelivery, type GitHubIssueAction, type GitHubIssueEvent, type GitHubPullRequestAction, type GitHubPullRequestEvent, type GitHubRepositoryRef, type GitHubUser, } from "#public/channels/github/inbound.js";
5
+ export { type GitHubAppRef, type GitHubCheckRunEvent, type GitHubCheckSuiteEvent, type GitHubCiEvent, type GitHubCiPayload, type GitHubComment, type GitHubConversationKind, type GitHubConversationRef, type GitHubDelivery, type GitHubIssueAction, type GitHubIssueEvent, type GitHubPullRequestAction, type GitHubPullRequestEvent, type GitHubRepositoryRef, type GitHubUser, type GitHubWorkflowRunEvent, } from "#public/channels/github/inbound.js";
6
6
  export { githubChannel, type GitHubChannel, type GitHubChannelConfig, type GitHubChannelEvents, type GitHubEventContext, type GitHubInboundContext, type GitHubInboundResult, type GitHubInboundResultOrPromise, type GitHubProgressConfig, type GitHubReceiveTarget, } from "#public/channels/github/githubChannel.js";
7
7
  export { GITHUB_DEFAULT_EXCLUDED_DIFF_FILES, type GitHubPullRequestContextConfig, } from "#public/channels/github/pr-context.js";
8
8
  export { type GitHubChannelState } from "#public/channels/github/state.js";
@@ -1,4 +1,4 @@
1
- import { type GitHubConversationKind, type GitHubConversationRef, type GitHubIssueCommentEvent, type GitHubIssueWebhookEvent, type GitHubPullRequestReviewCommentEvent, type GitHubPullRequestWebhookEvent } from "#public/channels/github/inbound.js";
1
+ import { type GitHubCiWebhookEvent, type GitHubConversationKind, type GitHubConversationRef, type GitHubIssueCommentEvent, type GitHubIssueWebhookEvent, type GitHubPullRequestReviewCommentEvent, type GitHubPullRequestWebhookEvent } from "#public/channels/github/inbound.js";
2
2
  /**
3
3
  * Durable, mutable per-conversation GitHub channel state, persisted as JSON.
4
4
  *
@@ -47,6 +47,8 @@ export declare function stateFromPullRequestReviewCommentEvent(event: GitHubPull
47
47
  export declare function stateFromIssueEvent(event: GitHubIssueWebhookEvent): GitHubChannelState;
48
48
  /** Builds state for a pull-request event hook dispatch. */
49
49
  export declare function stateFromPullRequestEvent(event: GitHubPullRequestWebhookEvent): GitHubChannelState;
50
+ /** Builds pull-request state for a CI event hook dispatch. */
51
+ export declare function stateFromCiEvent(event: GitHubCiWebhookEvent): GitHubChannelState;
50
52
  /** Builds state for proactive `receive()` calls. */
51
53
  export declare function stateFromReceiveTarget(input: {
52
54
  readonly target: GitHubReceiveStateTarget;
@@ -1 +1 @@
1
- import{githubContinuationToken}from"#public/channels/github/inbound.js";function initialGitHubState(){return{baseRef:null,baseSha:null,checkoutPath:null,conversationKind:`issue`,defaultBranch:null,headRef:null,headSha:null,installationId:null,issueNumber:null,owner:``,pullRequestNumber:null,repo:``,repositoryId:0,reviewCommentId:null,reviewThreadRootCommentId:null,triggeringCommentId:null,triggeringUserLogin:null}}function stateFromIssueCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:e.conversation.kind,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.comment.issueNumber,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestReviewCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`review_thread`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,reviewCommentId:e.comment.id,reviewThreadRootCommentId:e.comment.reviewThreadRootCommentId,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromIssueEvent(e){return{...initialGitHubState(),conversationKind:`issue`,installationId:e.installationId??null,issueNumber:e.issue.issueNumber,owner:e.repository.owner,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`pull_request`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.pullRequest.pullRequestNumber,owner:e.repository.owner,pullRequestNumber:e.pullRequest.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromReceiveTarget(e){let{target:t}=e,n=t.pullRequestNumber===void 0?`issue`:`pull_request`;return{...initialGitHubState(),conversationKind:n,installationId:t.installationId??null,issueNumber:n===`issue`?t.issueNumber??null:t.pullRequestNumber??null,owner:e.owner,pullRequestNumber:t.pullRequestNumber??null,repo:e.repo,repositoryId:e.repositoryId}}function conversationFromState(e){return{issueNumber:e.issueNumber,kind:e.conversationKind,pullRequestNumber:e.pullRequestNumber}}function continuationTokenFromState(t){return githubContinuationToken({conversationKind:t.conversationKind,issueNumber:t.issueNumber,pullRequestNumber:t.pullRequestNumber,repositoryId:t.repositoryId,reviewThreadRootCommentId:t.reviewThreadRootCommentId})}export{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromIssueCommentEvent,stateFromIssueEvent,stateFromPullRequestEvent,stateFromPullRequestReviewCommentEvent,stateFromReceiveTarget};
1
+ import{githubContinuationToken}from"#public/channels/github/inbound.js";function initialGitHubState(){return{baseRef:null,baseSha:null,checkoutPath:null,conversationKind:`issue`,defaultBranch:null,headRef:null,headSha:null,installationId:null,issueNumber:null,owner:``,pullRequestNumber:null,repo:``,repositoryId:0,reviewCommentId:null,reviewThreadRootCommentId:null,triggeringCommentId:null,triggeringUserLogin:null}}function stateFromIssueCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:e.conversation.kind,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.comment.issueNumber,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestReviewCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`review_thread`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,reviewCommentId:e.comment.id,reviewThreadRootCommentId:e.comment.reviewThreadRootCommentId,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromIssueEvent(e){return{...initialGitHubState(),conversationKind:`issue`,installationId:e.installationId??null,issueNumber:e.issue.issueNumber,owner:e.repository.owner,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`pull_request`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.pullRequest.pullRequestNumber,owner:e.repository.owner,pullRequestNumber:e.pullRequest.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromCiEvent(e){let t=ciPayload(e),n=t.pullRequests[0]??null;return{...initialGitHubState(),conversationKind:`pull_request`,headSha:t.headSha,installationId:e.installationId??null,issueNumber:n,owner:e.repository.owner,pullRequestNumber:n,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromReceiveTarget(e){let{target:t}=e,n=t.pullRequestNumber===void 0?`issue`:`pull_request`;return{...initialGitHubState(),conversationKind:n,installationId:t.installationId??null,issueNumber:n===`issue`?t.issueNumber??null:t.pullRequestNumber??null,owner:e.owner,pullRequestNumber:t.pullRequestNumber??null,repo:e.repo,repositoryId:e.repositoryId}}function conversationFromState(e){return{issueNumber:e.issueNumber,kind:e.conversationKind,pullRequestNumber:e.pullRequestNumber}}function continuationTokenFromState(t){return githubContinuationToken({conversationKind:t.conversationKind,issueNumber:t.issueNumber,pullRequestNumber:t.pullRequestNumber,repositoryId:t.repositoryId,reviewThreadRootCommentId:t.reviewThreadRootCommentId})}function ciPayload(e){return e.kind===`check_suite`?e.checkSuite:e.kind===`check_run`?e.checkRun:e.workflowRun}export{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromCiEvent,stateFromIssueCommentEvent,stateFromIssueEvent,stateFromPullRequestEvent,stateFromPullRequestReviewCommentEvent,stateFromReceiveTarget};
@@ -1 +1 @@
1
- import{markEventHandled}from"./utils.js";import{createLogger,logError}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{formatSlackContextBlock,parseAppMentionEvent,parseDirectMessageEvent}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=createSlackFetchFile({botToken:e.credentials?.botToken}),l=e.onAppMention??defaultOnAppMention,u=e.onDirectMessage??defaultOnDirectMessage,d=e.events?.[`authorization.required`],f={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler(),"authorization.required":d===void 0?defaultEvents[`authorization.required`]:constrainAuthorizationRequired(d)},p=new Set;return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,lastReasoningTypingAtMs:null,lastReasoningTypingStatus:null,pendingAuthMessageTs:{}},fetchFile:n,metadata(e){return{channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);return a===null?new Response(`unauthorized`,{status:401}):shouldDropSlackHttpTimeoutRetry(n.headers)?new Response(`ok`):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(a,{send:r,waitUntil:i},{config:e}):handleEventPost({body:a,send:r,waitUntil:i,onAppMention:l,onDirectMessage:u,uploadPolicy:t,handledEvents:p,headers:n.headers,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.target,i=r.channelId;if(!i||typeof i!=`string`)throw Error(`slackChannel().receive requires target.channelId.`);let a=typeof r.threadTs==`string`?r.threadTs:``,s=r.initialMessage;if(s&&a.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=a;if(s){let{thread:t}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:i,threadTs:``,teamId:void 0}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await t.post(n)).id}return n(t.message,{auth:t.auth,continuationToken:slackContinuationToken(i,c),state:{channelId:i,threadTs:c||null,teamId:null,triggeringUserId:null}})},events:f})}function constrainAuthorizationRequired(e){return(t,n,r)=>e(t,{postEphemeral:(e,t)=>n.thread.postEphemeral(e,t),postDirectMessage:(e,t)=>n.thread.postDirectMessage(e,t),state:n.state},r)}function shouldDropSlackHttpTimeoutRetry(e){return Number(e.get(`x-slack-retry-num`)??`0`)>=1&&e.get(`x-slack-retry-reason`)===`http_timeout`}async function handleEventPost(t){let n;try{n=JSON.parse(t.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(typeof n.challenge==`string`)return new Response(n.challenge,{status:200,headers:{"content-type":`text/plain`}});if(n.event_id){if(t.handledEvents.has(n.event_id))return log.warn(`received a duplicate event`,{event_id:n.event_id,event_time:n.event_time,retry_num:t.headers.get(`x-slack-retry-num`)||`(null)`,retry_reason:t.headers.get(`x-slack-retry-reason`)||`(null)`}),new Response(`ok`);markEventHandled(n.event_id,t.handledEvents)}let r=parseAppMentionEvent(n);if(r)return t.waitUntil(dispatchInboundMessage({kind:`app_mention`,message:r,handler:t.onAppMention,send:t.send,uploadPolicy:t.uploadPolicy,credentials:t.credentials})),new Response(`ok`);let i=parseDirectMessageEvent(n);return i&&t.waitUntil(dispatchInboundMessage({kind:`direct_message`,message:i,handler:t.onDirectMessage,send:t.send,uploadPolicy:t.uploadPolicy,credentials:t.credentials})),new Response(`ok`)}async function verifyInbound(e,t){try{return await verifySlackRequest(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function dispatchInboundMessage(e){let{message:t,kind:r}=e,{thread:i,slack:a}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId}),s={thread:i,slack:a},c;try{c=await e.handler(s,t)}catch(e){logError(log,`${r} handler failed`,e,{channelId:t.channelId});return}if(c!=null)try{let n=await collectInboundFileParts({mention:t,thread:i,policy:e.uploadPolicy}),r=buildSlackTurnMessage(t.markdown,n),a={channelId:t.channelId,fullName:t.author?.fullName,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},o=c.context??[];await e.send({message:r,context:[formatSlackContextBlock(a),...o]},{auth:c.auth,continuationToken:slackContinuationToken(t.channelId,t.threadTs),state:{channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId??null,triggeringUserId:a.userId||null}})}catch(e){logError(log,`${r} delivery failed`,e,{channelId:t.channelId})}}export{constrainAuthorizationRequired,slackChannel};
1
+ import{markEventHandled}from"./utils.js";import{createLogger,logError}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{formatSlackContextBlock,parseAppMentionEvent,parseDirectMessageEvent}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=createSlackFetchFile({botToken:e.credentials?.botToken}),u=e.onAppMention??defaultOnAppMention,d=e.onDirectMessage??defaultOnDirectMessage,f=e.events?.[`authorization.required`],p={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler(),"authorization.required":f===void 0?defaultEvents[`authorization.required`]:constrainAuthorizationRequired(f)},m=new Set;return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,lastReasoningTypingAtMs:null,lastReasoningTypingStatus:null,pendingAuthMessageTs:{}},fetchFile:n,metadata(e){return{channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);return a===null?new Response(`unauthorized`,{status:401}):shouldDropSlackHttpTimeoutRetry(n.headers)?new Response(`ok`):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(a,{send:r,waitUntil:i},{config:e}):handleEventPost({body:a,send:r,waitUntil:i,onAppMention:u,onDirectMessage:d,uploadPolicy:t,handledEvents:m,headers:n.headers,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.target,i=r.channelId;if(!i||typeof i!=`string`)throw Error(`slackChannel().receive requires target.channelId.`);let a=typeof r.threadTs==`string`?r.threadTs:``,s=r.initialMessage;if(s&&a.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=a;if(s){let{thread:t}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:i,threadTs:``,teamId:void 0}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await t.post(n)).id}let l=c||crypto.randomUUID();return n(t.message,{auth:t.auth,continuationToken:slackContinuationToken(i,l),state:{channelId:i,threadTs:c||null,teamId:null,triggeringUserId:null}})},events:p})}function constrainAuthorizationRequired(e){return(t,n,r)=>e(t,{postEphemeral:(e,t)=>n.thread.postEphemeral(e,t),postDirectMessage:(e,t)=>n.thread.postDirectMessage(e,t),state:n.state},r)}function shouldDropSlackHttpTimeoutRetry(e){return Number(e.get(`x-slack-retry-num`)??`0`)>=1&&e.get(`x-slack-retry-reason`)===`http_timeout`}async function handleEventPost(t){let n;try{n=JSON.parse(t.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(typeof n.challenge==`string`)return new Response(n.challenge,{status:200,headers:{"content-type":`text/plain`}});if(n.event_id){if(t.handledEvents.has(n.event_id))return log.warn(`received a duplicate event`,{event_id:n.event_id,event_time:n.event_time,retry_num:t.headers.get(`x-slack-retry-num`)||`(null)`,retry_reason:t.headers.get(`x-slack-retry-reason`)||`(null)`}),new Response(`ok`);markEventHandled(n.event_id,t.handledEvents)}let r=parseAppMentionEvent(n);if(r)return t.waitUntil(dispatchInboundMessage({kind:`app_mention`,message:r,handler:t.onAppMention,send:t.send,uploadPolicy:t.uploadPolicy,credentials:t.credentials})),new Response(`ok`);let i=parseDirectMessageEvent(n);return i&&t.waitUntil(dispatchInboundMessage({kind:`direct_message`,message:i,handler:t.onDirectMessage,send:t.send,uploadPolicy:t.uploadPolicy,credentials:t.credentials})),new Response(`ok`)}async function verifyInbound(e,t){try{return await verifySlackRequest(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function dispatchInboundMessage(e){let{message:t,kind:r}=e,{thread:i,slack:a}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId}),s={thread:i,slack:a},c;try{c=await e.handler(s,t)}catch(e){logError(log,`${r} handler failed`,e,{channelId:t.channelId});return}if(c!=null)try{let n=await collectInboundFileParts({mention:t,thread:i,policy:e.uploadPolicy}),r=buildSlackTurnMessage(t.markdown,n),a={channelId:t.channelId,fullName:t.author?.fullName,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},o=c.context??[];await e.send({message:r,context:[formatSlackContextBlock(a),...o]},{auth:c.auth,continuationToken:slackContinuationToken(t.channelId,t.threadTs),state:{channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId??null,triggeringUserId:a.userId||null}})}catch(e){logError(log,`${r} delivery failed`,e,{channelId:t.channelId})}}export{constrainAuthorizationRequired,slackChannel};
@@ -1 +1 @@
1
- import{EVE_CONNECTION_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#compiled/@workflow/core/runtime.js";import{applyEveWorkflowQueueNamespace}from"#internal/workflow/queue-namespace.js";import{buildAuthorizationCompletePage}from"#runtime/connections/authorization-complete-page.js";const HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/connections/callback`,HANDLED_METHODS=[`GET`,`POST`];function getConnectionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getConnectionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CONNECTION_CALLBACK_ROUTE_PATTERN,fetch:handleConnectionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:connection-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleConnectionCallbackRequest(e,i){let a=i.params.name,o=i.params.token;if(typeof a!=`string`||a.length===0)return Response.json({error:`Missing connection name.`,ok:!1},{status:400});if(typeof o!=`string`||o.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let s=await projectAuthorizationCallback(e);try{applyEveWorkflowQueueNamespace(),await resumeHook(o,{kind:`deliver`,payloads:[{authorizationCallback:{connectionName:a,callback:s}}]})}catch{return Response.json({error:`Connection callback not pending.`,ok:!1},{status:404})}return buildAuthorizationCompletePage()}async function projectAuthorizationCallback(e){let t={};for(let[n,r]of new URL(e.url).searchParams)t[n]=r;let n;if(e.method!==`GET`&&e.method!==`HEAD`){try{n=await e.text()}catch{n=void 0}let r=e.headers.get(`content-type`)??``;if(n&&r.includes(`application/x-www-form-urlencoded`))for(let[e,r]of new URLSearchParams(n))t[e]=r}return n===void 0?{params:t,method:e.method}:{params:t,method:e.method,body:n}}export{HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX,getConnectionCallbackChannelDefinitions,getConnectionCallbackChannelNames,handleConnectionCallbackRequest};
1
+ import{EVE_CONNECTION_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#internal/workflow/runtime.js";import{buildAuthorizationCompletePage}from"#runtime/connections/authorization-complete-page.js";const HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/connections/callback`,HANDLED_METHODS=[`GET`,`POST`];function getConnectionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getConnectionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CONNECTION_CALLBACK_ROUTE_PATTERN,fetch:handleConnectionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:connection-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleConnectionCallbackRequest(e,r){let i=r.params.name,a=r.params.token;if(typeof i!=`string`||i.length===0)return Response.json({error:`Missing connection name.`,ok:!1},{status:400});if(typeof a!=`string`||a.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let o=await projectAuthorizationCallback(e);try{await resumeHook(a,{kind:`deliver`,payloads:[{authorizationCallback:{connectionName:i,callback:o}}]})}catch{return Response.json({error:`Connection callback not pending.`,ok:!1},{status:404})}return buildAuthorizationCompletePage()}async function projectAuthorizationCallback(e){let t={};for(let[n,r]of new URL(e.url).searchParams)t[n]=r;let n;if(e.method!==`GET`&&e.method!==`HEAD`){try{n=await e.text()}catch{n=void 0}let r=e.headers.get(`content-type`)??``;if(n&&r.includes(`application/x-www-form-urlencoded`))for(let[e,r]of new URLSearchParams(n))t[e]=r}return n===void 0?{params:t,method:e.method}:{params:t,method:e.method,body:n}}export{HTTP_CONNECTION_CALLBACK_CHANNEL_NAME_PREFIX,getConnectionCallbackChannelDefinitions,getConnectionCallbackChannelNames,handleConnectionCallbackRequest};
@@ -1 +1 @@
1
- import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#compiled/@workflow/core/runtime.js";import{applyEveWorkflowQueueNamespace}from"#internal/workflow/queue-namespace.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`];function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:session-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,r){let i=r.params.token;if(typeof i!=`string`||i.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let a;try{a=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let o=projectSessionCallbackResult(a);if(o instanceof Response)return o;try{applyEveWorkflowQueueNamespace(),await resumeHook(i,{kind:`runtime-action-result`,results:[o]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=e;return typeof t.callId!=`string`||t.callId.length===0?Response.json({error:`Missing callback callId.`,ok:!1},{status:400}):typeof t.subagentName!=`string`||t.subagentName.length===0?Response.json({error:`Missing callback subagentName.`,ok:!1},{status:400}):t.kind===`session.completed`?{callId:t.callId,kind:`subagent-result`,output:t.output??``,subagentName:t.subagentName}:t.kind===`session.failed`?{callId:t.callId,isError:!0,kind:`subagent-result`,output:t.error===void 0?{code:`REMOTE_AGENT_FAILED`,message:`Remote agent failed.`}:t.error,subagentName:t.subagentName}:Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400})}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
1
+ import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#internal/workflow/runtime.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`];function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:session-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,n){let r=n.params.token;if(typeof r!=`string`||r.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let i;try{i=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let a=projectSessionCallbackResult(i);if(a instanceof Response)return a;try{await resumeHook(r,{kind:`runtime-action-result`,results:[a]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=e;return typeof t.callId!=`string`||t.callId.length===0?Response.json({error:`Missing callback callId.`,ok:!1},{status:400}):typeof t.subagentName!=`string`||t.subagentName.length===0?Response.json({error:`Missing callback subagentName.`,ok:!1},{status:400}):t.kind===`session.completed`?{callId:t.callId,kind:`subagent-result`,output:t.output??``,subagentName:t.subagentName}:t.kind===`session.failed`?{callId:t.callId,isError:!0,kind:`subagent-result`,output:t.error===void 0?{code:`REMOTE_AGENT_FAILED`,message:`Remote agent failed.`}:t.error,subagentName:t.subagentName}:Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400})}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
@@ -7,6 +7,8 @@ declare const VercelOidcClaimsSchema: z.ZodObject<{
7
7
  export interface DevelopmentOidcTarget {
8
8
  readonly ownerId: string;
9
9
  readonly projectId: string;
10
+ /** Ignore an ambient token and ask Vercel for this exact project. */
11
+ readonly forceRefresh?: boolean;
10
12
  }
11
13
  type VercelOidcClaimName = keyof z.infer<typeof VercelOidcClaimsSchema>;
12
14
  type InvalidVercelOidcClaim = VercelOidcClaimName | "claims";
@@ -1 +1 @@
1
- import{object,string}from"../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{toErrorMessage}from"#shared/errors.js";import{getVercelOidcToken}from"#compiled/@vercel/oidc/index.js";const VercelOidcClaimsSchema=object({owner_id:string().min(1),project_id:string().min(1)});async function resolveDevelopmentOidcToken(e){try{return validateDevelopmentOidcToken((await getVercelOidcToken({team:e.ownerId,project:e.projectId})).trim(),e)}catch(e){return{kind:`resolution-failed`,message:toErrorMessage(e)}}}function validateDevelopmentOidcToken(e,t){let n=e.split(`.`)[1];if(!n)return{kind:`malformed-token`,reason:`missing-payload`};let r;try{r=JSON.parse(Buffer.from(n,`base64url`).toString(`utf8`))}catch{return{kind:`malformed-token`,reason:`invalid-json-payload`}}let i=VercelOidcClaimsSchema.safeParse(r);if(!i.success)return{kind:`invalid-claims`,invalidClaims:i.error.issues.map(e=>{let t=e.path[0];return t===`owner_id`||t===`project_id`?t:`claims`})};let a=[];return i.data.owner_id!==t.ownerId&&a.push(`owner_id`),i.data.project_id!==t.projectId&&a.push(`project_id`),a.length>0?{kind:`target-mismatch`,mismatchedClaims:a}:{kind:`resolved`,token:e}}const VERCEL_PROTECTION_BYPASS_HEADER=`x-vercel-protection-bypass`;export{VERCEL_PROTECTION_BYPASS_HEADER,resolveDevelopmentOidcToken};
1
+ import{object,string}from"../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{toErrorMessage}from"#shared/errors.js";import{getVercelOidcToken}from"#compiled/@vercel/oidc/index.js";const VercelOidcClaimsSchema=object({owner_id:string().min(1),project_id:string().min(1)});async function resolveDevelopmentOidcToken(e){try{let t={team:e.ownerId,project:e.projectId};return e.forceRefresh===!0&&(t.expirationBufferMs=2**53-1),validateDevelopmentOidcToken((await getVercelOidcToken(t)).trim(),e)}catch(e){return{kind:`resolution-failed`,message:toErrorMessage(e)}}}function validateDevelopmentOidcToken(e,t){let n=e.split(`.`)[1];if(!n)return{kind:`malformed-token`,reason:`missing-payload`};let r;try{r=JSON.parse(Buffer.from(n,`base64url`).toString(`utf8`))}catch{return{kind:`malformed-token`,reason:`invalid-json-payload`}}let i=VercelOidcClaimsSchema.safeParse(r);if(!i.success)return{kind:`invalid-claims`,invalidClaims:i.error.issues.map(e=>{let t=e.path[0];return t===`owner_id`||t===`project_id`?t:`claims`})};let a=[];return i.data.owner_id!==t.ownerId&&a.push(`owner_id`),i.data.project_id!==t.projectId&&a.push(`project_id`),a.length>0?{kind:`target-mismatch`,mismatchedClaims:a}:{kind:`resolved`,token:e}}const VERCEL_PROTECTION_BYPASS_HEADER=`x-vercel-protection-bypass`;export{VERCEL_PROTECTION_BYPASS_HEADER,resolveDevelopmentOidcToken};
@@ -14,31 +14,29 @@
14
14
  * actionable message instead.
15
15
  */
16
16
  import type { DevelopmentOidcTokenFailure } from "#services/dev-client/request-headers.js";
17
+ /** Returns the stable Trusted Sources code embedded in a Vercel error message. */
18
+ export declare function vercelTrustedSourcesErrorCode(message: string): string | undefined;
17
19
  /**
18
- * Returns `true` when the thrown error is the Vercel Deployment
19
- * Protection SSO challenge.
20
+ * Returns `true` for an HTTP 401 carrying Vercel's protection challenge.
20
21
  *
21
22
  * Accepts both real {@link ClientError} instances and structurally
22
23
  * compatible duck-typed errors (`{ status: number, body: string }`)
23
24
  * so callers can detect the challenge regardless of whether the
24
25
  * error survived a network/IPC boundary.
25
- *
26
- * Exported so the dev REPL and other dev-client consumers can render
27
- * a focused authentication directive instead of dumping the SSO
28
- * challenge HTML to the terminal.
29
26
  */
30
27
  export declare function isVercelAuthChallenge(error: unknown): boolean;
31
28
  /**
32
- * Builds the human-readable message rendered when
33
- * {@link isVercelAuthChallenge} returns `true`.
34
- *
35
- * The message states the cause, the target URL, and the supported escape
36
- * hatches (link the project so an OIDC token can be minted, set an
37
- * automation bypass token, or disable protection). It is intentionally
38
- * short — multi-line CLI output is harder to scan than a focused
39
- * directive.
29
+ * Builds the human-readable repair message for the existing dev-client
30
+ * challenge surface, including a structured local OIDC failure when known.
40
31
  */
41
32
  export declare function formatVercelAuthChallengeMessage(input: {
42
33
  readonly serverUrl: string;
43
34
  readonly oidcTokenFailure?: DevelopmentOidcTokenFailure;
44
35
  }): string;
36
+ export declare function formatDevelopmentOidcTokenFailure(failure: DevelopmentOidcTokenFailure): string;
37
+ /**
38
+ * Keeps the actionable Trusted Sources reason and stable error code while
39
+ * dropping Vercel's per-request id. The id is useful in platform logs but is
40
+ * noise in a command result and changes on every retry.
41
+ */
42
+ export declare function formatVercelTrustedSourcesFailure(message: string): string;
@@ -1,2 +1,9 @@
1
- import{isObject}from"#shared/guards.js";import{ClientError}from"#client/client-error.js";const VERCEL_AUTH_CHALLENGE_MARKERS=[`vercel.com/sso-api`,`<title>Authentication Required</title>`,`Vercel Authentication`];function bodyLooksLikeVercelAuthChallenge(e){return e.length>0&&VERCEL_AUTH_CHALLENGE_MARKERS.every(t=>e.includes(t))}function isVercelAuthChallenge(n){return n instanceof ClientError?n.status===401&&bodyLooksLikeVercelAuthChallenge(n.body):isObject(n)&&n.status===401&&typeof n.body==`string`&&bodyLooksLikeVercelAuthChallenge(n.body)}function formatVercelAuthChallengeMessage(e){let t=[`Vercel Deployment Protection blocked the request to ${e.serverUrl}.`];return e.oidcTokenFailure!==void 0&&t.push(``,formatOidcTokenFailure(e.oidcTokenFailure)),t.push(``,"To access the deployment from `eve dev`, do one of:"," • Run `vercel link` in this project so the CLI can mint an OIDC",` token for the deployment automatically.`,` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`),t.join(`
2
- `)}function formatOidcTokenFailure(e){switch(e.kind){case`resolution-failed`:return`The local Vercel OIDC token could not be resolved: ${e.message}`;case`malformed-token`:return e.reason===`missing-payload`?`Vercel returned a local OIDC token without a JWT payload.`:`Vercel returned a local OIDC token whose payload is not valid JSON.`;case`invalid-claims`:return`The local Vercel OIDC token has invalid claims: ${e.invalidClaims.join(`, `)}.`;case`target-mismatch`:return`The local Vercel OIDC token does not match the resolved deployment: ${e.mismatchedClaims.join(`, `)}.`;default:return e}}export{formatVercelAuthChallengeMessage,isVercelAuthChallenge};
1
+ import{isObject}from"#shared/guards.js";import{ClientError}from"#client/client-error.js";const VERCEL_AUTH_CHALLENGE_MARKERS=[`vercel.com/sso-api`,`<title>Authentication Required</title>`],TRUSTED_SOURCES_ERROR_CODE=/^TRUSTED_SOURCES_[A-Z0-9_]+$/u;function vercelTrustedSourcesErrorCode(e){for(let t of e.replaceAll(`\r
2
+ `,`
3
+ `).trim().split(`
4
+ `)){let e=t.trim();if(TRUSTED_SOURCES_ERROR_CODE.test(e))return e}}function bodyLooksLikeVercelAuthChallenge(e){return e.length>0&&VERCEL_AUTH_CHALLENGE_MARKERS.every(t=>e.includes(t))}function isVercelAuthChallenge(n){return n instanceof ClientError?n.status===401&&bodyLooksLikeVercelAuthChallenge(n.body):isObject(n)&&n.status===401&&typeof n.body==`string`&&bodyLooksLikeVercelAuthChallenge(n.body)}function formatVercelAuthChallengeMessage(e){let t=[`Vercel Deployment Protection blocked the request to ${e.serverUrl}.`];return e.oidcTokenFailure!==void 0&&t.push(``,formatDevelopmentOidcTokenFailure(e.oidcTokenFailure)),t.push(``,"To access the deployment from `eve dev`, do one of:"," • Run `vercel link` in this project so the CLI can mint an OIDC",` token for the deployment automatically.`,` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`),t.join(`
5
+ `)}function formatDevelopmentOidcTokenFailure(e){switch(e.kind){case`resolution-failed`:return`The local Vercel OIDC token could not be resolved: ${e.message}`;case`malformed-token`:return e.reason===`missing-payload`?`Vercel returned a local OIDC token without a JWT payload.`:`Vercel returned a local OIDC token whose payload is not valid JSON.`;case`invalid-claims`:return`The local Vercel OIDC token has invalid claims: ${e.invalidClaims.join(`, `)}.`;case`target-mismatch`:return`The local Vercel OIDC token does not match the resolved deployment: ${e.mismatchedClaims.join(`, `)}.`;default:return e}}function formatVercelTrustedSourcesFailure(e){let t=e.replaceAll(`\r
6
+ `,`
7
+ `).trim().split(`
8
+ `),n=t.findIndex(e=>TRUSTED_SOURCES_ERROR_CODE.test(e.trim()));if(n<0)return e;let r=t[n].trim(),i=t.slice(0,n).join(`
9
+ `).trim();return i.length===0?e:`${i}\n\n${r}`}export{formatDevelopmentOidcTokenFailure,formatVercelAuthChallengeMessage,formatVercelTrustedSourcesFailure,isVercelAuthChallenge,vercelTrustedSourcesErrorCode};
@@ -26,7 +26,7 @@ export interface InstallVercelCliDeps {
26
26
  spawnPackageManager: typeof spawnPackageManager;
27
27
  }
28
28
  /**
29
- * THE INSTALL FLOW for the dev TUI's `/vc`: the fix command for the
29
+ * THE INSTALL FLOW for the dev TUI's `/vc:install`: the fix command for the
30
30
  * "Vercel CLI not found" diagnostic, so every diagnostic has a matching
31
31
  * command. Short-circuits when the CLI already resolves; otherwise runs a
32
32
  * global install with the project's package manager, streaming output to the
@@ -36,7 +36,7 @@ export interface LoginFlowDeps {
36
36
  }) => Promise<boolean>;
37
37
  }
38
38
  /**
39
- * THE LOGIN FLOW for the dev TUI's `/login`. Short-circuits when already
39
+ * THE LOGIN FLOW for the dev TUI's `/vc:login`. Short-circuits when already
40
40
  * authenticated; otherwise runs `vercel login` as a browser flow the TUI waits
41
41
  * on (see {@link runVercelLoginWithControls}) and re-probes after, so a
42
42
  * half-finished or abandoned login reports `failed`, never a false success.
@@ -44,6 +44,8 @@ export interface LoginFlowDeps {
44
44
  export declare function runLoginFlow(input: {
45
45
  appRoot: string;
46
46
  prompter: Prompter;
47
+ /** Run the browser login even when the account-level Vercel session is valid. */
48
+ force?: boolean;
47
49
  signal?: AbortSignal;
48
50
  deps?: Partial<LoginFlowDeps>;
49
51
  }): Promise<LoginFlowResult>;
@@ -1 +1 @@
1
- import{withSpinner}from"../with-spinner.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";import{runVercel}from"#setup/primitives/run-vercel.js";const defaultDeps={getVercelAuthStatus,runVercelLogin:({cwd:e,onOutput:t,signal:n})=>runVercel([`login`],{cwd:e,nonInteractive:!0,onOutput:t,timeoutMs:3e5,signal:n})};async function runVercelLoginWithControls(t,n,r,i,a){if(i.awaitChoice===void 0)return withSpinner(i,`Opening Vercel login in your browser…`,()=>t.runVercelLogin({cwd:n,onOutput:r,signal:a}));let o=new AbortController,s=a?AbortSignal.any([a,o.signal]):o.signal,c=i.awaitChoice({status:`Logging in to Vercel…`,context:`Complete the login in your browser`,actions:[{value:`cancel`,label:`Cancel`}]}),l=t.runVercelLogin({cwd:n,onOutput:r,signal:s});try{let e=await Promise.race([l.then(e=>({via:`work`,ok:e})),c.choice.then(()=>({via:`choice`}))]);return e.via===`work`?e.ok:(o.abort(),await l.catch(()=>{}),`cancelled`)}finally{c.close()}}async function runLoginFlow(t){let{appRoot:r,prompter:a,signal:o}=t,s={...defaultDeps,...t.deps},c=createPromptCommandOutput(a.log),probeAuth=()=>s.getVercelAuthStatus(r,{signal:o}),l=await withSpinner(a,`Checking your Vercel login…`,probeAuth);switch(o?.throwIfAborted(),l){case`authenticated`:return{kind:`already`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};case`logged-out`:break;default:return l}let u=await runVercelLoginWithControls(s,r,c,a,o);if(u===`cancelled`)return{kind:`cancelled`};if(!u)return{kind:`failed`};let d=await withSpinner(a,`Confirming your Vercel login…`,probeAuth);switch(o?.throwIfAborted(),d){case`authenticated`:return{kind:`logged-in`};case`logged-out`:return{kind:`failed`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};default:return d}}export{runLoginFlow};
1
+ import{withSpinner}from"../with-spinner.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";import{runVercel}from"#setup/primitives/run-vercel.js";const defaultDeps={getVercelAuthStatus,runVercelLogin:({cwd:e,onOutput:t,signal:n})=>runVercel([`login`],{cwd:e,nonInteractive:!0,onOutput:t,timeoutMs:3e5,signal:n})};async function runVercelLoginWithControls(t,n,r,i,a){if(i.awaitChoice===void 0)return withSpinner(i,`Opening Vercel login in your browser…`,()=>t.runVercelLogin({cwd:n,onOutput:r,signal:a}));let o=new AbortController,s=a?AbortSignal.any([a,o.signal]):o.signal,c=i.awaitChoice({status:`Logging in to Vercel…`,context:`Complete the login in your browser`,actions:[{value:`cancel`,label:`Cancel`}]}),l=t.runVercelLogin({cwd:n,onOutput:r,signal:s});try{let e=await Promise.race([l.then(e=>({via:`work`,ok:e})),c.choice.then(()=>({via:`choice`}))]);return e.via===`work`?e.ok:(o.abort(),await l.catch(()=>{}),`cancelled`)}finally{c.close()}}async function runLoginFlow(t){let{appRoot:r,prompter:a,signal:o}=t,s={...defaultDeps,...t.deps},c=createPromptCommandOutput(a.log),probeAuth=()=>s.getVercelAuthStatus(r,{signal:o}),l=await withSpinner(a,`Checking your Vercel login…`,probeAuth);switch(o?.throwIfAborted(),l){case`authenticated`:if(t.force!==!0)return{kind:`already`};break;case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};case`logged-out`:break;default:return l}let u=await runVercelLoginWithControls(s,r,c,a,o);if(u===`cancelled`)return{kind:`cancelled`};if(!u)return{kind:`failed`};let d=await withSpinner(a,`Confirming your Vercel login…`,probeAuth);switch(o?.throwIfAborted(),d){case`authenticated`:return{kind:`logged-in`};case`logged-out`:return{kind:`failed`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};default:return d}}export{runLoginFlow};