eve 0.27.1 → 0.27.3

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 (79) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/src/channel/session-callback.js +1 -1
  3. package/dist/src/chunks/{use-eve-agent-PMY2WkAt.js → use-eve-agent-CbF0l_Fp.js} +66 -27
  4. package/dist/src/chunks/{use-eve-agent-AeQLLhu9.js → use-eve-agent-CgxB9WQv.js} +66 -27
  5. package/dist/src/cli/commands/build.js +1 -1
  6. package/dist/src/cli/commands/info.js +1 -1
  7. package/dist/src/cli/dev/tui/setup-commands.js +1 -1
  8. package/dist/src/client/index.d.ts +1 -1
  9. package/dist/src/client/open-stream.d.ts +15 -2
  10. package/dist/src/client/open-stream.js +1 -1
  11. package/dist/src/client/session.d.ts +3 -2
  12. package/dist/src/client/session.js +1 -1
  13. package/dist/src/client/types.d.ts +32 -0
  14. package/dist/src/context/dynamic-tool-lifecycle.d.ts +13 -1
  15. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  16. package/dist/src/context/keys.d.ts +5 -0
  17. package/dist/src/context/keys.js +1 -1
  18. package/dist/src/execution/node-step.d.ts +6 -0
  19. package/dist/src/execution/node-step.js +1 -1
  20. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  21. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  22. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  23. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  24. package/dist/src/execution/terminal-session-failure-step.js +1 -1
  25. package/dist/src/execution/workflow-callback-url.d.ts +12 -2
  26. package/dist/src/execution/workflow-callback-url.js +1 -1
  27. package/dist/src/execution/workflow-entry.js +1 -1
  28. package/dist/src/execution/workflow-steps.js +1 -1
  29. package/dist/src/internal/application/package.js +1 -1
  30. package/dist/src/internal/authored-module-evaluation-error.d.ts +2 -0
  31. package/dist/src/internal/authored-module-evaluation-error.js +4 -0
  32. package/dist/src/internal/authored-module-loader.js +3 -3
  33. package/dist/src/internal/authored-package-tsconfig-paths.js +1 -1
  34. package/dist/src/internal/authored-relative-extension-resolver.d.ts +6 -0
  35. package/dist/src/internal/authored-relative-extension-resolver.js +1 -0
  36. package/dist/src/internal/nitro/host/build-application.js +1 -1
  37. package/dist/src/internal/nitro/host/types.d.ts +9 -0
  38. package/dist/src/internal/node-esm-compat-banner.js +1 -1
  39. package/dist/src/internal/workflow-bundle/builder-support.d.ts +5 -0
  40. package/dist/src/internal/workflow-bundle/builder.js +2 -2
  41. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +39 -0
  42. package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.js +1 -0
  43. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +4 -4
  44. package/dist/src/internal/workflow-bundle/vercel-workflow-output.d.ts +10 -1
  45. package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
  46. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  47. package/dist/src/public/channels/eve.js +2 -1
  48. package/dist/src/public/channels/linear/inbound-images.d.ts +18 -0
  49. package/dist/src/public/channels/linear/inbound-images.js +1 -0
  50. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  51. package/dist/src/public/channels/slack/api.d.ts +26 -2
  52. package/dist/src/public/channels/slack/api.js +1 -1
  53. package/dist/src/public/channels/slack/attachments.d.ts +6 -5
  54. package/dist/src/public/channels/slack/index.d.ts +1 -1
  55. package/dist/src/public/channels/slack/interactions.d.ts +2 -1
  56. package/dist/src/public/channels/slack/interactions.js +1 -1
  57. package/dist/src/public/channels/slack/limits.js +1 -1
  58. package/dist/src/public/channels/slack/slackChannel.d.ts +51 -14
  59. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  60. package/dist/src/public/channels/slack/thread.d.ts +4 -3
  61. package/dist/src/public/channels/slack/thread.js +1 -1
  62. package/dist/src/public/next/vercel-output-config.js +1 -1
  63. package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
  64. package/dist/src/setup/flows/install-vercel-cli.d.ts +8 -2
  65. package/dist/src/setup/flows/install-vercel-cli.js +1 -1
  66. package/dist/src/setup/scaffold/create/project.js +1 -1
  67. package/dist/src/setup/vercel-project-api.js +1 -1
  68. package/dist/src/shared/public-route-prefix.d.ts +23 -0
  69. package/dist/src/shared/public-route-prefix.js +1 -0
  70. package/dist/src/svelte/index.js +1 -1
  71. package/dist/src/svelte/use-eve-agent.js +1 -1
  72. package/dist/src/vue/index.js +1 -1
  73. package/dist/src/vue/use-eve-agent.js +1 -1
  74. package/docs/channels/linear.mdx +1 -1
  75. package/docs/channels/slack.mdx +40 -3
  76. package/docs/extensions.md +2 -2
  77. package/docs/guides/client/streaming.mdx +15 -0
  78. package/docs/guides/frontend/nextjs.mdx +2 -0
  79. 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{atomicWriteFile}from"#shared/atomic-write-file.js";import{buildSingleRolldownChunk}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{deriveEveWorkflowQueueNamespace}from"#internal/workflow/queue-namespace.js";import{createEveWorkflowQueueTrigger,detectWorkflowPatterns}from"#internal/workflow-bundle/workflow-builders.js";import{Buffer}from"node:buffer";import{runQueuedWorkflowBuild}from"#internal/workflow-bundle/build-queue.js";import{WORKFLOW_VIRTUAL_ENTRY_ID,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";var WorkflowBundleBuilder=class{#e;#t;#n;#r;config;#i=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.agentName,this.#t=t.compiledArtifactsBootstrapPath,this.#n=t.outDir,this.#r=deriveEveWorkflowQueueNamespace(t.agentName)}async build(e={}){await runQueuedWorkflowBuild(this.#n,async()=>this.#a(e))}async#a(i){await prepareEveVersionedCacheDirectory(this.#n);let a=await this.#o();if(a.length===0)throw Error(`Expected the execution workflow source file under "${resolvePackageSourceDirectoryPath(`src/execution`)}".`);let o=await this.findTsConfigPath();await mkdir(this.#n,{recursive:!0});let c=await this.discoverEntries(a,this.#n,o),l=join(this.#n,`workflows.mjs`),{manifest:u}=await this.createWorkflowsBundle({discoveredEntries:c,keepInterimBundleContext:!1,outfile:l,bundleFinalOutput:!1,format:`esm`,inputFiles:a,tsconfigPath:o}),d=join(this.#n,`steps.mjs`),f=await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:d,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,sideEffectFiles:[this.#t],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,sideEffectFiles:[this.#t],workingDir:this.config.workingDir}),await addStepRegistrationsImport(l,d),await rewriteWorkflowRuntimeImports(l),await rewriteWorkflowCodeLiteral(l,this.#r);let h=i.nitroWorkflowOutfile;h!==void 0&&h!==l&&(await mkdir(dirname(h),{recursive:!0}),await mirrorFileBypassingUnlink(l,h),p!==void 0&&(await addStepRegistrationsImport(h,p),await rewriteWorkflowRuntimeImports(h),await rewriteWorkflowCodeLiteral(h,this.#r))),await this.createManifest({workflowBundlePath:join(this.#n,`workflows.mjs`),manifestDir:this.#n,manifest:{steps:{...f.steps,...u.steps},workflows:{...f.workflows,...u.workflows},classes:{...f.classes,...u.classes}}}),await writeEveVersionedCacheMetadata(this.#n)}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.#i.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.#i.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={},m=[...l.map(e=>createWorkflowImport(e,this.config.workingDir)),...d.map(e=>createWorkflowImport(e,this.config.workingDir))].join(`
2
- `);return await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:(await buildSingleRolldownChunk(`intermediate workflow bundle for "${o}"`,{cwd:this.config.workingDir,input:WORKFLOW_VIRTUAL_ENTRY_ID,platform:`neutral`,plugins:[createWorkflowVirtualEntryPlugin(m),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,output:{banner:`globalThis.__private_workflows = new Map();`,comments:!1,format:`cjs`,sourcemap:`inline`}})).code,format:r,outfile:o,queueNamespace:this.#r,workingDir:this.config.workingDir}),a?{bundleFinal:async t=>{await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:t,format:r,outfile:o,queueNamespace:this.#r,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.#n,`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.#s(n,{experimentalTriggers:[createEveWorkflowQueueTrigger(this.#e)],maxDuration:`max`,runtime:e.runtime??null,shouldAddHelpers:!1}),cp(join(this.#n,`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#o(){return await this.getInputFiles()}async#s(e,t){let n=join(e,`.vc-config.json`),i=await this.#c(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#c(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{atomicWriteFile}from"#shared/atomic-write-file.js";import{buildSingleRolldownChunk}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{deriveEveWorkflowQueueNamespace}from"#internal/workflow/queue-namespace.js";import{createEveWorkflowQueueTrigger,detectWorkflowPatterns}from"#internal/workflow-bundle/workflow-builders.js";import{Buffer}from"node:buffer";import{runQueuedWorkflowBuild}from"#internal/workflow-bundle/build-queue.js";import{WORKFLOW_VIRTUAL_ENTRY_ID,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";var WorkflowBundleBuilder=class{#e;#t;#n;#r;#i;config;#a=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.agentName,this.#t=t.compiledArtifactsBootstrapPath,this.#n=t.outDir,this.#r=t.publicRoutePrefix,this.#i=deriveEveWorkflowQueueNamespace(t.agentName)}async build(e={}){await runQueuedWorkflowBuild(this.#n,async()=>this.#o(e))}async#o(i){await prepareEveVersionedCacheDirectory(this.#n);let a=await this.#s();if(a.length===0)throw Error(`Expected the execution workflow source file under "${resolvePackageSourceDirectoryPath(`src/execution`)}".`);let o=await this.findTsConfigPath();await mkdir(this.#n,{recursive:!0});let c=await this.discoverEntries(a,this.#n,o),l=join(this.#n,`workflows.mjs`),{manifest:u}=await this.createWorkflowsBundle({discoveredEntries:c,keepInterimBundleContext:!1,outfile:l,bundleFinalOutput:!1,format:`esm`,inputFiles:a,tsconfigPath:o}),d=join(this.#n,`steps.mjs`),f=await writeNitroStepEntrypoint({builtinsPath:resolveWorkflowModulePath(`workflow/internal/builtins`),discoveredEntries:c,outfile:d,preferAbsoluteFileImports:!0,projectRoot:this.config.projectRoot??this.config.workingDir,sideEffectFiles:[this.#t],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,sideEffectFiles:[this.#t],workingDir:this.config.workingDir}),await addStepRegistrationsImport(l,d),await rewriteWorkflowRuntimeImports(l),await rewriteWorkflowCodeLiteral(l,this.#i);let h=i.nitroWorkflowOutfile;h!==void 0&&h!==l&&(await mkdir(dirname(h),{recursive:!0}),await mirrorFileBypassingUnlink(l,h),p!==void 0&&(await addStepRegistrationsImport(h,p),await rewriteWorkflowRuntimeImports(h),await rewriteWorkflowCodeLiteral(h,this.#i))),await this.createManifest({workflowBundlePath:join(this.#n,`workflows.mjs`),manifestDir:this.#n,manifest:{steps:{...f.steps,...u.steps},workflows:{...f.workflows,...u.workflows},classes:{...f.classes,...u.classes}}}),await writeEveVersionedCacheMetadata(this.#n)}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.#a.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.#a.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={},m=[...l.map(e=>createWorkflowImport(e,this.config.workingDir)),...d.map(e=>createWorkflowImport(e,this.config.workingDir))].join(`
2
+ `);return await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:(await buildSingleRolldownChunk(`intermediate workflow bundle for "${o}"`,{cwd:this.config.workingDir,input:WORKFLOW_VIRTUAL_ENTRY_ID,platform:`neutral`,plugins:[createWorkflowVirtualEntryPlugin(m),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,output:{banner:`globalThis.__private_workflows = new Map();`,comments:!1,format:`cjs`,sourcemap:`inline`}})).code,format:r,outfile:o,queueNamespace:this.#i,workingDir:this.config.workingDir}),a?{bundleFinal:async t=>{await bundleFinalWorkflowOutput({bundleFinalOutput:e,code:t,format:r,outfile:o,queueNamespace:this.#i,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.#n,`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.#c(n,{experimentalTriggers:[createEveWorkflowQueueTrigger(this.#e)],maxDuration:`max`,runtime:e.runtime??null,shouldAddHelpers:!1}),cp(join(this.#n,`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#s(){return await this.getInputFiles()}async#c(e,t){let n=join(e,`.vc-config.json`),i=await this.#l(n),a={...i};a.environment=createWorkflowFunctionEnvironment({environment:i.environment,publicRoutePrefix:this.#r}),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#l(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,t){let n=await readTextFileIfPresent(e);if(n===null)return;let r=`;\n\nexport const POST = workflowEntrypoint(workflowCode, { namespace: ${JSON.stringify(t)} });`,i=n.indexOf(`const workflowCode = `),a=n.lastIndexOf(r);if(i===-1||a===-1||a<=i)return;let o=i+21,s=n.slice(o,a);if(!s.trimStart().startsWith("`"))return;let c=decodeWorkflowCodeTemplateLiteral(s,e),l=`${n.slice(0,o)}${encodeWorkflowCodeLiteral(c)}${n.slice(a)}`;l!==n&&await atomicWriteFile(e,l)}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};
@@ -0,0 +1,39 @@
1
+ /** Rolldown AST subset consumed by the dynamic-tool transform. */
2
+ export type DynamicToolAstNode = {
3
+ argument?: DynamicToolAstNode | null;
4
+ arguments?: DynamicToolAstNode[];
5
+ async?: boolean;
6
+ body?: DynamicToolAstNode | DynamicToolAstNode[] | {
7
+ body?: DynamicToolAstNode[];
8
+ type?: string;
9
+ start?: number;
10
+ end?: number;
11
+ };
12
+ callee?: DynamicToolAstNode;
13
+ computed?: boolean;
14
+ declaration?: DynamicToolAstNode | null;
15
+ declarations?: DynamicToolAstNode[];
16
+ end?: number;
17
+ expression?: DynamicToolAstNode | null;
18
+ id?: {
19
+ name?: string;
20
+ start?: number;
21
+ end?: number;
22
+ } | null;
23
+ init?: DynamicToolAstNode | null;
24
+ key?: DynamicToolAstNode | null;
25
+ kind?: string;
26
+ left?: DynamicToolAstNode | null;
27
+ method?: boolean;
28
+ name?: string;
29
+ params?: DynamicToolAstNode[];
30
+ properties?: DynamicToolAstNode[];
31
+ right?: DynamicToolAstNode | null;
32
+ start?: number;
33
+ type?: string;
34
+ value?: DynamicToolAstNode | unknown;
35
+ };
36
+ /**
37
+ * Collects identifiers used as runtime references in a function body AST.
38
+ */
39
+ export declare function collectReferencedIdentifierNames(node: DynamicToolAstNode): Set<string>;
@@ -0,0 +1 @@
1
+ function collectReferencedIdentifierNames(e){let t=new Set,visit=(e,n)=>{if(e.type?.startsWith(`TS`)){isRuntimeTypeScriptExpression(e)&&e.expression&&visit(e.expression,`reference`);return}e.type===`Identifier`&&e.name&&n===`reference`&&t.add(e.name);for(let[t,r]of Object.entries(e)){let i=getChildContext(e,t,n);if(i)if(Array.isArray(r))for(let e of r)isAstNode(e)&&visit(e,i);else isAstNode(r)&&visit(r,i)}};return visit(e,`reference`),t}function getChildContext(e,t,n){return t===`typeAnnotation`||t===`returnType`||t===`typeParameters`||t===`typeArguments`?null:e.type===`VariableDeclarator`&&t===`id`||(e.type===`FunctionExpression`||e.type===`ArrowFunctionExpression`||e.type===`FunctionDeclaration`)&&(t===`id`||t===`params`)||e.type===`CatchClause`&&t===`param`||(e.type===`ClassDeclaration`||e.type===`ClassExpression`)&&t===`id`?`binding`:e.type===`Property`&&t===`key`?e.computed===!0?`reference`:null:e.type===`Property`&&t===`value`?n:e.type===`AssignmentPattern`?t===`right`?`reference`:n:(e.type===`ObjectPattern`||e.type===`ArrayPattern`||e.type===`RestElement`)&&(t===`properties`||t===`elements`||t===`argument`)?n:(e.type===`MemberExpression`||e.type===`OptionalMemberExpression`)&&t===`property`||(e.type===`MethodDefinition`||e.type===`PropertyDefinition`)&&t===`key`?e.computed===!0?`reference`:null:(e.type===`LabeledStatement`||e.type===`BreakStatement`||e.type===`ContinueStatement`)&&t===`label`?null:`reference`}function isRuntimeTypeScriptExpression(e){return e.type===`TSAsExpression`||e.type===`TSInstantiationExpression`||e.type===`TSNonNullExpression`||e.type===`TSSatisfiesExpression`||e.type===`TSTypeAssertion`}function isAstNode(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}export{collectReferencedIdentifierNames};
@@ -1,4 +1,4 @@
1
- import{parseWithNitroRolldownAst}from"#internal/bundler/nitro-rolldown.js";let transformCounter=0;async function transformDynamicToolExecute(e,t){if(!t.includes(`defineDynamic`)||!t.includes(`events`)||!t.includes(`execute`))return null;let n=findDynamicToolHandlers(t,await parseSource(e,t));return n.every(e=>e.executes.length===0)?null:applyTransform(t,n)}async function parseSource(t,n){return await parseWithNitroRolldownAst(t,n)}function findDynamicToolHandlers(e,t){let n=[];return walkNode(t,t=>{if(t.type===`CallExpression`&&t.callee?.type===`Identifier`&&t.callee.name===`defineDynamic`&&t.arguments?.length===1){let r=t.arguments[0];if(r.type===`ObjectExpression`){let t=findProperty(r,`events`);t?.value&&t.value.type===`ObjectExpression`&&collectHandlers(e,t.value,n)}return!1}return!0}),n}function collectHandlers(e,t,n){for(let r of t.properties??[]){if(r.type!==`Property`)continue;let t=r.value;if(!t||t.type!==`ArrowFunctionExpression`&&t.type!==`FunctionExpression`)continue;let i=t.body;if(!i)continue;let a=findBlockBodyStart(i);if(a===null)continue;let o=extractParamNames(t),s=collectScopeVarDeclarations(i),c=findExecuteFunctions(e,i);c.length>0&&n.push({handlerNode:t,bodyStart:a,scopeVars:s,paramNames:o,executes:c})}}function findBlockBodyStart(e){return e.type===`BlockStatement`&&e.start!==void 0?e.start:typeof e.body==`object`&&!Array.isArray(e.body)&&e.body?.type===`BlockStatement`&&e.body.start!==void 0?e.body.start:null}function extractParamNames(e){let t=[];for(let n of e.params??[])n.type===`Identifier`&&n.name&&t.push(n.name);return t}function collectScopeVarDeclarations(e){let t=[];return collectVarsRecursive(e,t),t}function collectVarsRecursive(e,t){if(!e||e.type===`FunctionExpression`||e.type===`ArrowFunctionExpression`||e.type===`FunctionDeclaration`)return;if(e.type===`VariableDeclaration`)for(let n of e.declarations??[])collectDeclaredNames(n,t);e.type===`ForStatement`&&e.init&&collectVarsRecursive(e.init,t);let n=e;if((e.type===`ForInStatement`||e.type===`ForOfStatement`)&&e.left&&collectVarsRecursive(e.left,t),Array.isArray(e.body))for(let n of e.body)collectVarsRecursive(n,t);else e.body&&typeof e.body==`object`&&`type`in e.body&&collectVarsRecursive(e.body,t);if(e.declarations)for(let n of e.declarations)collectVarsRecursive(n,t);if(e.expression&&collectVarsRecursive(e.expression,t),Array.isArray(n.consequent))for(let e of n.consequent)collectVarsRecursive(e,t);else n.consequent&&collectVarsRecursive(n.consequent,t);if(n.alternate&&collectVarsRecursive(n.alternate,t),n.block&&collectVarsRecursive(n.block,t),n.handler&&collectVarsRecursive(n.handler,t),n.finalizer&&collectVarsRecursive(n.finalizer,t),n.cases&&Array.isArray(n.cases))for(let e of n.cases)collectVarsRecursive(e,t)}function collectDeclaredNames(e,t){e.type===`VariableDeclarator`&&collectPatternNames(e.id,t)}function collectPatternNames(e,t){if(e){if(e.type===`Identifier`&&e.name){t.push(e.name);return}if(e.type===`ObjectPattern`)for(let n of e.properties??[])n.type===`Property`?collectPatternNames(n.value,t):n.type===`RestElement`&&collectPatternNames(n.argument,t);if(e.type===`ArrayPattern`)for(let n of e.elements??[])n&&collectPatternNames(n,t)}}function findExecuteFunctions(e,t){let n=[];return walkForExecuteProps(e,t,n,[]),n}function walkForExecuteProps(e,n,r,i){if(!n)return;if(n.type===`FunctionExpression`||n.type===`ArrowFunctionExpression`||n.type===`FunctionDeclaration`){let t=extractParamNames(n),a=n.body;if(!a)return;let o=collectScopeVarDeclarations(a),s=[...i,{params:t,vars:o}];a.type,walkForExecuteProps(e,a,r,s);return}if(n.type===`CallExpression`&&n.callee?.type===`Identifier`&&n.callee.name===`defineTool`&&n.arguments?.length===1&&n.arguments[0].type===`ObjectExpression`){let a=n.arguments[0];for(let n of a.properties??[])if(n.type===`Property`&&!n.computed&&n.key?.type===`Identifier`&&n.key.name===`execute`&&n.start!==void 0&&n.end!==void 0){let a=n.value;if(!a||a.start===void 0||a.end===void 0)continue;let o=a.type===`FunctionExpression`||a.type===`ArrowFunctionExpression`,s=n.method===!0;if(o||s){let o=extractFnParams(e,a),s=extractFnBody(e,a),c=a.async===!0;r.push({propStart:n.start,propEnd:n.end,fnSource:e.slice(a.start,a.end),isAsync:c,params:o,body:s,hoistedName:`__eve_dynamic_exec_${transformCounter++}`,nestedScopes:i})}}return}let walk=t=>walkForExecuteProps(e,t,r,i);if(Array.isArray(n.body))for(let e of n.body)walk(e);else n.body&&typeof n.body==`object`&&`type`in n.body&&walk(n.body);if(n.properties)for(let e of n.properties)e.value&&typeof e.value==`object`&&`type`in e.value&&walk(e.value);if(n.callee&&walk(n.callee),n.arguments)for(let e of n.arguments)walk(e);if(n.expression&&walk(n.expression),n.argument&&walk(n.argument),n.init&&walk(n.init),n.left&&walk(n.left),n.right&&walk(n.right),n.declarations)for(let e of n.declarations)walk(e);let a=n;if(Array.isArray(a.consequent))for(let e of a.consequent)walk(e);else a.consequent&&walk(a.consequent);if(a.alternate&&walk(a.alternate),a.block&&walk(a.block),a.handler&&walk(a.handler),a.finalizer&&walk(a.finalizer),a.cases&&Array.isArray(a.cases))for(let e of a.cases)walk(e)}function extractFnParams(e,t){if(!t.params||t.params.length===0)return``;let n=t.params[0],r=t.params[t.params.length-1];return n.start===void 0||r.end===void 0?``:e.slice(n.start,r.end)}function extractFnBody(e,t){let n=t.body;if(!n||n.start===void 0||n.end===void 0)return`{}`;let r=e.slice(n.start,n.end);return t.type===`ArrowFunctionExpression`&&n.type!==`BlockStatement`?`{ return ${r}; }`:r}function applyTransform(e,t){let n=[],r=[],i=[],a=[];for(let e of t)for(let t of e.executes){let o=[...e.paramNames,...e.scopeVars,...t.nestedScopes.flatMap(e=>[...e.params,...e.vars])],s=new Set,c=[];for(let e=o.length-1;e>=0;e--)s.has(o[e])||(s.add(o[e]),c.unshift(o[e]));let l=t.body,u=extractExecuteParamNames(t.params),d=c.filter(e=>!u.has(e)&&RegExp(`\\b${escapeForRegex(e)}\\b`).test(l)),f=d.length>0?`{ ${d.join(`, `)} }`:`{}`,p=t.isAsync?`async `:``,m=d.length>0?`const ${f} = __vars;\n `:``,h=t.params,g=h?`__vars, ${h}`:`__vars`,_=t.body.slice(1,-1).trim(),v=`eve:dynamic-tool//${t.hoistedName}`;r.push(`${p}function ${t.hoistedName}(${g}) {\n ${m}${_}\n}`),i.push(`${t.hoistedName}.stepId = ${JSON.stringify(v)};`),i.push(`__eveStepRegistry.set(${JSON.stringify(v)}, ${t.hoistedName});`),a.push(t.hoistedName);let y=h||``,b=h?splitParamsTopLevel(h).map(e=>extractParamBindingName(e)).join(`, `):``,x=b?`${f}, ${b}`:f,S=t.isAsync?`async `:``,C=t.isAsync?`await `:``;n.push({start:t.propStart,end:t.propEnd,text:[`execute: ${S}(${y}) => ${C}${t.hoistedName}(${x})`,`__executeStepFn: ${t.hoistedName}`,`__closureVars: ${f}`].join(`,
2
- `)})}let o=[...n].sort((e,t)=>t.start-e.start),s=e;for(let e of o)s=s.slice(0,e.start)+e.text+s.slice(e.end);s=`${[`var __eveStepRegistrySym = Symbol.for("@workflow/core//registeredSteps");`,`if (!globalThis[__eveStepRegistrySym]) globalThis[__eveStepRegistrySym] = new Map();`,`var __eveStepRegistry = globalThis[__eveStepRegistrySym];`].join(`
3
- `)}\n${s}`;let c=[...r,...i];return c.length>0&&(s=`${s}\n\n${c.join(`
4
- `)}\n`),{code:s}}function walkNode(e,t){if(t(e)){if(Array.isArray(e.body))for(let n of e.body)walkNode(n,t);else e.body&&typeof e.body==`object`&&`type`in e.body&&walkNode(e.body,t);if(e.declarations)for(let n of e.declarations)walkNode(n,t);if(e.init&&walkNode(e.init,t),e.expression&&walkNode(e.expression,t),e.declaration&&walkNode(e.declaration,t),e.argument&&walkNode(e.argument,t),e.arguments)for(let n of e.arguments)walkNode(n,t);if(e.properties)for(let n of e.properties)walkNode(n,t),n.value&&typeof n.value==`object`&&`type`in n.value&&walkNode(n.value,t);e.left&&walkNode(e.left,t),e.right&&walkNode(e.right,t)}}function findProperty(e,t){return e.properties?.find(e=>e.type===`Property`&&!e.computed&&e.key?.type===`Identifier`&&e.key.name===t)}function escapeForRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function splitParamsTopLevel(e){let t=[],n=0,r=0;for(let i=0;i<e.length;i++){let a=e[i];a===`<`||a===`(`||a===`[`||a===`{`?n++:a===`>`||a===`)`||a===`]`||a===`}`?n--:a===`,`&&n===0&&(t.push(e.slice(r,i)),r=i+1)}return t.push(e.slice(r)),t}function extractParamBindingName(e){let t=e.trim(),n=0;for(let e=0;e<t.length;e++){let r=t[e];if(r===`<`||r===`(`||r===`[`||r===`{`)n++;else if(r===`>`||r===`)`||r===`]`||r===`}`)n--;else if(n===0&&(r===`:`||r===`=`))return t.slice(0,e).trim()}return t}function extractExecuteParamNames(e){if(!e)return new Set;let t=new Set;for(let n of splitParamsTopLevel(e)){let e=extractParamBindingName(n);e&&t.add(e)}return t}export{transformDynamicToolExecute as transformDynamicToolAwait,transformDynamicToolExecute};
1
+ import{parseWithNitroRolldownAst}from"#internal/bundler/nitro-rolldown.js";import{collectReferencedIdentifierNames}from"#internal/workflow-bundle/dynamic-tool-ast-references.js";let transformCounter=0;async function transformDynamicToolExecute(e,t){if(!t.includes(`defineDynamic`)||!t.includes(`events`)||!t.includes(`execute`))return null;let n=findDynamicToolHandlers(t,await parseSource(e,t));return n.every(e=>e.executes.length===0)?null:applyTransform(t,n)}async function parseSource(t,n){return await parseWithNitroRolldownAst(t,n)}function findDynamicToolHandlers(e,t){let n=[];return walkNode(t,t=>{if(t.type===`CallExpression`&&t.callee?.type===`Identifier`&&t.callee.name===`defineDynamic`&&t.arguments?.length===1){let r=t.arguments[0];if(r.type===`ObjectExpression`){let t=findProperty(r,`events`);t?.value&&t.value.type===`ObjectExpression`&&collectHandlers(e,t.value,n)}return!1}return!0}),n}function collectHandlers(e,t,n){for(let r of t.properties??[]){if(r.type!==`Property`)continue;let t=r.value;if(!t||t.type!==`ArrowFunctionExpression`&&t.type!==`FunctionExpression`)continue;let i=t.body;if(!i)continue;let a=findBlockBodyStart(i);if(a===null)continue;let o=extractParamNames(t),s=collectScopeVarDeclarations(i),c=findExecuteFunctions(e,i);c.length>0&&n.push({handlerNode:t,bodyStart:a,scopeVars:s,paramNames:o,executes:c})}}function findBlockBodyStart(e){return e.type===`BlockStatement`&&e.start!==void 0?e.start:typeof e.body==`object`&&!Array.isArray(e.body)&&e.body?.type===`BlockStatement`&&e.body.start!==void 0?e.body.start:null}function extractParamNames(e){let t=[];for(let n of e.params??[])n.type===`Identifier`&&n.name&&t.push(n.name);return t}function collectScopeVarDeclarations(e){let t=[];return collectVarsRecursive(e,t),t}function collectVarsRecursive(e,t){if(!e||e.type===`FunctionExpression`||e.type===`ArrowFunctionExpression`||e.type===`FunctionDeclaration`)return;if(e.type===`VariableDeclaration`)for(let n of e.declarations??[])collectDeclaredNames(n,t);e.type===`ForStatement`&&e.init&&collectVarsRecursive(e.init,t);let n=e;if((e.type===`ForInStatement`||e.type===`ForOfStatement`)&&e.left&&collectVarsRecursive(e.left,t),Array.isArray(e.body))for(let n of e.body)collectVarsRecursive(n,t);else e.body&&typeof e.body==`object`&&`type`in e.body&&collectVarsRecursive(e.body,t);if(e.declarations)for(let n of e.declarations)collectVarsRecursive(n,t);if(e.expression&&collectVarsRecursive(e.expression,t),Array.isArray(n.consequent))for(let e of n.consequent)collectVarsRecursive(e,t);else n.consequent&&collectVarsRecursive(n.consequent,t);if(n.alternate&&collectVarsRecursive(n.alternate,t),n.block&&collectVarsRecursive(n.block,t),n.handler&&collectVarsRecursive(n.handler,t),n.finalizer&&collectVarsRecursive(n.finalizer,t),n.cases&&Array.isArray(n.cases))for(let e of n.cases)collectVarsRecursive(e,t)}function collectDeclaredNames(e,t){e.type===`VariableDeclarator`&&collectPatternNames(e.id,t)}function collectPatternNames(e,t){if(e){if(e.type===`Identifier`&&e.name){t.push(e.name);return}if(e.type===`ObjectPattern`)for(let n of e.properties??[])n.type===`Property`?collectPatternNames(n.value,t):n.type===`RestElement`&&collectPatternNames(n.argument,t);if(e.type===`ArrayPattern`)for(let n of e.elements??[])n&&collectPatternNames(n,t)}}function findExecuteFunctions(e,t){let n=[];return walkForExecuteProps(e,t,n,[]),n}function walkForExecuteProps(e,t,r,i){if(!t)return;if(t.type===`FunctionExpression`||t.type===`ArrowFunctionExpression`||t.type===`FunctionDeclaration`){let n=extractParamNames(t),a=t.body;if(!a)return;let o=collectScopeVarDeclarations(a),s=[...i,{params:n,vars:o}];a.type,walkForExecuteProps(e,a,r,s);return}if(t.type===`CallExpression`&&t.callee?.type===`Identifier`&&t.callee.name===`defineTool`&&t.arguments?.length===1&&t.arguments[0].type===`ObjectExpression`){let a=t.arguments[0];for(let t of a.properties??[])if(t.type===`Property`&&!t.computed&&t.key?.type===`Identifier`&&t.key.name===`execute`&&t.start!==void 0&&t.end!==void 0){let a=t.value;if(!a||a.start===void 0||a.end===void 0)continue;let o=a.type===`FunctionExpression`||a.type===`ArrowFunctionExpression`,s=t.method===!0;if(o||s){let o=extractFnParams(e,a),s=extractFnBody(e,a),c=a.body,l=a.async===!0;c&&r.push({propStart:t.start,propEnd:t.end,fnSource:e.slice(a.start,a.end),isAsync:l,params:o,body:s,bodyNode:c,hoistedName:`__eve_dynamic_exec_${transformCounter++}`,nestedScopes:i})}}return}let walk=t=>walkForExecuteProps(e,t,r,i);if(Array.isArray(t.body))for(let e of t.body)walk(e);else t.body&&typeof t.body==`object`&&`type`in t.body&&walk(t.body);if(t.properties)for(let e of t.properties)e.value&&typeof e.value==`object`&&`type`in e.value&&walk(e.value);if(t.callee&&walk(t.callee),t.arguments)for(let e of t.arguments)walk(e);if(t.expression&&walk(t.expression),t.argument&&walk(t.argument),t.init&&walk(t.init),t.left&&walk(t.left),t.right&&walk(t.right),t.declarations)for(let e of t.declarations)walk(e);let a=t;if(Array.isArray(a.consequent))for(let e of a.consequent)walk(e);else a.consequent&&walk(a.consequent);if(a.alternate&&walk(a.alternate),a.block&&walk(a.block),a.handler&&walk(a.handler),a.finalizer&&walk(a.finalizer),a.cases&&Array.isArray(a.cases))for(let e of a.cases)walk(e)}function extractFnParams(e,t){if(!t.params||t.params.length===0)return``;let n=t.params[0],r=t.params[t.params.length-1];return n.start===void 0||r.end===void 0?``:e.slice(n.start,r.end)}function extractFnBody(e,t){let n=t.body;if(!n||n.start===void 0||n.end===void 0)return`{}`;let r=e.slice(n.start,n.end);return t.type===`ArrowFunctionExpression`&&n.type!==`BlockStatement`?`{ return ${r}; }`:r}function applyTransform(e,n){let r=[],i=[],a=[],o=[];for(let e of n)for(let n of e.executes){let s=[...e.paramNames,...e.scopeVars,...n.nestedScopes.flatMap(e=>[...e.params,...e.vars])],c=new Set,l=[];for(let e=s.length-1;e>=0;e--)c.has(s[e])||(c.add(s[e]),l.unshift(s[e]));let u=collectReferencedIdentifierNames(n.bodyNode),d=extractExecuteParamNames(n.params),f=l.filter(e=>!d.has(e)&&u.has(e)),p=f.length>0?`{ ${f.join(`, `)} }`:`{}`,m=n.isAsync?`async `:``,h=f.length>0?`const ${p} = __vars;\n `:``,g=n.params,_=g?`__vars, ${g}`:`__vars`,v=n.body.slice(1,-1).trim(),y=`eve:dynamic-tool//${n.hoistedName}`;i.push(`${m}function ${n.hoistedName}(${_}) {\n ${h}${v}\n}`),a.push(`${n.hoistedName}.stepId = ${JSON.stringify(y)};`),a.push(`__eveStepRegistry.set(${JSON.stringify(y)}, ${n.hoistedName});`),o.push(n.hoistedName);let b=g||``,x=g?splitParamsTopLevel(g).map(e=>extractParamBindingName(e)).join(`, `):``,S=x?`${p}, ${x}`:p,C=n.isAsync?`async `:``,w=n.isAsync?`await `:``;r.push({start:n.propStart,end:n.propEnd,text:[`execute: ${C}(${b}) => ${w}${n.hoistedName}(${S})`,`__executeStepFn: ${n.hoistedName}`,`__closureVars: ${p}`].join(`,
2
+ `)})}let s=[...r].sort((e,t)=>t.start-e.start),c=e;for(let e of s)c=c.slice(0,e.start)+e.text+c.slice(e.end);c=`${[`var __eveStepRegistrySym = Symbol.for("@workflow/core//registeredSteps");`,`if (!globalThis[__eveStepRegistrySym]) globalThis[__eveStepRegistrySym] = new Map();`,`var __eveStepRegistry = globalThis[__eveStepRegistrySym];`].join(`
3
+ `)}\n${c}`;let l=[...i,...a];return l.length>0&&(c=`${c}\n\n${l.join(`
4
+ `)}\n`),{code:c}}function walkNode(e,t){if(t(e)){if(Array.isArray(e.body))for(let n of e.body)walkNode(n,t);else e.body&&typeof e.body==`object`&&`type`in e.body&&walkNode(e.body,t);if(e.declarations)for(let n of e.declarations)walkNode(n,t);if(e.init&&walkNode(e.init,t),e.expression&&walkNode(e.expression,t),e.declaration&&walkNode(e.declaration,t),e.argument&&walkNode(e.argument,t),e.arguments)for(let n of e.arguments)walkNode(n,t);if(e.properties)for(let n of e.properties)walkNode(n,t),n.value&&typeof n.value==`object`&&`type`in n.value&&walkNode(n.value,t);e.left&&walkNode(e.left,t),e.right&&walkNode(e.right,t)}}function findProperty(e,t){return e.properties?.find(e=>e.type===`Property`&&!e.computed&&e.key?.type===`Identifier`&&e.key.name===t)}function splitParamsTopLevel(e){let t=[],n=0,r=0;for(let i=0;i<e.length;i++){let a=e[i];a===`<`||a===`(`||a===`[`||a===`{`?n++:a===`>`||a===`)`||a===`]`||a===`}`?n--:a===`,`&&n===0&&(t.push(e.slice(r,i)),r=i+1)}return t.push(e.slice(r)),t}function extractParamBindingName(e){let t=e.trim(),n=0;for(let e=0;e<t.length;e++){let r=t[e];if(r===`<`||r===`(`||r===`[`||r===`{`)n++;else if(r===`>`||r===`)`||r===`]`||r===`}`)n--;else if(n===0&&(r===`:`||r===`=`))return t.slice(0,e).trim()}return t}function extractExecuteParamNames(e){if(!e)return new Set;let t=new Set;for(let n of splitParamsTopLevel(e)){let e=extractParamBindingName(n);e&&t.add(e)}return t}export{transformDynamicToolExecute as transformDynamicToolAwait,transformDynamicToolExecute};
@@ -7,8 +7,16 @@ export declare const WORKFLOW_STEP_EXTERNAL_PACKAGES: readonly ["@mongodb-js/zst
7
7
  export declare const WORKFLOW_BUILDER_DEFERRED_PACKAGES: readonly ["@chat-adapter/slack", "chat"];
8
8
  /**
9
9
  * Builds the environment block every generated Vercel workflow function needs.
10
+ *
11
+ * When the build input carries the agent's resolved public route prefix, it
12
+ * is baked into the function environment under
13
+ * {@link EVE_PUBLIC_ROUTE_PREFIX_ENV} so callback-URL minting inside the
14
+ * deployed workflow functions knows the agent's public mount.
10
15
  */
11
- export declare function createWorkflowFunctionEnvironment(environment?: unknown): Record<string, unknown>;
16
+ export declare function createWorkflowFunctionEnvironment(input?: {
17
+ environment?: unknown;
18
+ publicRoutePrefix?: string;
19
+ }): Record<string, unknown>;
12
20
  /**
13
21
  * Creates an empty staging directory for one emitted Vercel function.
14
22
  */
@@ -50,6 +58,7 @@ export declare function normalizeEveVercelFunctionOutput(outputDir: string, opti
50
58
  export declare function emitBundledWorkflowFunctionDirectory(input: {
51
59
  bundlePath: string;
52
60
  pluginPaths?: readonly string[];
61
+ publicRoutePrefix?: string;
53
62
  targetPath: string;
54
63
  }): Promise<void>;
55
64
  /**
@@ -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{buildSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{EVE_SHARED_SERVER_FUNCTION_PATH,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.WORKFLOW_PRECONDITION_GUARD=`1`,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&&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({pluginPaths:e.pluginPaths??[],targetPath:e.targetPath}),i=join(dirname(e.bundlePath),`__eve_workflow_function_entry.js`),a=await buildSingleRolldownChunk(`Vercel workflow function for "${e.bundlePath}"`,{cwd:dirname(e.bundlePath),input:i,platform:`node`,plugins:[createVirtualModulePlugin({id:i,moduleType:`js`,source:createWorkflowFunctionEntrypointSource({bundlePath:e.bundlePath,pluginModulePaths:n})})],output:{comments:!1,format:`cjs`,sourcemap:!1}});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=await buildSingleRolldownChunk(`workflow plugin for "${t}"`,{input:t,platform:`node`,output:{comments:!1,format:`esm`,sourcemap:!1}}),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{EVE_PUBLIC_ROUTE_PREFIX_ENV,normalizePublicRoutePrefix}from"#shared/public-route-prefix.js";import{cp,mkdir,readFile,readdir,realpath,rename,rm,symlink,writeFile}from"node:fs/promises";import{buildSingleRolldownChunk}from"#internal/bundler/nitro-rolldown.js";import{EVE_SHARED_SERVER_FUNCTION_PATH,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={};isRecord(e.environment)&&Object.assign(t,e.environment);let n=normalizePublicRoutePrefix(e.publicRoutePrefix);return n!==void 0&&(t[EVE_PUBLIC_ROUTE_PREFIX_ENV]=n),t.WORKFLOW_PRECONDITION_GUARD=`1`,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&&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),a;try{a=await realpath(n)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}let o=`${i}.eve-staging`;return await mkdir(dirname(i),{recursive:!0}),await rm(o,{force:!0,recursive:!0}),await cp(a,o,{dereference:!0,recursive:!0}),await rm(i,{force:!0,recursive:!0}),await rename(o,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({pluginPaths:e.pluginPaths??[],targetPath:e.targetPath}),i=join(dirname(e.bundlePath),`__eve_workflow_function_entry.js`),a=await buildSingleRolldownChunk(`Vercel workflow function for "${e.bundlePath}"`,{cwd:dirname(e.bundlePath),input:i,platform:`node`,plugins:[createVirtualModulePlugin({id:i,moduleType:`js`,source:createWorkflowFunctionEntrypointSource({bundlePath:e.bundlePath,pluginModulePaths:n})})],output:{comments:!1,format:`cjs`,sourcemap:!1}});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({publicRoutePrefix:e.publicRoutePrefix}),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=await buildSingleRolldownChunk(`workflow plugin for "${t}"`,{input:t,platform:`node`,output:{comments:!1,format:`esm`,sourcemap:!1}}),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 +1 @@
1
- function connectionProtocols(e){return[e.mcp?`mcp`:null,e.openapi?`openapi`:null].filter(e=>e!==null)}const INTEGRATIONS=[{slug:`slack`,name:`Slack`,kind:`channel`,tagline:`Mention your agent in channels and DMs, with Connect-managed auth.`,surfaces:{scaffoldable:!0,gallery:!0}},{slug:`discord`,name:`Discord`,kind:`channel`,tagline:`Run your agent as a Discord bot across servers and threads.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`teams`,name:`Microsoft Teams`,kind:`channel`,tagline:`Bring your agent into Teams chats and channels.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`telegram`,name:`Telegram`,kind:`channel`,tagline:`Connect your agent to a Telegram bot for 1:1 and group chats.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`twilio`,name:`Twilio`,kind:`channel`,tagline:`Put your agent on a phone number: SMS and speech-transcribed calls.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`github`,name:`GitHub`,kind:`channel`,tagline:`Drive your agent from issues, pull requests, and comments.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`linear-agent`,name:`Linear Agent`,kind:`channel`,tagline:`Delegate Linear issues and comments to your agent through Linear's Agent Sessions.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`eve`,name:`Web Chat`,kind:`channel`,tagline:`Embed a first-party web chat UI backed by your agent.`,surfaces:{scaffoldable:!0,gallery:!0}},{slug:`chat-sdk-gchat`,name:`Google Chat`,kind:`channel`,tagline:`Google Chat spaces and DMs via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-whatsapp`,name:`WhatsApp`,kind:`channel`,tagline:`Customer messaging through WhatsApp Business Cloud via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-x`,name:`X`,kind:`channel`,tagline:`Public mentions and DMs on X via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-messenger`,name:`Messenger`,kind:`channel`,tagline:`Facebook Messenger bots with templates, buttons, and reactions via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`agent-browser`,name:`agent-browser`,kind:`extension`,tagline:`Add browser automation tools backed by agent-browser to an eve agent.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`kernel`,name:`Kernel`,kind:`connection`,tagline:`Launch cloud browsers and automate web interactions through Kernel's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Kernel: launch and automate cloud browsers, run Playwright, and inspect replays.`,mcp:{url:`https://mcp.onkernel.com/mcp`}}},{slug:`browser-use`,name:`Browser Use`,kind:`connection`,tagline:`Run managed browser automation tasks through Browser Use's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Browser Use: run browser automation tasks, inspect sessions, and manage browser profiles.`,mcp:{url:`https://api.browser-use.com/v3/mcp`}}},{slug:`vercel`,name:`Vercel`,kind:`connection`,tagline:`Manage Vercel projects, deployments, and logs through Vercel's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Vercel: manage projects and deployments, inspect logs, and search documentation.`,mcp:{url:`https://mcp.vercel.com`}}},{slug:`linear`,name:`Linear`,kind:`connection`,tagline:`Issues, projects, cycles, and comments via Linear's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Linear workspace: issues, projects, cycles, and comments.`,mcp:{url:`https://mcp.linear.app/mcp`}}},{slug:`notion`,name:`Notion`,kind:`connection`,tagline:`Search and edit Notion pages and databases over MCP or OpenAPI.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Notion workspace: search and edit pages and databases.`,mcp:{url:`https://mcp.notion.com/mcp`},openapi:{spec:`https://developers.notion.com/openapi.json`,baseUrl:`https://api.notion.com`,headers:{"Notion-Version":`2022-06-28`}}}},{slug:`datadog`,name:`Datadog`,kind:`connection`,tagline:`Query metrics, monitors, and logs through Datadog's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Datadog: query metrics, monitors, logs, and incidents.`,mcp:{url:`https://mcp.datadoghq.com/api/mcp`}}},{slug:`honeycomb`,name:`Honeycomb`,kind:`connection`,tagline:`Explore traces and run queries through Honeycomb's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Honeycomb: explore traces, run queries, and inspect datasets.`,mcp:{url:`https://mcp.honeycomb.io/mcp`}}},{slug:`airtable`,name:`Airtable`,kind:`connection`,tagline:`Bases, tables, and records through Airtable's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Airtable: bases, tables, and records.`,mcp:{url:`https://mcp.airtable.com/mcp`}}},{slug:`bitly`,name:`Bitly`,kind:`connection`,tagline:`Shorten links, generate QR Codes, and track performance.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Bitly: shorten links, generate QR Codes, and track link performance.`,mcp:{url:`https://api-ssl.bitly.com/v4/mcp`}}},{slug:`brex`,name:`Brex`,kind:`connection`,tagline:`Expenses, cards, and cash through Brex's finance automation.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Brex: expenses, cards, budgets, and cash.`,mcp:{url:`https://api.brex.com/mcp`}}},{slug:`candid`,name:`Candid`,kind:`connection`,tagline:`Research nonprofits and funders using Candid's data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Candid: research nonprofits, funders, and grants.`,mcp:{url:`https://mcp.candid.org/mcp`}}},{slug:`clickhouse`,name:`ClickHouse`,kind:`connection`,tagline:`Query and explore your ClickHouse Cloud data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`ClickHouse Cloud: query and explore databases and tables.`,mcp:{url:`https://mcp.clickhouse.cloud/mcp`}}},{slug:`cloudinary`,name:`Cloudinary`,kind:`connection`,tagline:`Manage, transform, and deliver your images and videos.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Cloudinary: manage, transform, and deliver image and video assets.`,mcp:{url:`https://asset-management.mcp.cloudinary.com/sse`}}},{slug:`coda`,name:`Coda`,kind:`connection`,tagline:`Create, search, and update docs and tables.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Coda: create, search, and update docs and tables.`,mcp:{url:`https://coda.io/apis/mcp`}}},{slug:`egnyte`,name:`Egnyte`,kind:`connection`,tagline:`Securely access and analyze Egnyte content.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Egnyte: search, access, and analyze governed content.`,mcp:{url:`https://mcp-server.egnyte.com/mcp`}}},{slug:`embat`,name:`Embat`,kind:`connection`,tagline:`Ask Embat about cash, debt, payments, and accounting.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Embat: cash, debt, payments, and accounting.`,mcp:{url:`https://tellme.embat.io/mcp`}}},{slug:`hugging-face`,name:`Hugging Face`,kind:`connection`,tagline:`Access the Hugging Face Hub and thousands of Gradio apps.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Hugging Face: models, datasets, Spaces, and Gradio apps on the Hub.`,mcp:{url:`https://huggingface.co/mcp?login&gradio=none`}}},{slug:`local-falcon`,name:`Local Falcon`,kind:`connection`,tagline:`AI visibility and local search intelligence.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Local Falcon: local search rankings and AI visibility reports.`,mcp:{url:`https://mcp.localfalcon.com`}}},{slug:`make`,name:`Make`,kind:`connection`,tagline:`Run Make scenarios and manage your Make account.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Make: run scenarios and manage automations.`,mcp:{url:`https://mcp.make.com`}}},{slug:`manufact`,name:`Manufact`,kind:`connection`,tagline:`Deploy and monitor MCP servers with Manufact.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Manufact: deploy and monitor MCP servers.`,mcp:{url:`https://mcp.manufact.com/mcp`}}},{slug:`mem0`,name:`Mem0`,kind:`connection`,tagline:`Persistent memory for AI agents and assistants.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Mem0: store and retrieve persistent agent memory.`,mcp:{url:`https://mcp.mem0.ai/mcp`}}},{slug:`miro`,name:`Miro`,kind:`connection`,tagline:`Access and create content on Miro boards.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Miro: read and create content on boards.`,mcp:{url:`https://mcp.miro.com/`}}},{slug:`mixpanel`,name:`Mixpanel`,kind:`connection`,tagline:`Analyze, query, and manage your Mixpanel data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Mixpanel: analyze, query, and manage analytics data.`,mcp:{url:`https://mcp.mixpanel.com/mcp`}}},{slug:`netlify`,name:`Netlify`,kind:`connection`,tagline:`Create, deploy, manage, and secure websites on Netlify.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Netlify: create, deploy, manage, and secure sites.`,mcp:{url:`https://netlify-mcp.netlify.app/mcp`}}},{slug:`oreilly`,name:`O'Reilly`,kind:`connection`,tagline:`Discover O'Reilly's expert learning content.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`O'Reilly: search books, courses, and learning content.`,mcp:{url:`https://api.oreilly.com/api/content-discovery/v1/mcp/`}}},{slug:`planetscale`,name:`PlanetScale`,kind:`connection`,tagline:`Authenticated access to your PlanetScale Postgres and MySQL databases.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`PlanetScale: query Postgres and MySQL databases.`,mcp:{url:`https://mcp.pscale.dev/mcp/planetscale`}}},{slug:`posthog`,name:`PostHog`,kind:`connection`,tagline:`Query, analyze, and manage your PostHog insights.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`PostHog: insights, events, and feature flags.`,mcp:{url:`https://mcp.posthog.com/mcp`}}},{slug:`postman`,name:`Postman`,kind:`connection`,tagline:`Give API context to your coding agents with Postman.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Postman: APIs, collections, and workspaces.`,mcp:{url:`https://mcp.postman.com/minimal`}}},{slug:`razorpay`,name:`Razorpay`,kind:`connection`,tagline:`Razorpay payments, settlements, and dashboard data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Razorpay: payments, settlements, and dashboard data.`,mcp:{url:`https://mcp.razorpay.com/mcp`}}},{slug:`sentry`,name:`Sentry`,kind:`connection`,tagline:`Search, query, and debug errors intelligently.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Sentry: search, query, and debug errors and issues.`,mcp:{url:`https://mcp.sentry.dev/mcp`}}},{slug:`similarweb`,name:`Similarweb`,kind:`connection`,tagline:`Real-time web, mobile app, and market data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Similarweb: web traffic, app, and market intelligence data.`,mcp:{url:`https://mcp.similarweb.com`}}},{slug:`stripe`,name:`Stripe`,kind:`connection`,tagline:`Payment processing and financial infrastructure tools.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Stripe: payments, customers, billing, and financial infrastructure.`,mcp:{url:`https://mcp.stripe.com`}}},{slug:`supabase`,name:`Supabase`,kind:`connection`,tagline:`Manage databases, authentication, and storage.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Supabase: databases, authentication, and storage.`,mcp:{url:`https://mcp.supabase.com/mcp`}}},{slug:`ticket-tailor`,name:`Ticket Tailor`,kind:`connection`,tagline:`Manage tickets, orders, and events with Ticket Tailor.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Ticket Tailor: events, tickets, and orders.`,mcp:{url:`https://mcp.tickettailor.ai/mcp`}}},{slug:`ticktick`,name:`TickTick`,kind:`connection`,tagline:`Search, create, and manage your tasks and habits in TickTick.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`TickTick: tasks, habits, and lists.`,mcp:{url:`https://mcp.ticktick.com`}}},{slug:`todoist`,name:`Todoist`,kind:`connection`,tagline:`Search, complete, and manage your tasks in Todoist.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Todoist: search, complete, and manage tasks.`,mcp:{url:`https://ai.todoist.net/mcp`}}},{slug:`webflow`,name:`Webflow`,kind:`connection`,tagline:`Manage Webflow CMS, pages, assets, and sites.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Webflow: CMS items, pages, assets, and sites.`,mcp:{url:`https://mcp.webflow.com/mcp`}}},{slug:`wix`,name:`Wix`,kind:`connection`,tagline:`Manage and build sites and apps on Wix.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Wix: manage and build sites and apps.`,mcp:{url:`https://mcp.wix.com/mcp`}}},{slug:`zapier`,name:`Zapier`,kind:`connection`,tagline:`Automate workflows across thousands of apps.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Zapier: run and manage automations across apps.`,mcp:{url:`https://mcp.zapier.com/api/v1/connect`}}},{slug:`zomato`,name:`Zomato`,kind:`connection`,tagline:`Online food ordering and delivery through Zomato.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Zomato: food ordering and delivery.`,mcp:{url:`https://mcp-server.zomato.com/mcp`}}}];new Map(INTEGRATIONS.map(e=>[e.slug,e]));function integrationsByKind(t){return INTEGRATIONS.filter(e=>e.kind===t)}function connectionEntries(){return integrationsByKind(`connection`)}function channelEntries(){return integrationsByKind(`channel`)}export{channelEntries,connectionEntries,connectionProtocols};
1
+ function connectionProtocols(e){return[e.mcp?`mcp`:null,e.openapi?`openapi`:null].filter(e=>e!==null)}const INTEGRATIONS=[{slug:`slack`,name:`Slack`,kind:`channel`,tagline:`Mention your agent in channels and DMs, with Connect-managed auth.`,surfaces:{scaffoldable:!0,gallery:!0}},{slug:`discord`,name:`Discord`,kind:`channel`,tagline:`Run your agent as a Discord bot across servers and threads.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`teams`,name:`Microsoft Teams`,kind:`channel`,tagline:`Bring your agent into Teams chats and channels.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`telegram`,name:`Telegram`,kind:`channel`,tagline:`Connect your agent to a Telegram bot for 1:1 and group chats.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`twilio`,name:`Twilio`,kind:`channel`,tagline:`Put your agent on a phone number: SMS and speech-transcribed calls.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`github`,name:`GitHub`,kind:`channel`,tagline:`Drive your agent from issues, pull requests, and comments.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`linear-agent`,name:`Linear Agent`,kind:`channel`,tagline:`Delegate Linear issues and comments to your agent through Linear's Agent Sessions.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`eve`,name:`Web Chat`,kind:`channel`,tagline:`Embed a first-party web chat UI backed by your agent.`,surfaces:{scaffoldable:!0,gallery:!0}},{slug:`chat-sdk-gchat`,name:`Google Chat`,kind:`channel`,tagline:`Google Chat spaces and DMs via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-whatsapp`,name:`WhatsApp`,kind:`channel`,tagline:`Customer messaging through WhatsApp Business Cloud via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-x`,name:`X`,kind:`channel`,tagline:`Public mentions and DMs on X via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-messenger`,name:`Messenger`,kind:`channel`,tagline:`Facebook Messenger bots with templates, buttons, and reactions via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-zernio`,name:`Zernio`,kind:`channel`,tagline:`Reach seven social and messaging platforms through one Zernio integration.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-velt`,name:`Velt`,kind:`channel`,tagline:`Add agents to anchored comments across documents, canvases, PDFs, and video.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-sendblue`,name:`Sendblue`,kind:`channel`,tagline:`Send and receive iMessage, SMS, and RCS through Sendblue.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-novu`,name:`Novu`,kind:`channel`,tagline:`Reach Slack, Teams, WhatsApp, Telegram, and email through Novu.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-liveblocks`,name:`Liveblocks`,kind:`channel`,tagline:`Bring your agent into Liveblocks comment threads, mentions, and reactions.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-linq`,name:`Linq`,kind:`channel`,tagline:`iMessage and SMS conversations, media, and tapbacks through Linq.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-kapso`,name:`Kapso`,kind:`channel`,tagline:`Managed WhatsApp conversations, media, buttons, and history through Kapso.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-photon`,name:`Photon`,kind:`channel`,tagline:`Cloud, self-hosted, and local iMessage messaging through Photon.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-dial`,name:`Dial`,kind:`channel`,tagline:`Give your agent a phone number for SMS, MMS, iMessage, and voice transcripts.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-agentphone`,name:`AgentPhone`,kind:`channel`,tagline:`SMS, MMS, iMessage, and voice conversations through AgentPhone.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-lark`,name:`Lark / Feishu`,kind:`channel`,tagline:`Lark and Feishu chats with native card streaming via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-beeper`,name:`Beeper`,kind:`channel`,tagline:`Matrix rooms and bridged messaging networks through Beeper.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`chat-sdk-resend`,name:`Resend`,kind:`channel`,tagline:`Send and receive threaded email through Resend via the Chat SDK.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`agent-browser`,name:`agent-browser`,kind:`extension`,tagline:`Add browser automation tools backed by agent-browser to an eve agent.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`browserbase`,name:`Browserbase`,kind:`extension`,tagline:`Search, fetch, and automate the web with Browserbase and Stagehand.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`github-tools`,name:`GitHub Tools`,kind:`extension`,tagline:`Add scoped GitHub tools with Vercel Connect authentication and approval rules.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`jetty`,name:`Jetty`,kind:`extension`,tagline:`Grade agent turns, compare experiments, and store durable evaluation trajectories.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`kernel`,name:`KERNEL`,kind:`extension`,tagline:`Let your eve agent use the Internet with KERNEL browser infra, o11y, and stealth. Integrated natively with Vercel Connect and AI Gateway.`,surfaces:{scaffoldable:!1,gallery:!0}},{slug:`browser-use`,name:`Browser Use`,kind:`connection`,tagline:`Run managed browser automation tasks through Browser Use's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Browser Use: run browser automation tasks, inspect sessions, and manage browser profiles.`,mcp:{url:`https://api.browser-use.com/v3/mcp`}}},{slug:`vercel`,name:`Vercel`,kind:`connection`,tagline:`Manage Vercel projects, deployments, and logs through Vercel's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Vercel: manage projects and deployments, inspect logs, and search documentation.`,mcp:{url:`https://mcp.vercel.com`}}},{slug:`linear`,name:`Linear`,kind:`connection`,tagline:`Issues, projects, cycles, and comments via Linear's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Linear workspace: issues, projects, cycles, and comments.`,mcp:{url:`https://mcp.linear.app/mcp`}}},{slug:`notion`,name:`Notion`,kind:`connection`,tagline:`Search and edit Notion pages and databases over MCP or OpenAPI.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Notion workspace: search and edit pages and databases.`,mcp:{url:`https://mcp.notion.com/mcp`},openapi:{spec:`https://developers.notion.com/openapi.json`,baseUrl:`https://api.notion.com`,headers:{"Notion-Version":`2022-06-28`}}}},{slug:`datadog`,name:`Datadog`,kind:`connection`,tagline:`Query metrics, monitors, and logs through Datadog's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Datadog: query metrics, monitors, logs, and incidents.`,mcp:{url:`https://mcp.datadoghq.com/api/mcp`}}},{slug:`honeycomb`,name:`Honeycomb`,kind:`connection`,tagline:`Explore traces and run queries through Honeycomb's MCP server.`,surfaces:{scaffoldable:!0,gallery:!0},connection:{description:`Honeycomb: explore traces, run queries, and inspect datasets.`,mcp:{url:`https://mcp.honeycomb.io/mcp`}}},{slug:`airtable`,name:`Airtable`,kind:`connection`,tagline:`Bases, tables, and records through Airtable's MCP server.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Airtable: bases, tables, and records.`,mcp:{url:`https://mcp.airtable.com/mcp`}}},{slug:`bitly`,name:`Bitly`,kind:`connection`,tagline:`Shorten links, generate QR Codes, and track performance.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Bitly: shorten links, generate QR Codes, and track link performance.`,mcp:{url:`https://api-ssl.bitly.com/v4/mcp`}}},{slug:`brex`,name:`Brex`,kind:`connection`,tagline:`Expenses, cards, and cash through Brex's finance automation.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Brex: expenses, cards, budgets, and cash.`,mcp:{url:`https://api.brex.com/mcp`}}},{slug:`candid`,name:`Candid`,kind:`connection`,tagline:`Research nonprofits and funders using Candid's data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Candid: research nonprofits, funders, and grants.`,mcp:{url:`https://mcp.candid.org/mcp`}}},{slug:`clickhouse`,name:`ClickHouse`,kind:`connection`,tagline:`Query and explore your ClickHouse Cloud data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`ClickHouse Cloud: query and explore databases and tables.`,mcp:{url:`https://mcp.clickhouse.cloud/mcp`}}},{slug:`cloudinary`,name:`Cloudinary`,kind:`connection`,tagline:`Manage, transform, and deliver your images and videos.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Cloudinary: manage, transform, and deliver image and video assets.`,mcp:{url:`https://asset-management.mcp.cloudinary.com/sse`}}},{slug:`coda`,name:`Coda`,kind:`connection`,tagline:`Create, search, and update docs and tables.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Coda: create, search, and update docs and tables.`,mcp:{url:`https://coda.io/apis/mcp`}}},{slug:`egnyte`,name:`Egnyte`,kind:`connection`,tagline:`Securely access and analyze Egnyte content.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Egnyte: search, access, and analyze governed content.`,mcp:{url:`https://mcp-server.egnyte.com/mcp`}}},{slug:`embat`,name:`Embat`,kind:`connection`,tagline:`Ask Embat about cash, debt, payments, and accounting.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Embat: cash, debt, payments, and accounting.`,mcp:{url:`https://tellme.embat.io/mcp`}}},{slug:`hugging-face`,name:`Hugging Face`,kind:`connection`,tagline:`Access the Hugging Face Hub and thousands of Gradio apps.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Hugging Face: models, datasets, Spaces, and Gradio apps on the Hub.`,mcp:{url:`https://huggingface.co/mcp?login&gradio=none`}}},{slug:`local-falcon`,name:`Local Falcon`,kind:`connection`,tagline:`AI visibility and local search intelligence.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Local Falcon: local search rankings and AI visibility reports.`,mcp:{url:`https://mcp.localfalcon.com`}}},{slug:`make`,name:`Make`,kind:`connection`,tagline:`Run Make scenarios and manage your Make account.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Make: run scenarios and manage automations.`,mcp:{url:`https://mcp.make.com`}}},{slug:`manufact`,name:`Manufact`,kind:`connection`,tagline:`Deploy and monitor MCP servers with Manufact.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Manufact: deploy and monitor MCP servers.`,mcp:{url:`https://mcp.manufact.com/mcp`}}},{slug:`mem0`,name:`Mem0`,kind:`connection`,tagline:`Persistent memory for AI agents and assistants.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Mem0: store and retrieve persistent agent memory.`,mcp:{url:`https://mcp.mem0.ai/mcp`}}},{slug:`miro`,name:`Miro`,kind:`connection`,tagline:`Access and create content on Miro boards.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Miro: read and create content on boards.`,mcp:{url:`https://mcp.miro.com/`}}},{slug:`mixpanel`,name:`Mixpanel`,kind:`connection`,tagline:`Analyze, query, and manage your Mixpanel data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Mixpanel: analyze, query, and manage analytics data.`,mcp:{url:`https://mcp.mixpanel.com/mcp`}}},{slug:`netlify`,name:`Netlify`,kind:`connection`,tagline:`Create, deploy, manage, and secure websites on Netlify.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Netlify: create, deploy, manage, and secure sites.`,mcp:{url:`https://netlify-mcp.netlify.app/mcp`}}},{slug:`oreilly`,name:`O'Reilly`,kind:`connection`,tagline:`Discover O'Reilly's expert learning content.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`O'Reilly: search books, courses, and learning content.`,mcp:{url:`https://api.oreilly.com/api/content-discovery/v1/mcp/`}}},{slug:`planetscale`,name:`PlanetScale`,kind:`connection`,tagline:`Authenticated access to your PlanetScale Postgres and MySQL databases.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`PlanetScale: query Postgres and MySQL databases.`,mcp:{url:`https://mcp.pscale.dev/mcp/planetscale`}}},{slug:`posthog`,name:`PostHog`,kind:`connection`,tagline:`Query, analyze, and manage your PostHog insights.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`PostHog: insights, events, and feature flags.`,mcp:{url:`https://mcp.posthog.com/mcp`}}},{slug:`postman`,name:`Postman`,kind:`connection`,tagline:`Give API context to your coding agents with Postman.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Postman: APIs, collections, and workspaces.`,mcp:{url:`https://mcp.postman.com/minimal`}}},{slug:`razorpay`,name:`Razorpay`,kind:`connection`,tagline:`Razorpay payments, settlements, and dashboard data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Razorpay: payments, settlements, and dashboard data.`,mcp:{url:`https://mcp.razorpay.com/mcp`}}},{slug:`sentry`,name:`Sentry`,kind:`connection`,tagline:`Search, query, and debug errors intelligently.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Sentry: search, query, and debug errors and issues.`,mcp:{url:`https://mcp.sentry.dev/mcp`}}},{slug:`similarweb`,name:`Similarweb`,kind:`connection`,tagline:`Real-time web, mobile app, and market data.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Similarweb: web traffic, app, and market intelligence data.`,mcp:{url:`https://mcp.similarweb.com`}}},{slug:`stripe`,name:`Stripe`,kind:`connection`,tagline:`Payment processing and financial infrastructure tools.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Stripe: payments, customers, billing, and financial infrastructure.`,mcp:{url:`https://mcp.stripe.com`}}},{slug:`supabase`,name:`Supabase`,kind:`connection`,tagline:`Manage databases, authentication, and storage.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Supabase: databases, authentication, and storage.`,mcp:{url:`https://mcp.supabase.com/mcp`}}},{slug:`ticket-tailor`,name:`Ticket Tailor`,kind:`connection`,tagline:`Manage tickets, orders, and events with Ticket Tailor.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Ticket Tailor: events, tickets, and orders.`,mcp:{url:`https://mcp.tickettailor.ai/mcp`}}},{slug:`ticktick`,name:`TickTick`,kind:`connection`,tagline:`Search, create, and manage your tasks and habits in TickTick.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`TickTick: tasks, habits, and lists.`,mcp:{url:`https://mcp.ticktick.com`}}},{slug:`todoist`,name:`Todoist`,kind:`connection`,tagline:`Search, complete, and manage your tasks in Todoist.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Todoist: search, complete, and manage tasks.`,mcp:{url:`https://ai.todoist.net/mcp`}}},{slug:`webflow`,name:`Webflow`,kind:`connection`,tagline:`Manage Webflow CMS, pages, assets, and sites.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Webflow: CMS items, pages, assets, and sites.`,mcp:{url:`https://mcp.webflow.com/mcp`}}},{slug:`wix`,name:`Wix`,kind:`connection`,tagline:`Manage and build sites and apps on Wix.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Wix: manage and build sites and apps.`,mcp:{url:`https://mcp.wix.com/mcp`}}},{slug:`zapier`,name:`Zapier`,kind:`connection`,tagline:`Automate workflows across thousands of apps.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Zapier: run and manage automations across apps.`,mcp:{url:`https://mcp.zapier.com/api/v1/connect`}}},{slug:`zomato`,name:`Zomato`,kind:`connection`,tagline:`Online food ordering and delivery through Zomato.`,surfaces:{scaffoldable:!1,gallery:!0},connection:{description:`Zomato: food ordering and delivery.`,mcp:{url:`https://mcp-server.zomato.com/mcp`}}}];new Map(INTEGRATIONS.map(e=>[e.slug,e]));function integrationsByKind(t){return INTEGRATIONS.filter(e=>e.kind===t)}function connectionEntries(){return integrationsByKind(`connection`)}function channelEntries(){return integrationsByKind(`channel`)}export{channelEntries,connectionEntries,connectionProtocols};
@@ -1,2 +1,3 @@
1
1
  import{createLogger,logError}from"#internal/logging.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_INFO_ROUTE_PATH}from"#protocol/routes.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{readAgentInfoRouteResponse,readRouteAgent}from"#internal/nitro/routes/channel-route-context.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`eve.channel`);function defaultEveAuth(e){return e.eve.caller}function eveChannel(e){let n=mergeUploadPolicy(e.uploadPolicy);return defineChannel({cors:normalizeEveCors(e.cors),routes:[GET(EVE_INFO_ROUTE_PATH,async(t,n)=>{let r=await routeAuth(t,e.auth);if(r instanceof Response)return r;let i=readAgentInfoRouteResponse(n);return i===void 0?Response.json({error:`Agent info route requires internal channel dispatch context.`,ok:!1},{status:500}):await i()}),POST(`/eve/v1/session`,async(t,{send:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=i,o;try{o=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof o!=`object`||!o)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let s=parseCreateBody(o);if(s instanceof Response)return s;let c=checkUploadPolicy(s,n);if(c!==null)return c;let l=await resolveOnMessage({auth:a,config:e,message:s.message,request:t});if(l instanceof Response)return l;if(!l.dispatch)return droppedMessageResponse();let u=`eve:${crypto.randomUUID()}`,d=await r(createSendPayload(s,mergeContext(s.context,l.context)),{auth:l.auth,callback:s.callback,continuationToken:u,mode:s.mode});return Response.json({continuationToken:d.continuationToken,ok:!0,sessionId:d.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:d.id},status:202})}),POST(`/eve/v1/session/:sessionId`,async(t,{send:r,getSession:i,params:a})=>{let o=await routeAuth(t,e.auth);if(o instanceof Response)return o;let s=o,c=a.sessionId;if(!c)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(c)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let l;try{l=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof l!=`object`||!l)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let u=parseContinueBody(l);if(u instanceof Response)return u;let d=checkUploadPolicy(u,n);if(d!==null)return d;let f=u.context,p=s;if(u.message!==void 0){let n=await resolveOnMessage({auth:s,config:e,message:u.message,request:t,sessionId:c});if(n instanceof Response)return n;if(!n.dispatch)return droppedMessageResponse();f=mergeContext(u.context,n.context),p=n.auth}let m=await r({inputResponses:u.inputResponses,message:u.message,context:f,outputSchema:u.outputSchema},{auth:p,continuationToken:u.continuationToken});return Response.json({ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:200})}),POST(EVE_CANCEL_TURN_ROUTE_PATTERN,async(n,r)=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=r.params.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=await parseCancelTurnBody(n);if(o instanceof Response)return o;let s;try{let e=readRouteAgent(r);if(e===void 0)throw Error(`Missing route agent.`);s=await e.cancelTurn({sessionId:a,turnId:o.turnId})}catch(e){let n=logError(log,`cancel-turn request failed`,e,{sessionId:a});return Response.json({error:`Failed to cancel the turn.`,errorId:n,ok:!1},{status:500})}return Response.json({ok:!0,sessionId:a,status:s.status},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:a},status:202})}),GET(`/eve/v1/session/:sessionId/stream`,async(t,{getSession:n,params:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let u=r.sessionId;if(!u)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let d=parseStartIndex(t);if(d instanceof Response)return d;try{let e=serializeAsNdjson(await n(u).getEventStream({startIndex:d}));return new Response(e,{headers:{"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:u,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}function normalizeEveCors(e){if(e===void 0||e===!1)return!1;if(e===!0)return!0;let t={};return e.origin!==void 0&&(t.origin=normalizeEveCorsOrigin(e.origin)),e.methods!==void 0&&(t.methods=e.methods),e.allowedHeaders!==void 0&&(t.allowHeaders=e.allowedHeaders),e.exposedHeaders!==void 0&&(t.exposeHeaders=e.exposedHeaders),e.credentials!==void 0&&(t.credentials=e.credentials),e.maxAge!==void 0&&(t.maxAge=e.maxAge),e.preflightStatus!==void 0&&(t.preflight={statusCode:e.preflightStatus}),t}function normalizeEveCorsOrigin(e){return e===`*`||e===`null`?e:typeof e==`string`?[e]:e}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({eve:e.sessionId===void 0?{caller:e.auth,request:e.request}:{caller:e.auth,request:e.request,sessionId:e.sessionId}},e.message)}catch(n){let r=logError(log,`onMessage handler failed`,n,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:r,ok:!1},{status:500})}return r==null?{dispatch:!1}:r.context===void 0?{auth:r.auth,dispatch:!0}:{auth:r.auth,context:r.context,dispatch:!0}}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}function droppedMessageResponse(){return new Response(null,{headers:{"cache-control":`no-store`},status:204})}function parseCreateBody(e){let t=parseMessageField(e.message);if(t instanceof Response)return t;let n=parseClientContextField(e.clientContext);if(n instanceof Response)return n;let r=parseCallbackField(e.callback);if(r instanceof Response)return r;let i=parseModeField(e.mode);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,context:n,outputSchema:a}}function parseContinueBody(e){let t=typeof e.continuationToken==`string`&&e.continuationToken.length>0?e.continuationToken:void 0;if(t===void 0)return Response.json({error:`Missing or empty 'continuationToken' field.`,ok:!1},{status:400});let n=parseMessageField(e.message);if(n instanceof Response)return n;let r=parseInputResponses(e.inputResponses);if(r instanceof Response)return r;let i=parseClientContextField(e.clientContext);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:n===void 0&&r===void 0?Response.json({error:`Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.`,ok:!1},{status:400}):{message:n,continuationToken:t,inputResponses:r,context:i,outputSchema:a}}async function parseCancelTurnBody(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof n!=`object`||!n||Array.isArray(n))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let r=n.turnId;return r===void 0?{}:typeof r!=`string`||r.length===0?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):{turnId:r}}function createSendPayload(e,t=e.context){if(t===void 0&&e.outputSchema===void 0)return e.message;let n={message:e.message};return t!==void 0&&(n.context=t),e.outputSchema!==void 0&&(n.outputSchema=e.outputSchema),n}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseModeField(e){if(e!==void 0)return e===`conversation`||e===`task`?e:Response.json({error:`Expected 'mode' to be either 'conversation' or 'task'.`,ok:!1},{status:400})}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function mergeContext(e,t){return e===void 0?t:t===void 0?e:[...e,...t]}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?[toClientContextMessage(e)]:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e.map(e=>toClientContextMessage(e)):Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{let t=parseJsonObject(e);return[toClientContextMessage(JSON.stringify(t))]}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function toClientContextMessage(e){return`Client context:
2
- ${e}`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{defaultEveAuth,eveChannel};
2
+ ${e}`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({start(e){e.enqueue(t.encode(`
3
+ `))},transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{defaultEveAuth,eveChannel};
@@ -0,0 +1,18 @@
1
+ import type { UserContent } from "ai";
2
+ import type { LinearFetch } from "#public/channels/linear/api.js";
3
+ import { type LinearChannelCredentials } from "#public/channels/linear/auth.js";
4
+ /** One trusted Linear upload referenced by markdown image syntax. */
5
+ export interface LinearUploadImageReference {
6
+ readonly altText: string;
7
+ readonly end: number;
8
+ readonly start: number;
9
+ readonly url: URL;
10
+ }
11
+ /** Extracts markdown image references that target Linear's exact upload origin. */
12
+ export declare function extractLinearUploadImageReferences(markdown: string): readonly LinearUploadImageReference[];
13
+ /** Adds authenticated Linear upload images to otherwise text-only inbound content. */
14
+ export declare function attachLinearInboundImages(input: {
15
+ readonly content: UserContent;
16
+ readonly credentials?: LinearChannelCredentials;
17
+ readonly fetch?: LinearFetch;
18
+ }): Promise<UserContent>;
@@ -0,0 +1 @@
1
+ import{resolveLinearAccessToken}from"#public/channels/linear/auth.js";const MARKDOWN_IMAGE_PATTERN=/!\[([^\]\r\n]*)\]\(\s*(?:<([^>\r\n]+)>|([^\s)\r\n]+))(?:\s+(?:"[^"\r\n]*"|'[^'\r\n]*'|\([^)\r\n]*\)))?\s*\)/gu;function extractLinearUploadImageReferences(e){let n=[];for(let r of e.matchAll(MARKDOWN_IMAGE_PATTERN)){let e=r[2]??r[3],t=r.index;if(e===void 0||t===void 0)continue;let i=parseLinearUploadUrl(e);i!==null&&n.push({altText:r[1]??``,end:t+r[0].length,start:t,url:i})}return n}async function attachLinearInboundImages(t){if(typeof t.content!=`string`)return t.content;let n=extractLinearUploadImageReferences(t.content);if(n.length===0)return t.content;let r;try{r=await resolveLinearAccessToken(t.credentials?.accessToken)}catch{return t.content}let i=t.fetch??fetch,a=await Promise.all(n.map(e=>fetchLinearUploadImage(e.url,r,i)));return a.every(e=>e===null)?t.content:buildLinearImageContent(t.content,n,a)}function parseLinearUploadUrl(e){let t;try{t=new URL(e)}catch{return null}return t.origin!==`https://uploads.linear.app`||t.username!==``||t.password!==``?null:t}async function fetchLinearUploadImage(e,t,n){if(parseLinearUploadUrl(e.href)===null)return null;try{let r=await n(e.href,{credentials:`omit`,headers:{accept:`image/*`,authorization:`Bearer ${t}`},redirect:`manual`});if(!r.ok)return null;let i=readImageMediaType(r.headers.get(`content-type`));return i===null?null:{data:Buffer.from(await r.arrayBuffer()),mediaType:i,type:`file`}}catch{return null}}function readImageMediaType(e){let t=e?.split(`;`,1)[0]?.trim().toLowerCase();return t?.startsWith(`image/`)===!0&&t.length>6?t:null}function buildLinearImageContent(e,t,n){let r=0,i=``,a=[];for(let[o,s]of t.entries()){let t=n[o];t!=null&&(i+=e.slice(r,s.start),i+=s.altText,r=s.end,a.push(t))}return i+=e.slice(r),i.trim().length===0?a:[{text:i,type:`text`},...a]}export{attachLinearInboundImages,extractLinearUploadImageReferences};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,a={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:n}){let r=t.target,a=await resolveReceiveSession(r,e),o=readString(r.initialActivity);return o!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:a.id,content:{body:o,type:`thought`}}}),n(t.message,{auth:t.auth,continuationToken:linearContinuationToken(a.id),state:stateFromAgentSession(a)})},events:a})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);r!==null&&await e.send({context:[formatLinearContextBlock(t),...t.previousComments,...r.context??[]],message:messageFromLinearAgentSessionEvent(t)},{auth:r.auth,continuationToken:linearContinuationToken(t.agentSession.id),state:stateFromAgentSession(t.agentSession)})}async function resolveReceiveSession(e,t){if(hasString(e,`agentSessionId`))return{id:e.agentSessionId};if(hasString(e,`issueId`))return createLinearAgentSessionOnIssue({api:t.api,credentials:t.credentials,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls),issueId:e.issueId});if(hasString(e,`commentId`))return createLinearAgentSessionOnComment({api:t.api,credentials:t.credentials,commentId:e.commentId,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls)});throw Error(`linearChannel().receive requires target.agentSessionId, issueId, or commentId.`)}function stateFromAgentSession(e){return{agentSessionId:e.id,agentSessionUrl:e.url??null,commentId:e.commentId??null,issueId:e.issueId??e.issue?.id??null,issueIdentifier:e.issue?.identifier??null,issueTitle:e.issue?.title??null,issueUrl:e.issue?.url??null,organizationId:`organizationId`in e?e.organizationId??null:null,pendingToolCallMessage:null,sourceCommentId:e.sourceCommentId??null}}function initialLinearState(){return{agentSessionId:null,agentSessionUrl:null,commentId:null,issueId:null,issueIdentifier:null,issueTitle:null,issueUrl:null,organizationId:null,pendingToolCallMessage:null,sourceCommentId:null}}async function verifyInbound(e,t){try{return await verifyLinearRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`linear inbound verification failed`,{error:e}),null}}function hasString(e,t){return typeof e[t]==`string`&&e[t].length>0}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}function readExternalUrls(e){if(!Array.isArray(e))return;let n=e.filter(e=>isObject(e)&&typeof e.label==`string`&&typeof e.url==`string`);return n.length>0?n:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{linearChannel};
1
+ import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";import{attachLinearInboundImages}from"#public/channels/linear/inbound-images.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,a={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:n}){let r=t.target,a=await resolveReceiveSession(r,e),o=readString(r.initialActivity);return o!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:a.id,content:{body:o,type:`thought`}}}),n(t.message,{auth:t.auth,continuationToken:linearContinuationToken(a.id),state:stateFromAgentSession(a)})},events:a})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);if(r===null)return;let i=await attachLinearInboundImages({content:messageFromLinearAgentSessionEvent(t),credentials:e.config.credentials,fetch:e.config.api?.fetch});await e.send({context:[formatLinearContextBlock(t),...t.previousComments,...r.context??[]],message:i},{auth:r.auth,continuationToken:linearContinuationToken(t.agentSession.id),state:stateFromAgentSession(t.agentSession)})}async function resolveReceiveSession(e,t){if(hasString(e,`agentSessionId`))return{id:e.agentSessionId};if(hasString(e,`issueId`))return createLinearAgentSessionOnIssue({api:t.api,credentials:t.credentials,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls),issueId:e.issueId});if(hasString(e,`commentId`))return createLinearAgentSessionOnComment({api:t.api,credentials:t.credentials,commentId:e.commentId,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls)});throw Error(`linearChannel().receive requires target.agentSessionId, issueId, or commentId.`)}function stateFromAgentSession(e){return{agentSessionId:e.id,agentSessionUrl:e.url??null,commentId:e.commentId??null,issueId:e.issueId??e.issue?.id??null,issueIdentifier:e.issue?.identifier??null,issueTitle:e.issue?.title??null,issueUrl:e.issue?.url??null,organizationId:`organizationId`in e?e.organizationId??null:null,pendingToolCallMessage:null,sourceCommentId:e.sourceCommentId??null}}function initialLinearState(){return{agentSessionId:null,agentSessionUrl:null,commentId:null,issueId:null,issueIdentifier:null,issueTitle:null,issueUrl:null,organizationId:null,pendingToolCallMessage:null,sourceCommentId:null}}async function verifyInbound(e,t){try{return await verifyLinearRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`linear inbound verification failed`,{error:e}),null}}function hasString(e,t){return typeof e[t]==`string`&&e[t].length>0}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}function readExternalUrls(e){if(!Array.isArray(e))return;let n=e.filter(e=>isObject(e)&&typeof e.label==`string`&&typeof e.url==`string`);return n.length>0?n:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{linearChannel};
@@ -145,6 +145,13 @@ export interface SlackThreadMessage {
145
145
  readonly botId: string | undefined;
146
146
  readonly ts: string;
147
147
  readonly threadTs: string;
148
+ /**
149
+ * Whether this message was authored by the Slack app bound to the thread.
150
+ * Classification requires the binding to carry the app identity (bot user
151
+ * id or app id). Inbound event bindings do; bindings rebuilt from session
152
+ * state or interaction payloads currently do not and mark every message
153
+ * `false`.
154
+ */
148
155
  readonly isMe: boolean;
149
156
  readonly raw: Record<string, unknown>;
150
157
  }
@@ -157,6 +164,18 @@ export interface SlackThreadMessage {
157
164
  export interface SlackThread {
158
165
  /** Recently fetched thread messages. Populated by {@link refresh}. */
159
166
  readonly recentMessages: readonly SlackThreadMessage[];
167
+ /**
168
+ * Fetch the latest replies via {@link refresh} and return the unique
169
+ * human Slack user ids participating in this thread, ordered by first
170
+ * appearance. For a human-started thread, the first entry is the
171
+ * starting author. Bot messages and user-less system messages are
172
+ * excluded.
173
+ *
174
+ * Shares {@link refresh} semantics: it observes at most the first 50
175
+ * messages of the thread, and refresh failures are logged and swallowed,
176
+ * so the returned list may be empty or stale.
177
+ */
178
+ listParticipants(): Promise<readonly string[]>;
160
179
  /**
161
180
  * Post a reply to this thread.
162
181
  *
@@ -195,8 +214,9 @@ export interface SlackThread {
195
214
  startTyping(status?: string): Promise<void>;
196
215
  /**
197
216
  * Fetch the latest replies in this thread into {@link recentMessages}
198
- * via `conversations.replies` (50-message cap). Failures are logged and
199
- * swallowed, leaving `recentMessages` empty.
217
+ * via `conversations.replies` (50-message cap). Overlapping calls share
218
+ * one request. Failures are logged and swallowed without discarding the
219
+ * most recently loaded messages.
200
220
  */
201
221
  refresh(): Promise<void>;
202
222
  /**
@@ -276,7 +296,11 @@ interface SlackBinding {
276
296
  * anchor.
277
297
  */
278
298
  export declare function buildSlackBinding(input: {
299
+ /** Slack app id used to identify this app's fetched thread replies. */
300
+ readonly appId?: string;
279
301
  readonly botToken: SlackBotToken | undefined;
302
+ /** Slack bot user id used to identify this app's fetched thread replies. */
303
+ readonly botUserId?: string;
280
304
  readonly channelId: string;
281
305
  readonly threadTs: string;
282
306
  readonly teamId: string | undefined;
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{isCardElement}from"#compiled/chat/index.js";import{callSlackApi as callSlackApi$1,fetchSlackThreadReplies,postSlackEphemeral,postSlackMessage,resolveSlackBotToken as resolveSlackBotToken$1,uploadSlackFiles}from"#compiled/@chat-adapter/slack/api.js";import{cardToBlocks,cardToFallbackText}from"#public/channels/slack/blocks.js";import{truncateTypingStatus}from"#public/channels/slack/limits.js";import{slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";const log=createLogger(`slack.api`);function slackContinuationToken(e,t){return`${e}:${t}`}async function resolveSlackBotToken(e){let t=e??process.env.SLACK_BOT_TOKEN;if(!t)throw Error(`SLACK_BOT_TOKEN is required.`);return resolveSlackBotToken$1(t)}async function callSlackApi(e){return callSlackApi$1(e.operation,normalizeSlackApiBody(e.body),createSlackApiOptions(e.botToken))}function createSlackRequester(e){return(t,n)=>callSlackApi({botToken:e,operation:t,body:n})}function buildSlackWorkspaceHandle(e){return{teamId:e.teamId,request:createSlackRequester(e.botToken)}}function buildSlackBinding(e){let n=createSlackRequester(e.botToken),r=[],s=e.threadTs;function handleMessageTs(t){s||t===s||(s=t,e.onThreadTsChanged?.(t))}async function uploadFiles(t,n){let r=n?.channelId??e.channelId,i=n?.threadTs??s;return uploadSlackFiles(t.map(toSlackFileUpload),{...createSlackApiOptions(e.botToken),channelId:r||void 0,initialComment:n?.initialComment,threadTs:i||void 0})}return{thread:{recentMessages:r,async post(t){let n=normalizePostInput(t),r=n.files??[],i=`blocks`in n||`card`in n||`markdown`in n;if(r.length>0&&!i){let e=await uploadFiles(r,{initialComment:`text`in n?n.text:void 0});return{id:Array.isArray(e.raw.files)&&e.raw.files.length>0?String(e.raw.files[0].id??``):``,raw:e.raw}}let a=await postSlackMessage(buildPostMessageOptions(n,e.channelId,s,e.botToken)),c=a.id;if(handleMessageTs(c),r.length>0&&i)try{await uploadFiles(r)}catch(e){log.warn(`file upload after message post failed`,{error:e})}return{id:c,raw:a.raw}},async postEphemeral(t,n){let r=await postSlackEphemeral({...buildPostMessageOptions(normalizePostInput(n),e.channelId,s,e.botToken),user:t});return{id:r.id,raw:r.raw}},async postDirectMessage(t,r){let i=await n(`conversations.open`,{users:t}),a=i.ok===!0?i.channel?.id:void 0;if(typeof a!=`string`||a.length===0)throw Error(`Slack conversations.open failed: ${i.error??`unknown_error`}`);let s=await postSlackMessage(buildPostMessageOptions(normalizePostInput(r),a,``,e.botToken));return{id:s.id,raw:s.raw}},async startTyping(r){if(!(!e.channelId||!s))try{let t=r===void 0?``:truncateTypingStatus(r),i={channel_id:e.channelId,thread_ts:s,status:t};t.length>0&&(i.loading_messages=[t]);let a=await n(`assistant.threads.setStatus`,i);a.ok!==!0&&log.warn(`assistant.threads.setStatus returned not-ok`,{error:a.error})}catch(n){logError(log,`startTyping threw — swallowed`,n,{channelId:e.channelId})}},async refresh(){if(r.length=0,!(!e.channelId||!s))try{let t=await fetchSlackThreadReplies({...createSlackApiOptions(e.botToken),channel:e.channelId,limit:50,ts:s});for(let e of t.messages)r.push(parseThreadMessage(e,s))}catch(n){logError(log,`refresh threw — swallowed`,n,{channelId:e.channelId})}},mentionUser(e){return`<@${e}>`}},slack:{channelId:e.channelId,get threadTs(){return s},teamId:e.teamId,request:n,uploadFiles}}}function normalizePostInput(e){return typeof e==`string`?{markdown:e}:isCardElement(e)?{card:e}:e}function buildPostMessageOptions(e,t,n,r){let i={...createSlackApiOptions(r),channel:t,threadTs:n||void 0,unfurlLinks:!1,unfurlMedia:!1};return`card`in e?(i.blocks=cardToBlocks(e.card),i.text=e.fallbackText??cardToFallbackText(e.card),i):`blocks`in e?(i.blocks=[...e.blocks],e.text!==void 0&&(i.text=e.text),i):`markdown`in e?(i.markdownText=e.markdown,i):(i.text=e.text,i)}function createSlackApiOptions(e){return{token:()=>resolveSlackBotToken(e)}}function normalizeSlackApiBody(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function toSlackFileUpload(e){return{data:normalizeFileData(e.data),filename:e.filename}}function normalizeFileData(e){if(e instanceof ArrayBuffer||typeof Blob<`u`&&e instanceof Blob)return e;if(ArrayBuffer.isView(e)){let t=e;return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}return e}function parseThreadMessage(e,t){let n=typeof e.text==`string`?e.text:``,r=typeof e.ts==`string`?e.ts:``,i=typeof e.thread_ts==`string`?e.thread_ts:t,a=typeof e.user==`string`?e.user:void 0,o=typeof e.bot_id==`string`?e.bot_id:void 0;return{text:n,markdown:slackMrkdwnToGfm(n),user:a,botId:o,ts:r,threadTs:i,isMe:o!==void 0,raw:e}}export{buildSlackBinding,buildSlackWorkspaceHandle,callSlackApi,resolveSlackBotToken,slackContinuationToken};
1
+ import{createLogger,logError}from"#internal/logging.js";import{isCardElement}from"#compiled/chat/index.js";import{callSlackApi as callSlackApi$1,fetchSlackThreadReplies,postSlackEphemeral,postSlackMessage,resolveSlackBotToken as resolveSlackBotToken$1,uploadSlackFiles}from"#compiled/@chat-adapter/slack/api.js";import{cardToBlocks,cardToFallbackText}from"#public/channels/slack/blocks.js";import{truncateTypingStatus}from"#public/channels/slack/limits.js";import{slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";const log=createLogger(`slack.api`);function slackContinuationToken(e,t){return`${e}:${t}`}async function resolveSlackBotToken(e){let t=e??process.env.SLACK_BOT_TOKEN;if(!t)throw Error(`SLACK_BOT_TOKEN is required.`);return resolveSlackBotToken$1(t)}async function callSlackApi(e){return callSlackApi$1(e.operation,normalizeSlackApiBody(e.body),createSlackApiOptions(e.botToken))}function createSlackRequester(e){return(t,n)=>callSlackApi({botToken:e,operation:t,body:n})}function buildSlackWorkspaceHandle(e){return{teamId:e.teamId,request:createSlackRequester(e.botToken)}}function buildSlackBinding(e){let n=createSlackRequester(e.botToken),r=[],s=e.threadTs,l;function handleMessageTs(t){s||t===s||(s=t,e.onThreadTsChanged?.(t))}async function uploadFiles(t,n){let r=n?.channelId??e.channelId,i=n?.threadTs??s;return uploadSlackFiles(t.map(toSlackFileUpload),{...createSlackApiOptions(e.botToken),channelId:r||void 0,initialComment:n?.initialComment,threadTs:i||void 0})}function refreshMessages(){if(l!==void 0)return l;async function fetchAndReplace(){if(!e.channelId||!s){r=[];return}try{r=(await fetchSlackThreadReplies({...createSlackApiOptions(e.botToken),channel:e.channelId,limit:50,ts:s})).messages.map(t=>parseThreadMessage(t,s,{appId:e.appId,botUserId:e.botUserId}))}catch(n){logError(log,`refresh threw — swallowed`,n,{channelId:e.channelId})}}let n=fetchAndReplace().finally(()=>{l===n&&(l=void 0)});return l=n,n}let u={get recentMessages(){return r},async listParticipants(){await u.refresh();let e=new Set;for(let t of r)t.user!==void 0&&t.botId===void 0&&e.add(t.user);return[...e]},async post(t){let n=normalizePostInput(t),r=n.files??[],i=`blocks`in n||`card`in n||`markdown`in n;if(r.length>0&&!i){let e=await uploadFiles(r,{initialComment:`text`in n?n.text:void 0});return{id:Array.isArray(e.raw.files)&&e.raw.files.length>0?String(e.raw.files[0].id??``):``,raw:e.raw}}let a=await postSlackMessage(buildPostMessageOptions(n,e.channelId,s,e.botToken)),c=a.id;if(handleMessageTs(c),r.length>0&&i)try{await uploadFiles(r)}catch(e){log.warn(`file upload after message post failed`,{error:e})}return{id:c,raw:a.raw}},async postEphemeral(t,n){let r=await postSlackEphemeral({...buildPostMessageOptions(normalizePostInput(n),e.channelId,s,e.botToken),user:t});return{id:r.id,raw:r.raw}},async postDirectMessage(t,r){let i=await n(`conversations.open`,{users:t}),a=i.ok===!0?i.channel?.id:void 0;if(typeof a!=`string`||a.length===0)throw Error(`Slack conversations.open failed: ${i.error??`unknown_error`}`);let s=await postSlackMessage(buildPostMessageOptions(normalizePostInput(r),a,``,e.botToken));return{id:s.id,raw:s.raw}},async startTyping(r){if(!(!e.channelId||!s))try{let t=r===void 0?``:truncateTypingStatus(r),i={channel_id:e.channelId,thread_ts:s,status:t};t.length>0&&(i.loading_messages=[t]);let a=await n(`assistant.threads.setStatus`,i);a.ok!==!0&&log.warn(`assistant.threads.setStatus returned not-ok`,{error:a.error})}catch(n){logError(log,`startTyping threw — swallowed`,n,{channelId:e.channelId})}},refresh(){return refreshMessages()},mentionUser(e){return`<@${e}>`}};return{thread:u,slack:{channelId:e.channelId,get threadTs(){return s},teamId:e.teamId,request:n,uploadFiles}}}function normalizePostInput(e){return typeof e==`string`?{markdown:e}:isCardElement(e)?{card:e}:e}function buildPostMessageOptions(e,t,n,r){let i={...createSlackApiOptions(r),channel:t,threadTs:n||void 0,unfurlLinks:!1,unfurlMedia:!1};return`card`in e?(i.blocks=cardToBlocks(e.card),i.text=e.fallbackText??cardToFallbackText(e.card),i):`blocks`in e?(i.blocks=[...e.blocks],e.text!==void 0&&(i.text=e.text),i):`markdown`in e?(i.markdownText=e.markdown,i):(i.text=e.text,i)}function createSlackApiOptions(e){return{token:()=>resolveSlackBotToken(e)}}function normalizeSlackApiBody(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function toSlackFileUpload(e){return{data:normalizeFileData(e.data),filename:e.filename}}function normalizeFileData(e){if(e instanceof ArrayBuffer||typeof Blob<`u`&&e instanceof Blob)return e;if(ArrayBuffer.isView(e)){let t=e;return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}return e}function parseThreadMessage(e,t,n){let r=typeof e.text==`string`?e.text:``,i=typeof e.ts==`string`?e.ts:``,a=typeof e.thread_ts==`string`?e.thread_ts:t,o=typeof e.user==`string`?e.user:void 0,s=typeof e.bot_id==`string`?e.bot_id:void 0,c=typeof e.app_id==`string`?e.app_id:void 0,l=n.botUserId!==void 0&&o===n.botUserId||n.appId!==void 0&&c===n.appId;return{text:r,markdown:slackMrkdwnToGfm(r),user:o,botId:s,ts:i,threadTs:a,isMe:l,raw:e}}export{buildSlackBinding,buildSlackWorkspaceHandle,callSlackApi,resolveSlackBotToken,slackContinuationToken};
@@ -19,11 +19,12 @@ export declare function collectSlackFileParts(attachments: readonly SlackAttachm
19
19
  * Prefers attachments on the triggering mention (the common case: user
20
20
  * uploads a file and mentions the bot in the same message). When the
21
21
  * mention has none, refreshes the thread via {@link SlackThread.refresh}
22
- * and picks the latest non-bot message's attachments covering the
23
- * case where a user dropped a file in the thread first, then mentioned
24
- * the bot in a follow-up. Any error during refresh is logged and treated
25
- * as "no attachments" so the text portion of the mention still gets
26
- * delivered.
22
+ * and picks the attachments of the latest message this app did not
23
+ * author (the thread message `isMe` classification) covering the case
24
+ * where a user or another bot dropped a file in the thread first, then a
25
+ * user mentioned the bot in a follow-up. Any error during refresh is logged
26
+ * and treated as "no attachments" so the text portion of the mention
27
+ * still gets delivered.
27
28
  *
28
29
  * Skips the thread-history lookback when the policy disables uploads,
29
30
  * since the refresh can't surface anything we'd deliver.
@@ -5,7 +5,7 @@
5
5
  * without taking a direct `ai` dependency.
6
6
  */
7
7
  export type { ModelMessage } from "ai";
8
- export { slackChannel, type SlackApiResponse, type SlackAuthorizationEventContext, type SlackAuthorizationRequiredHandler, type SlackBotToken, type SlackChannel, type SlackChannelConfig, type SlackChannelCredentials, type SlackChannelEvents, type SlackChannelState, type SlackContext, type SlackEventContext, type SlackEventReceiveFn, type SlackEventReceiveOptions, type SlackHandle, type SlackInboundEventContext, type SlackInboundResult, type SlackInboundResultOrPromise, type SlackInitialMessage, type SlackInstrumentationMetadata, type SlackInteractionAction, type SlackMentionResult, type SlackMentionResultOrPromise, type SlackReceiveTarget, type SlackThread, type SlackWebhookVerifier, type SlackWorkspaceHandle, } from "#public/channels/slack/slackChannel.js";
8
+ export { slackChannel, type SlackApiResponse, type SlackAuthorizationEventContext, type SlackAuthorizationRequiredHandler, type SlackBotToken, type SlackCancelOptions, type SlackChannel, type SlackChannelConfig, type SlackChannelCredentials, type SlackChannelEvents, type SlackChannelState, type SlackContext, type SlackEventCancelOptions, type SlackEventContext, type SlackEventReceiveFn, type SlackEventReceiveOptions, type SlackHandle, type SlackInboundEventContext, type SlackInboundMessageContext, type SlackInboundResult, type SlackInboundResultOrPromise, type SlackInitialMessage, type SlackInstrumentationMetadata, type SlackInteractionAction, type SlackInteractionContext, type SlackMentionResult, type SlackMentionResultOrPromise, type SlackReceiveTarget, type SlackSessionTarget, type SlackThread, type SlackWebhookVerifier, type SlackWorkspaceHandle, } from "#public/channels/slack/slackChannel.js";
9
9
  export type { SlackAttachment, SlackAuthor, SlackEvent, SlackEventEnvelope, SlackInboundContext, SlackMessage, } from "#public/channels/slack/inbound.js";
10
10
  export { callSlackApi, resolveSlackBotToken, slackContinuationToken, type SlackPostInput, type SlackPostedMessage, type SlackThreadMessage, type SlackUploadFilesOptions, type SlackUploadFilesResult, } from "#public/channels/slack/api.js";
11
11
  export { defaultSlackAuth } from "#public/channels/slack/defaults.js";
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { type SlackBlockActionsPayload } from "#compiled/@chat-adapter/slack/webhook.js";
20
20
  import type { SlackChannelConfig, SlackChannelState, SlackInteractionAction } from "#public/channels/slack/slackChannel.js";
21
- import type { SendFn } from "#public/definitions/channel.js";
21
+ import type { CancelFn, SendFn } from "#public/definitions/channel.js";
22
22
  /**
23
23
  * Decoded view of a Slack `block_actions` payload. Returned by
24
24
  * {@link parseBlockActionsPayload} and read by the handler.
@@ -59,6 +59,7 @@ export interface InteractionHandlerDeps {
59
59
  * anything else to `config.onInteraction`.
60
60
  */
61
61
  export declare function handleInteractionPost(rawBody: string, ctx: {
62
+ cancel: CancelFn;
62
63
  send: SendFn<SlackChannelState>;
63
64
  waitUntil: (task: Promise<unknown>) => void;
64
65
  }, deps: InteractionHandlerDeps): Promise<Response>;
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{SLACK_CARD_SUBTEXT_MAX_LENGTH,truncateCardSubtext}from"#public/channels/slack/limits.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=o?.id??s.team_id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,label:extractActionLabel(e),user:l})),channelId:r,threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,threadTs:e.threadTs,teamId:e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){return findPromptBlocks(e)[0]}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}function buildAnsweredHitlMessageBlocks(e){let t=findActionBlockIndex(e.messageBlocks,e.actionId);if(t===-1)return buildAnsweredBlocks({promptBlocks:findPromptBlocks(e.messageBlocks),answerLabel:e.answerLabel,userId:e.userId});let n=e.messageBlocks[t],r=answeredBlocksFromActionBlock({answerLabel:e.answerLabel,block:n,userId:e.userId})??buildAnsweredBlocks({promptBlocks:promptBlocksFromActionBlock(n),answerLabel:e.answerLabel,userId:e.userId});return[...e.messageBlocks.slice(0,t),...r,...e.messageBlocks.slice(t+1)]}function findActionBlockIndex(e,t){return e.findIndex(e=>blockContainsActionId(e,t))}function blockContainsActionId(e,t){return isObjectRecord(e)?actionsContainActionId(e.elements,t)||actionsContainActionId(e.actions,t):!1}function actionsContainActionId(e,t){return Array.isArray(e)?e.some(e=>isObjectRecord(e)&&e.action_id===t):!1}function isObjectRecord(e){return typeof e==`object`&&!!e}function answeredBlocksFromActionBlock(e){if(!isObjectRecord(e.block)||e.block.type!==`card`)return;let{actions:t,subtext:n,...r}=e.block,i={...r,subtext:{type:`mrkdwn`,text:formatAnsweredCardSubtext(e),verbatim:!1}};return hasCardContent(i)?[i]:void 0}function formatAnsweredCardSubtext(e){let r=e.userId.length>0?` by <@${e.userId}>`:``,i=SLACK_CARD_SUBTEXT_MAX_LENGTH-20-1-r.length;return truncateCardSubtext(`:white_check_mark: *${truncateWithEllipsis(e.answerLabel,i)}*${r}`)}function truncateWithEllipsis(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function promptBlocksFromActionBlock(e){if(!isObjectRecord(e)||e.type!==`card`)return[];let{actions:t,...n}=e;return hasCardContent(n)?[n]:[]}function hasCardContent(e){return e.body!==void 0||e.title!==void 0||e.hero_image!==void 0}async function handleInteractionPost(e,t,n){let i=new Response(`ok`,{status:200}),s;try{s=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(s.kind===`view_submission`)return handleViewSubmission(s,t,n);if(s.kind!==`block_actions`)return i;let c=parseBlockActionsPayload(s);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:s.raw,interaction:c,freeformAction:l,deps:n}),i;let u=slackContinuationToken(c.channelId,c.threadTs),d=c.actions.map(deriveHitlResponse).filter(e=>e!==null);if(d.length>0){let e=c.actions[0]?.user;if(!e)return i;t.waitUntil(t.send({inputResponses:d},{auth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:e.id,userName:e.username??e.name}),continuationToken:u,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId??null,triggeringUserId:e.id}}).catch(e=>{log.error(`HITL interaction delivery failed`,{error:e})})),t.waitUntil(updateAnsweredHitlCard(c,n).catch(e=>{log.error(`HITL answered-card update failed`,{error:e})}))}let p=n.config.onInteraction;if(p){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let{thread:i,slack:a}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),o={thread:i,slack:a};for(let n of e)t.waitUntil(Promise.resolve(p(n,o)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return i}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,t,n){let r=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let i;try{i=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!i.continuationToken||!i.requestId||!i.messageTs||!i.channelId||!i.threadTs)return r;let a=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(a.length===0)return r;let u=e.user,d=e.userId,f=u?.teamId??e.teamId??null;return t.waitUntil(t.send({inputResponses:[{requestId:i.requestId,text:a}]},{auth:buildSlackAuthContext({channelId:i.channelId,teamId:f,threadTs:i.threadTs,userId:d,userName:u?.username??u?.name}),continuationToken:i.continuationToken,state:{channelId:i.channelId,threadTs:i.threadTs,teamId:f,triggeringUserId:d}}).catch(e=>{log.error(`freeform answer delivery failed`,{error:e})})),t.waitUntil(updateAnsweredFreeformCard({channelId:i.channelId,messageTs:i.messageTs,answerLabel:a,userId:d??void 0,deps:n}).catch(e=>{log.error(`freeform answered-card update failed`,{error:e})})),r}async function updateAnsweredHitlCard(e,t){let n=e.actions.find(e=>isHitlAction(e.actionId));if(!n||!n.messageTs)return;let r=n.label??n.selectedOptionValue??n.value;if(!r)return;let a=buildAnsweredHitlMessageBlocks({actionId:n.actionId,answerLabel:r,messageBlocks:e.messageBlocks,userId:n.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),s=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:n.messageTs,blocks:a,text:`Answered: ${r}`})});if(!s.ok)throw Error(`Slack chat.update returned HTTP ${s.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlocks:[],answerLabel:e.answerLabel,userId:e.userId}),n=await resolveSlackBotToken(e.deps.config.credentials?.botToken),r=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${n}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!r.ok)throw Error(`Slack chat.update returned HTTP ${r.status}`)}export{handleInteractionPost,parseBlockActionsPayload};
1
+ import{createLogger}from"#internal/logging.js";import{SLACK_CARD_SUBTEXT_MAX_LENGTH,truncateCardSubtext}from"#public/channels/slack/limits.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=o?.id??s.team_id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,label:extractActionLabel(e),user:l})),channelId:r,threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,threadTs:e.threadTs,teamId:e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){return findPromptBlocks(e)[0]}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}function buildAnsweredHitlMessageBlocks(e){let t=findActionBlockIndex(e.messageBlocks,e.actionId);if(t===-1)return buildAnsweredBlocks({promptBlocks:findPromptBlocks(e.messageBlocks),answerLabel:e.answerLabel,userId:e.userId});let n=e.messageBlocks[t],r=answeredBlocksFromActionBlock({answerLabel:e.answerLabel,block:n,userId:e.userId})??buildAnsweredBlocks({promptBlocks:promptBlocksFromActionBlock(n),answerLabel:e.answerLabel,userId:e.userId});return[...e.messageBlocks.slice(0,t),...r,...e.messageBlocks.slice(t+1)]}function findActionBlockIndex(e,t){return e.findIndex(e=>blockContainsActionId(e,t))}function blockContainsActionId(e,t){return isObjectRecord(e)?actionsContainActionId(e.elements,t)||actionsContainActionId(e.actions,t):!1}function actionsContainActionId(e,t){return Array.isArray(e)?e.some(e=>isObjectRecord(e)&&e.action_id===t):!1}function isObjectRecord(e){return typeof e==`object`&&!!e}function answeredBlocksFromActionBlock(e){if(!isObjectRecord(e.block)||e.block.type!==`card`)return;let{actions:t,subtext:n,...r}=e.block,i={...r,subtext:{type:`mrkdwn`,text:formatAnsweredCardSubtext(e),verbatim:!1}};return hasCardContent(i)?[i]:void 0}function formatAnsweredCardSubtext(e){let r=e.userId.length>0?` by <@${e.userId}>`:``,i=SLACK_CARD_SUBTEXT_MAX_LENGTH-20-1-r.length;return truncateCardSubtext(`:white_check_mark: *${truncateWithEllipsis(e.answerLabel,i)}*${r}`)}function truncateWithEllipsis(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function promptBlocksFromActionBlock(e){if(!isObjectRecord(e)||e.type!==`card`)return[];let{actions:t,...n}=e;return hasCardContent(n)?[n]:[]}function hasCardContent(e){return e.body!==void 0||e.title!==void 0||e.hero_image!==void 0}async function handleInteractionPost(e,t,n){let i=new Response(`ok`,{status:200}),s;try{s=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(s.kind===`view_submission`)return handleViewSubmission(s,t,n);if(s.kind!==`block_actions`)return i;let c=parseBlockActionsPayload(s);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:s.raw,interaction:c,freeformAction:l,deps:n}),i;let u=slackContinuationToken(c.channelId,c.threadTs),d=c.actions.map(deriveHitlResponse).filter(e=>e!==null);if(d.length>0){let e=c.actions[0]?.user;if(!e)return i;t.waitUntil(t.send({inputResponses:d},{auth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:e.id,userName:e.username??e.name}),continuationToken:u,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId??null,triggeringUserId:e.id}}).catch(e=>{log.error(`HITL interaction delivery failed`,{error:e})})),t.waitUntil(updateAnsweredHitlCard(c,n).catch(e=>{log.error(`HITL answered-card update failed`,{error:e})}))}let p=n.config.onInteraction;if(p){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let{thread:i,slack:a}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),o={cancel:(e={})=>t.cancel({continuationToken:u,turnId:e.turnId}),thread:i,slack:a};for(let n of e)t.waitUntil(Promise.resolve(p(n,o)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return i}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,t,n){let r=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let i;try{i=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!i.continuationToken||!i.requestId||!i.messageTs||!i.channelId||!i.threadTs)return r;let a=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(a.length===0)return r;let u=e.user,d=e.userId,f=u?.teamId??e.teamId??null;return t.waitUntil(t.send({inputResponses:[{requestId:i.requestId,text:a}]},{auth:buildSlackAuthContext({channelId:i.channelId,teamId:f,threadTs:i.threadTs,userId:d,userName:u?.username??u?.name}),continuationToken:i.continuationToken,state:{channelId:i.channelId,threadTs:i.threadTs,teamId:f,triggeringUserId:d}}).catch(e=>{log.error(`freeform answer delivery failed`,{error:e})})),t.waitUntil(updateAnsweredFreeformCard({channelId:i.channelId,messageTs:i.messageTs,answerLabel:a,userId:d??void 0,deps:n}).catch(e=>{log.error(`freeform answered-card update failed`,{error:e})})),r}async function updateAnsweredHitlCard(e,t){let n=e.actions.find(e=>isHitlAction(e.actionId));if(!n||!n.messageTs)return;let r=n.label??n.selectedOptionValue??n.value;if(!r)return;let a=buildAnsweredHitlMessageBlocks({actionId:n.actionId,answerLabel:r,messageBlocks:e.messageBlocks,userId:n.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),s=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:n.messageTs,blocks:a,text:`Answered: ${r}`})});if(!s.ok)throw Error(`Slack chat.update returned HTTP ${s.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlocks:[],answerLabel:e.answerLabel,userId:e.userId}),n=await resolveSlackBotToken(e.deps.config.credentials?.botToken),r=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${n}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!r.ok)throw Error(`Slack chat.update returned HTTP ${r.status}`)}export{handleInteractionPost,parseBlockActionsPayload};