experimental-ash 0.63.0 → 0.64.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/docs/public/advanced/auth-and-route-protection.mdx +26 -20
  3. package/dist/docs/public/channels/ash.mdx +5 -1
  4. package/dist/src/chunks/{use-ash-agent-CRWVA4i-.js → use-ash-agent-D7LvOfgD.js} +13 -7
  5. package/dist/src/chunks/{use-ash-agent-BQJLh7KU.js → use-ash-agent-DPYNpc07.js} +13 -7
  6. package/dist/src/cli/dev/tui/runner.d.ts +6 -0
  7. package/dist/src/cli/dev/tui/runner.js +1 -1
  8. package/dist/src/cli/dev/tui/tui.js +1 -1
  9. package/dist/src/client/client-error.js +1 -1
  10. package/dist/src/execution/durable-session-migrations/chain.d.ts +7 -0
  11. package/dist/src/execution/durable-session-migrations/chain.js +1 -1
  12. package/dist/src/execution/durable-session-migrations/turn-workflow-v0-to-v1.d.ts +12 -0
  13. package/dist/src/execution/durable-session-migrations/turn-workflow-v0-to-v1.js +1 -0
  14. package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +40 -0
  15. package/dist/src/execution/durable-session-migrations/turn-workflow.js +1 -0
  16. package/dist/src/execution/sandbox/prewarm.d.ts +1 -0
  17. package/dist/src/execution/sandbox/prewarm.js +1 -1
  18. package/dist/src/execution/turn-workflow.d.ts +3 -13
  19. package/dist/src/execution/turn-workflow.js +1 -1
  20. package/dist/src/execution/workflow-steps.d.ts +5 -11
  21. package/dist/src/execution/workflow-steps.js +1 -1
  22. package/dist/src/internal/application/package.js +1 -1
  23. package/dist/src/internal/nitro/dev-runtime-artifacts.d.ts +32 -0
  24. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -0
  25. package/dist/src/internal/nitro/host/artifacts-config.js +1 -1
  26. package/dist/src/internal/nitro/host/configure-nitro-routes.js +3 -3
  27. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  28. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  29. package/dist/src/internal/nitro/host/prepare-application-host.d.ts +3 -1
  30. package/dist/src/internal/nitro/host/prepare-application-host.js +1 -1
  31. package/dist/src/internal/nitro/host/start-development-server.js +1 -1
  32. package/dist/src/internal/nitro/routes/dev-runtime-artifacts.d.ts +10 -0
  33. package/dist/src/internal/nitro/routes/dev-runtime-artifacts.js +1 -0
  34. package/dist/src/internal/nitro/routes/runtime-artifacts.d.ts +1 -0
  35. package/dist/src/internal/nitro/routes/runtime-artifacts.js +1 -1
  36. package/dist/src/internal/nitro/routes/schedule-task.js +1 -1
  37. package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
  38. package/dist/src/packages/ash-scaffold/src/web-template.js +5 -16
  39. package/dist/src/protocol/routes.d.ts +9 -0
  40. package/dist/src/protocol/routes.js +1 -1
  41. package/dist/src/public/channels/ash.js +1 -1
  42. package/dist/src/public/channels/auth.d.ts +45 -3
  43. package/dist/src/public/channels/auth.js +1 -1
  44. package/dist/src/public/channels/slack/inbound.d.ts +3 -1
  45. package/dist/src/public/channels/slack/inbound.js +1 -1
  46. package/dist/src/services/dev-client.d.ts +27 -0
  47. package/dist/src/services/dev-client.js +1 -1
  48. package/dist/src/svelte/index.js +1 -1
  49. package/dist/src/svelte/use-ash-agent.js +1 -1
  50. package/dist/src/vue/index.js +1 -1
  51. package/dist/src/vue/use-ash-agent.js +1 -1
  52. package/package.json +1 -1
@@ -0,0 +1,32 @@
1
+ import type { CompileAgentResult } from "#compiler/compile-agent.js";
2
+ export interface DevelopmentRuntimeArtifactsRevision {
3
+ readonly revision: string;
4
+ }
5
+ /**
6
+ * Resolves the dev-server pointer that records the latest runtime artifact
7
+ * snapshot for new sessions.
8
+ */
9
+ export declare function resolveDevelopmentRuntimeArtifactsPointerPath(appRoot: string): string;
10
+ /**
11
+ * Publishes one immutable dev runtime snapshot and points future sessions at it.
12
+ */
13
+ export declare function publishDevelopmentRuntimeArtifactsSnapshot(compileResult: CompileAgentResult): Promise<string>;
14
+ /**
15
+ * Stages one immutable dev runtime snapshot without moving the latest pointer.
16
+ */
17
+ export declare function stageDevelopmentRuntimeArtifactsSnapshot(compileResult: CompileAgentResult): Promise<string>;
18
+ /**
19
+ * Moves the dev runtime pointer so future sessions use a staged snapshot.
20
+ */
21
+ export declare function activateDevelopmentRuntimeArtifactsSnapshot(input: {
22
+ readonly appRoot: string;
23
+ readonly snapshotRoot: string;
24
+ }): Promise<void>;
25
+ /**
26
+ * Reads the latest dev runtime snapshot root when the dev server has one.
27
+ */
28
+ export declare function readDevelopmentRuntimeArtifactsSnapshotRoot(pointerPath: string | undefined): string | undefined;
29
+ /**
30
+ * Reads a revision token for the latest dev runtime artifact snapshot.
31
+ */
32
+ export declare function readDevelopmentRuntimeArtifactsRevision(appRoot: string): DevelopmentRuntimeArtifactsRevision;
@@ -0,0 +1 @@
1
+ import{basename,dirname,join,relative}from"node:path";import{cp,mkdir,readFile,readdir,rename,rm,writeFile}from"node:fs/promises";import{existsSync,readFileSync}from"node:fs";import{randomUUID}from"node:crypto";const DEV_RUNTIME_ARTIFACTS_DIRECTORY=`dev-runtime`,DEV_RUNTIME_ARTIFACTS_SNAPSHOT_SKIP_NAMES=new Set([`.ash`,`.git`,`.output`,`.turbo`,`.vercel`,`.workflow-data`,`node_modules`]);function resolveDevelopmentRuntimeArtifactsPointerPath(e){return join(e,`.ash`,DEV_RUNTIME_ARTIFACTS_DIRECTORY,`current.json`)}async function publishDevelopmentRuntimeArtifactsSnapshot(e){let t=await stageDevelopmentRuntimeArtifactsSnapshot(e);return await activateDevelopmentRuntimeArtifactsSnapshot({appRoot:e.project.appRoot,snapshotRoot:t}),t}async function stageDevelopmentRuntimeArtifactsSnapshot(e){let t=join(e.project.appRoot,`.ash`,DEV_RUNTIME_ARTIFACTS_DIRECTORY,`snapshots`,`${Date.now().toString(36)}-${randomUUID()}`);return await copyAuthoredAppSourceSnapshot({appRoot:e.project.appRoot,snapshotRoot:t}),await cp(e.paths.compileDirectoryPath,join(t,`.ash`,`compile`),{recursive:!0}),await rewriteSnapshotCompiledManifest({appRoot:e.project.appRoot,manifestPath:join(t,`.ash`,`compile`,`compiled-agent-manifest.json`),snapshotRoot:t}),t}async function activateDevelopmentRuntimeArtifactsSnapshot(e){await writeDevelopmentRuntimeArtifactsPointer(e)}function readDevelopmentRuntimeArtifactsSnapshotRoot(e){if(!(e===void 0||!existsSync(e)))try{let t=JSON.parse(readFileSync(e,`utf8`));return t.kind!==`ash-dev-runtime-artifacts-pointer`||t.version!==1||typeof t.appRoot!=`string`||t.appRoot.length===0?void 0:t.appRoot}catch{return}}function readDevelopmentRuntimeArtifactsRevision(e){return{revision:readDevelopmentRuntimeArtifactsSnapshotRoot(resolveDevelopmentRuntimeArtifactsPointerPath(e))??e}}async function copyAuthoredAppSourceSnapshot(e){await mkdir(e.snapshotRoot,{recursive:!0});for(let t of await readdir(e.appRoot,{withFileTypes:!0}))DEV_RUNTIME_ARTIFACTS_SNAPSHOT_SKIP_NAMES.has(t.name)||await cp(join(e.appRoot,t.name),join(e.snapshotRoot,t.name),{filter:t=>!shouldSkipSnapshotSource(e.appRoot,t),recursive:!0})}function shouldSkipSnapshotSource(e,t){let n=relative(e,t);return n.length===0?!1:n.split(/[\\/]/).some(e=>DEV_RUNTIME_ARTIFACTS_SNAPSHOT_SKIP_NAMES.has(e))}async function rewriteSnapshotCompiledManifest(e){let t=JSON.parse(await readFile(e.manifestPath,`utf8`)),n=rewriteManifestRoots({appRoot:e.appRoot,snapshotRoot:e.snapshotRoot,value:t});await writeFile(e.manifestPath,`${JSON.stringify(n,null,2)}\n`)}function rewriteManifestRoots(e){if(Array.isArray(e.value))return e.value.map(t=>rewriteManifestRoots({...e,value:t}));if(e.value===null||typeof e.value!=`object`)return e.value;let t={};for(let[n,r]of Object.entries(e.value)){if(typeof r==`string`&&(n===`appRoot`||n===`agentRoot`)){t[n]=rewritePathWithinAppRoot({appRoot:e.appRoot,path:r,snapshotRoot:e.snapshotRoot});continue}t[n]=rewriteManifestRoots({appRoot:e.appRoot,snapshotRoot:e.snapshotRoot,value:r})}return t}function rewritePathWithinAppRoot(t){let i=relative(t.appRoot,t.path);return i.startsWith(`..`)||i.length===0||basename(i)===``?t.path===t.appRoot?t.snapshotRoot:t.path:join(t.snapshotRoot,i)}async function writeDevelopmentRuntimeArtifactsPointer(e){let n=resolveDevelopmentRuntimeArtifactsPointerPath(e.appRoot),r=`${n}.${randomUUID()}.tmp`,i={appRoot:e.snapshotRoot,kind:`ash-dev-runtime-artifacts-pointer`,version:1};await mkdir(dirname(n),{recursive:!0}),await writeFile(r,`${JSON.stringify(i,null,2)}\n`);try{await rename(r,n)}catch(e){throw await rm(r,{force:!0}).catch(()=>{}),e}}export{activateDevelopmentRuntimeArtifactsSnapshot,publishDevelopmentRuntimeArtifactsSnapshot,readDevelopmentRuntimeArtifactsRevision,readDevelopmentRuntimeArtifactsSnapshotRoot,resolveDevelopmentRuntimeArtifactsPointerPath,stageDevelopmentRuntimeArtifactsSnapshot};
@@ -1 +1 @@
1
- import{resolvePackageSourceFilePath}from"#internal/application/package.js";function createNitroArtifactsConfig(e){return e.dev?{appRoot:e.appRoot,dev:e.dev,moduleMapLoaderPath:resolvePackageSourceFilePath(`src/internal/authored-module-map-loader.ts`)}:{appRoot:e.appRoot,dev:e.dev}}export{createNitroArtifactsConfig};
1
+ import{resolvePackageSourceFilePath}from"#internal/application/package.js";import{resolveDevelopmentRuntimeArtifactsPointerPath}from"#internal/nitro/dev-runtime-artifacts.js";function createNitroArtifactsConfig(e){return e.dev?{appRoot:e.appRoot,devRuntimeArtifactsPointerPath:resolveDevelopmentRuntimeArtifactsPointerPath(e.appRoot),dev:e.dev,moduleMapLoaderPath:resolvePackageSourceFilePath(`src/internal/authored-module-map-loader.ts`)}:{appRoot:e.appRoot,dev:e.dev}}export{createNitroArtifactsConfig};
@@ -1,4 +1,4 @@
1
- import{ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolvePackageRoot,resolvePackageSourceFilePath,resolveWorkflowModulePath}from"#internal/application/package.js";import{normalizeEsmImportSpecifier,stringifyEsmImportSpecifier}from"#internal/application/import-specifier.js";import{WorkflowBundleBuilder}from"#internal/workflow-bundle/builder.js";import{WORKFLOW_RUNS_API_ROUTE_PATH,WORKFLOW_RUN_EVENTS_ROUTE_PATTERN,WORKFLOW_RUN_ROUTE_PATTERN,WORKFLOW_RUN_STEPS_ROUTE_PATTERN}from"#internal/nitro/routes/workflow-route-helpers.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{computeChannelRouteRegistrations,registerChannelVirtualHandlers}from"#internal/nitro/host/channel-routes.js";function includesApplicationRoutes(e){return e===`all`||e===`app`}function includesWorkflowBundles(e){return includesWorkflowRoute(e)}function includesWorkflowRoute(e){return e===`all`||e===`flow`}function registerHandler(e,t){let n=`#ash-route-handler/${t.method??`ALL`} ${t.route}`,r=stringifyEsmImportSpecifier(t.handlerPath);e.options.handlers.push({handler:n,method:t.method,route:t.route}),e.options.virtual[n]=[`import handler from ${r};`,`export default handler;`].join(`
2
- `)}function resolveNitroWorkflowBuildDirectory(e){return join(e.options.buildDir,`workflow`)}function createRelativeImportSpecifier(e,t){let n=relative(e,t).replaceAll(`\\`,`/`);return n.startsWith(`.`)?n:`./${n}`}async function addWorkflowFileHandler(e,t){let n=join(resolveNitroWorkflowBuildDirectory(e),`${t.bundleName}-handler.mjs`),i=dirname(n),s=createRelativeImportSpecifier(i,t.bundlePath),c=(t.directHandlers??[]).map(e=>{let t=createRelativeImportSpecifier(i,e.bundlePath);return{importSpecifier:t,isOwnBundle:t===s,queuePrefix:e.queuePrefix}});await mkdir(i,{recursive:!0}),await writeFile(n,buildWorkflowFileHandlerSource({bundlePath:s,directHandlers:c,runtimeImportSpecifier:t.runtimeImportSpecifier})),e.options.handlers.push({handler:n,route:t.route})}function buildWorkflowFileHandlerSource(e){let t=[`// Generated by Ash. Do not edit by hand.`,`import { POST } from ${JSON.stringify(e.bundlePath)};`];if(e.directHandlers.length>0&&e.runtimeImportSpecifier!==void 0){let n=0,r=e.directHandlers.map(e=>{if(e.isOwnBundle)return{...e,binding:`POST`};let t=`__ashWorkflowDirectHandler${n}`;return n+=1,{...e,binding:t}});for(let e of r)e.isOwnBundle||t.push(`import { POST as ${e.binding} } from ${JSON.stringify(e.importSpecifier)};`);t.push(`import { getWorld as __ashGetWorkflowWorld } from ${JSON.stringify(e.runtimeImportSpecifier)};`,``,`try {`,` const __ashWorkflowWorld = await __ashGetWorkflowWorld();`,` if (typeof __ashWorkflowWorld?.registerHandler === "function") {`);for(let e of r)t.push(` __ashWorkflowWorld.registerHandler(${JSON.stringify(e.queuePrefix)}, ${e.binding});`);t.push(` }`,`} catch (err) {`,` console.warn("[ash] Failed to register direct workflow queue handlers:", err);`,`}`)}return t.push(``,`export default async ({ req }) => {`,` return await POST(req);`,`};`,``),t.join(`
1
+ import{ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,ASH_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolvePackageRoot,resolvePackageSourceFilePath,resolveWorkflowModulePath}from"#internal/application/package.js";import{normalizeEsmImportSpecifier,stringifyEsmImportSpecifier}from"#internal/application/import-specifier.js";import{WorkflowBundleBuilder}from"#internal/workflow-bundle/builder.js";import{WORKFLOW_RUNS_API_ROUTE_PATH,WORKFLOW_RUN_EVENTS_ROUTE_PATTERN,WORKFLOW_RUN_ROUTE_PATTERN,WORKFLOW_RUN_STEPS_ROUTE_PATTERN}from"#internal/nitro/routes/workflow-route-helpers.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{computeChannelRouteRegistrations,registerChannelVirtualHandlers}from"#internal/nitro/host/channel-routes.js";function includesApplicationRoutes(e){return e===`all`||e===`app`}function includesWorkflowBundles(e){return includesWorkflowRoute(e)}function includesWorkflowRoute(e){return e===`all`||e===`flow`}function registerHandler(e,t){let n=`#ash-route-handler/${t.method??`ALL`} ${t.route}`,r=stringifyEsmImportSpecifier(t.handlerPath);e.options.handlers.push({handler:n,method:t.method,route:t.route}),e.options.virtual[n]=[`import handler from ${r};`,`export default handler;`].join(`
2
+ `)}function resolveNitroWorkflowBuildDirectory(e){return join(e.options.buildDir,`workflow`)}function createRelativeImportSpecifier(e,t){let n=relative(e,t).replaceAll(`\\`,`/`);return n.startsWith(`.`)?n:`./${n}`}async function addWorkflowFileHandler(e,t){let n=join(resolveNitroWorkflowBuildDirectory(e),`${t.bundleName}-handler.mjs`),r=dirname(n),a=createRelativeImportSpecifier(r,t.bundlePath),c=(t.directHandlers??[]).map(e=>{let t=createRelativeImportSpecifier(r,e.bundlePath);return{importSpecifier:t,isOwnBundle:t===a,queuePrefix:e.queuePrefix}});await mkdir(r,{recursive:!0}),await writeFile(n,buildWorkflowFileHandlerSource({bundlePath:a,directHandlers:c,runtimeImportSpecifier:t.runtimeImportSpecifier})),e.options.handlers.push({handler:n,route:t.route})}function buildWorkflowFileHandlerSource(e){let t=[`// Generated by Ash. Do not edit by hand.`,`import { POST } from ${JSON.stringify(e.bundlePath)};`];if(e.directHandlers.length>0&&e.runtimeImportSpecifier!==void 0){let n=0,r=e.directHandlers.map(e=>{if(e.isOwnBundle)return{...e,binding:`POST`};let t=`__ashWorkflowDirectHandler${n}`;return n+=1,{...e,binding:t}});for(let e of r)e.isOwnBundle||t.push(`import { POST as ${e.binding} } from ${JSON.stringify(e.importSpecifier)};`);t.push(`import { getWorld as __ashGetWorkflowWorld } from ${JSON.stringify(e.runtimeImportSpecifier)};`,``,`try {`,` const __ashWorkflowWorld = await __ashGetWorkflowWorld();`,` if (typeof __ashWorkflowWorld?.registerHandler === "function") {`);for(let e of r)t.push(` __ashWorkflowWorld.registerHandler(${JSON.stringify(e.queuePrefix)}, ${e.binding});`);t.push(` }`,`} catch (err) {`,` console.warn("[ash] Failed to register direct workflow queue handlers:", err);`,`}`)}return t.push(``,`export default async ({ req }) => {`,` return await POST(req);`,`};`,``),t.join(`
3
3
  `)}function addFrameworkVirtualHandler(e,t){let n=`#ash-route${t.route}`,r=stringifyEsmImportSpecifier(t.modulePath);e.options.handlers.push({handler:n,method:t.method,route:t.route}),e.options.virtual[n]=[`import { ${t.handlerExport} } from ${r};`,`export default async (event) => ${t.handlerExport}(${t.args}, event.req);`].join(`
4
- `)}async function configureNitroRoutes(r,i,a){if(includesWorkflowBundles(a.surface)){let e=resolvePackageRoot(),t=new WorkflowBundleBuilder({appRoot:i.appRoot,compiledArtifactsBootstrapPath:i.compiledArtifacts.bootstrapPath,outDir:i.workflowBuildDir,rootDir:e,watch:r.options.dev}),n=Promise.resolve(),buildWorkflowArtifacts=async()=>{await t.build({nitroStepOutfile:includesWorkflowRoute(a.surface)?join(resolveNitroWorkflowBuildDirectory(r),`steps.mjs`):void 0,nitroWorkflowOutfile:r.options.dev&&includesWorkflowRoute(a.surface)?join(resolveNitroWorkflowBuildDirectory(r),`workflows.mjs`):void 0})},syncWorkflowArtifacts=async()=>{let e=n.then(buildWorkflowArtifacts);n=e.catch(()=>{}),await e},o=!0;await syncWorkflowArtifacts(),r.hooks.hook(`build:before`,async()=>{if(o){o=!1;return}await syncWorkflowArtifacts()}),r.options.dev&&r.hooks.hook(`dev:reload`,async()=>{await syncWorkflowArtifacts()})}let o=createNitroArtifactsConfig({appRoot:i.appRoot,dev:r.options.dev});includesApplicationRoutes(a.surface)&&(registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/index.ts`),method:`GET`,route:`/`}),registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/health.ts`),method:`GET`,route:ASH_HEALTH_ROUTE_PATH}),addFrameworkVirtualHandler(r,{args:JSON.stringify({appRoot:o.appRoot}),handlerExport:`handleAgentInfoRequest`,method:`GET`,modulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/info.ts`),route:ASH_INFO_ROUTE_PATH}),registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-runs.ts`),method:`GET`,route:WORKFLOW_RUNS_API_ROUTE_PATH}),registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run.ts`),method:`GET`,route:WORKFLOW_RUN_ROUTE_PATTERN}),registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run-steps.ts`),method:`GET`,route:WORKFLOW_RUN_STEPS_ROUTE_PATTERN}),registerHandler(r,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run-events.ts`),method:`GET`,route:WORKFLOW_RUN_EVENTS_ROUTE_PATTERN}),registerChannelVirtualHandlers(r,{artifactsConfig:o,registrations:computeChannelRouteRegistrations(i)}),r.options.dev&&addFrameworkVirtualHandler(r,{args:JSON.stringify({appRoot:o.appRoot}),handlerExport:`handleDevScheduleDispatchRequest`,method:`POST`,modulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/dev-schedule-dispatch.ts`),route:ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN}));let l=resolveNitroWorkflowBuildDirectory(r),u=includesWorkflowRoute(a.surface)?r.options.dev?join(l,`workflows.mjs`):join(i.workflowBuildDir,`workflows.mjs`):void 0,d=r.options.dev&&u!==void 0?[{bundlePath:u,queuePrefix:`__wkf_workflow_`}]:[],f=d.length>0?normalizeEsmImportSpecifier(resolveWorkflowModulePath(`workflow/runtime`)):void 0;u&&await addWorkflowFileHandler(r,{bundleName:`workflows`,bundlePath:u,directHandlers:d,route:`/.well-known/workflow/v1/flow`,runtimeImportSpecifier:f}),r.routing.sync()}export{configureNitroRoutes};
4
+ `)}async function configureNitroRoutes(i,a,o){if(includesWorkflowBundles(o.surface)){let e=resolvePackageRoot(),t=new WorkflowBundleBuilder({appRoot:a.appRoot,compiledArtifactsBootstrapPath:a.compiledArtifacts.bootstrapPath,outDir:a.workflowBuildDir,rootDir:e,watch:i.options.dev}),n=Promise.resolve(),buildWorkflowArtifacts=async()=>{await t.build({nitroStepOutfile:includesWorkflowRoute(o.surface)?join(resolveNitroWorkflowBuildDirectory(i),`steps.mjs`):void 0,nitroWorkflowOutfile:i.options.dev&&includesWorkflowRoute(o.surface)?join(resolveNitroWorkflowBuildDirectory(i),`workflows.mjs`):void 0})},syncWorkflowArtifacts=async()=>{let e=n.then(buildWorkflowArtifacts);n=e.catch(()=>{}),await e},r=!0;await syncWorkflowArtifacts(),i.hooks.hook(`build:before`,async()=>{if(r){r=!1;return}await syncWorkflowArtifacts()}),i.options.dev&&i.hooks.hook(`dev:reload`,async()=>{await syncWorkflowArtifacts()})}let s=createNitroArtifactsConfig({appRoot:a.appRoot,dev:i.options.dev});includesApplicationRoutes(o.surface)&&(registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/index.ts`),method:`GET`,route:`/`}),registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/health.ts`),method:`GET`,route:ASH_HEALTH_ROUTE_PATH}),addFrameworkVirtualHandler(i,{args:JSON.stringify({appRoot:s.appRoot}),handlerExport:`handleAgentInfoRequest`,method:`GET`,modulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/info.ts`),route:ASH_INFO_ROUTE_PATH}),registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-runs.ts`),method:`GET`,route:WORKFLOW_RUNS_API_ROUTE_PATH}),registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run.ts`),method:`GET`,route:WORKFLOW_RUN_ROUTE_PATTERN}),registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run-steps.ts`),method:`GET`,route:WORKFLOW_RUN_STEPS_ROUTE_PATTERN}),registerHandler(i,{handlerPath:resolvePackageSourceFilePath(`src/internal/nitro/routes/workflow-run-events.ts`),method:`GET`,route:WORKFLOW_RUN_EVENTS_ROUTE_PATTERN}),registerChannelVirtualHandlers(i,{artifactsConfig:s,registrations:computeChannelRouteRegistrations(a)}),i.options.dev&&(addFrameworkVirtualHandler(i,{args:JSON.stringify({appRoot:s.appRoot}),handlerExport:`handleDevRuntimeArtifactsRequest`,method:`GET`,modulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/dev-runtime-artifacts.ts`),route:ASH_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}),addFrameworkVirtualHandler(i,{args:JSON.stringify({appRoot:s.appRoot}),handlerExport:`handleDevScheduleDispatchRequest`,method:`POST`,modulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/dev-schedule-dispatch.ts`),route:ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN})));let l=resolveNitroWorkflowBuildDirectory(i),u=includesWorkflowRoute(o.surface)?i.options.dev?join(l,`workflows.mjs`):join(a.workflowBuildDir,`workflows.mjs`):void 0,d=i.options.dev&&u!==void 0?[{bundlePath:u,queuePrefix:`__wkf_workflow_`}]:[],f=d.length>0?normalizeEsmImportSpecifier(resolveWorkflowModulePath(`workflow/runtime`)):void 0;u&&await addWorkflowFileHandler(i,{bundleName:`workflows`,bundlePath:u,directHandlers:d,route:`/.well-known/workflow/v1/flow`,runtimeImportSpecifier:f}),i.routing.sync()}export{configureNitroRoutes};
@@ -1 +1 @@
1
- import{dirname,isAbsolute,join,relative,resolve}from"node:path";import{readFile}from"node:fs/promises";import{resolveNitroBuildDirectory}from"#internal/application/paths.js";import{resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath}from"#internal/application/package.js";import{resolveCodeModeEnabled}from"#shared/code-mode.js";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";import{createNitro}from"nitro/builder";import{prepareAshVersionedCacheDirectory,writeAshVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{createCompiledSandboxBackendPrunePlugin}from"#internal/nitro/host/compiled-sandbox-backend-prune-plugin.js";import{configureNitroRoutes}from"#internal/nitro/host/configure-nitro-routes.js";import{applyAshCronHandlerRoute}from"#internal/nitro/host/cron-handler-route.js";import{createNitroBundlerConfig}from"#internal/nitro/host/nitro-bundler-config.js";import{addNitroRoutingImportSpecifierPlugin}from"#internal/nitro/host/nitro-routing-import-specifier-plugin.js";import{registerScheduleTaskHandlers}from"#internal/nitro/host/schedule-task-routes.js";import{SERVER_EXTERNAL_PACKAGES}from"#internal/nitro/host/server-external-packages.js";import{createAshVercelOptions}from"#internal/nitro/host/vercel-build-output-config.js";import{applyWorkflowTransform}from"#internal/workflow-bundle/workflow-builders.js";import{transformDynamicToolExecute}from"#internal/workflow-bundle/dynamic-tool-transform.js";const WORKFLOW_ALIAS_SPECIFIERS=[`workflow`,`workflow/api`,`workflow/errors`,`workflow/internal/builtins`,`workflow/internal/private`,`workflow/runtime`],WORKFLOW_TRANSFORM_PATCHED=Symbol(`ash.workflow-transform-patched`),FRAMEWORK_HOSTED_EXTERNAL_PACKAGES=[`@napi-rs/keyring`];function resolveWorkflowAliases(){let e={};for(let t of WORKFLOW_ALIAS_SPECIFIERS)e[t]=resolveWorkflowModulePath(t);return e}function resolveNitroPreset(e){if(!e&&process.env.VERCEL)return`vercel`}function includesApplicationSurface(e){return e===`all`||e===`app`}function includesWorkflowSurface(e){return e===`all`||e===`flow`}function includesWorkflowStepRegistrations(e){return includesWorkflowSurface(e)}function manifestEnablesCodeMode(e){return[e.config,...e.subagents.map(e=>e.agent.config)].some(e=>resolveCodeModeEnabled(e.experimental?.codeMode))}function manifestHasWebSocketChannel(e){return e.channels.some(e=>e.kind===`channel`&&e.method===`WEBSOCKET`)}function resolveWorkflowStepEntrypointPath(e,t){return e.options.dev?join(e.options.buildDir,`workflow`,`steps.mjs`):join(t.workflowBuildDir,`steps.mjs`)}function collectHostedTraceDependencies(e){let t=e.compileResult.manifest.config.build;return[...new Set([...FRAMEWORK_HOSTED_EXTERNAL_PACKAGES,...SERVER_EXTERNAL_PACKAGES,...t?.externalDependencies??[]])].filter(e=>e!==ASH_PACKAGE_NAME)}function normalizePath(e){return e.replaceAll(`\\`,`/`)}function stripPathQueryAndHash(e){let t=e.indexOf(`?`),n=e.indexOf(`#`),r=t===-1?n:n===-1?t:Math.min(t,n);return r===-1?e:e.slice(0,r)}function stripFileSystemPrefix(e){return e.startsWith(`/@fs/`)?e.slice(4):e}function resolveNitroModuleComparisonPath(e,n){return n.startsWith(`file://`)?normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(fileURLToPath(n)))):isAbsolute(n)?normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(n))):normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(resolve(e,n))))}function isWorkflowBundlePath(e,t){let n=normalizePath(e);return n.startsWith(t)||n.includes(`/.ash/workflow-cache/`)}function normalizeStepTransformComparisonPath(e){let t=normalizePath(e);return process.platform===`win32`?t.toLowerCase():t}function parseImportedModuleSpecifiers(e){let t=/^\s*import\s+(?:.+?\s+from\s+)?["']([^"']+)["'];?\s*$/gm,n=[];for(let r of e.matchAll(t)){let e=r[1];e!==void 0&&n.push(e)}return n}function resolveNitroImportPath(t,n,r){return n.startsWith(`workflow`)?resolveWorkflowModulePath(n):n.startsWith(`.`)||n.startsWith(`/`)||n.startsWith(`file://`)?resolveNitroModuleComparisonPath(r===void 0?t:dirname(resolveNitroModuleComparisonPath(t,r)),n):null}async function collectNitroStepTransformTargets(e,t){let n=await readFile(e,`utf8`),r=new Set;for(let i of parseImportedModuleSpecifiers(n)){let n=resolveNitroImportPath(t,i,e);n!==null&&r.add(normalizeStepTransformComparisonPath(n))}return r}async function addNitroStepNoExternals(e,t){if(e.options.noExternals===!0)return;let n;try{n=await collectNitroStepTransformTargets(t,e.options.rootDir)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}let r=Array.isArray(e.options.noExternals)?[...e.options.noExternals]:[];e.options.noExternals=[...new Set([...r,...n])]}function createRelativeTransformFilename(e,t){let n=normalizePath(e).replace(/\/$/,``),i=normalizePath(t),a=n.toLowerCase(),o=i.toLowerCase();if(o.startsWith(`${a}/`))return i.slice(n.length+1);if(o===a)return`.`;let s=relative(n,i).replaceAll(`\\`,`/`);if(s.startsWith(`../`)&&(s=s.split(`/`).filter(e=>e!==`..`).join(`/`)),s.includes(`:`)||s.startsWith(`/`)){let e=i.split(`/`).pop();return e===void 0||e.length===0?`unknown.ts`:e}return s}function addWorkflowModuleSideEffectsPlugin(e,t){let r=[t,join(e.options.buildDir,`workflow`)].map(t=>resolveNitroModuleComparisonPath(e.options.rootDir,t));e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({name:`ash:workflow-module-side-effects`,resolveId(t,n){let i=resolveNitroImportPath(e.options.rootDir,t,n)??resolveNitroModuleComparisonPath(e.options.rootDir,t);return r.some(e=>isWorkflowBundlePath(i,e))?{id:i,moduleSideEffects:`no-treeshake`}:null}})})}function addNitroStepModuleSideEffectsPlugin(e,t){let n=null,getStepTransformTargets=async()=>(n===null&&(n=await collectNitroStepTransformTargets(t.stepEntrypointPath,e.options.rootDir)),n);e.hooks.hook(`build:before`,()=>{n=null}),e.options.dev&&e.hooks.hook(`dev:reload`,()=>{n=null}),e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({name:`ash:workflow-step-module-side-effects`,async resolveId(t,n){let r=resolveNitroImportPath(e.options.rootDir,t,n);return r===null||!(await getStepTransformTargets()).has(normalizeStepTransformComparisonPath(r))?null:{id:r,moduleSideEffects:`no-treeshake`}}})})}function addNitroStepTransformPlugin(e,t){let n=null,getStepTransformTargets=async()=>(n===null&&(n=await collectNitroStepTransformTargets(t.stepEntrypointPath,e.options.rootDir)),n);e.hooks.hook(`build:before`,()=>{n=null}),e.options.dev&&e.hooks.hook(`dev:reload`,()=>{n=null}),e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({async transform(t,n){let r=await getStepTransformTargets(),i=resolveNitroModuleComparisonPath(e.options.rootDir,n);return r.has(normalizeStepTransformComparisonPath(i))?{code:(await applyWorkflowTransform(createRelativeTransformFilename(e.options.rootDir,i),t,`step`,i,e.options.rootDir)).code,map:null}:null},name:`ash:workflow-step-transform`})})}function addDynamicToolTransformPlugin(e){e.hooks.hook(`rollup:before`,(e,t)=>{Array.isArray(t.plugins)&&t.plugins.unshift({async transform(e,t){if(!t.includes(`/tools/`))return null;let n=await transformDynamicToolExecute(t,e);return n===null?null:{code:n.code,map:null}},name:`ash:dynamic-tool-transform`})})}function addInstrumentationModuleSideEffectsPlugin(e,t){let n=normalizePath(t);e.hooks.hook(`rollup:before`,(e,t)=>{Array.isArray(t.plugins)&&t.plugins.unshift({name:`ash:instrumentation-module-side-effects`,resolveId(e){return normalizePath(e)===n?{id:e,moduleSideEffects:`no-treeshake`}:null}})})}function patchWorkflowTransformExcludePath(e,t){let n=normalizePath(t);e.hooks.hook(`rollup:before`,(e,t)=>{if(Array.isArray(t.plugins))for(let e of t.plugins){if(typeof e!=`object`||!e)continue;let t=e;if(t.name!==`workflow:transform`||t[WORKFLOW_TRANSFORM_PATCHED]===!0||typeof t.transform!=`function`)continue;let r=t.transform;t.transform=function(e,t,...i){return isWorkflowBundlePath(t,n)?null:r.call(this,e,t,...i)},t[WORKFLOW_TRANSFORM_PATCHED]=!0}})}async function createApplicationNitro(e,t,r={}){let i=r.surface??`all`,a=!t&&includesApplicationSurface(i)&&e.scheduleRegistrations.length>0,c=resolveNitroPreset(t),l=c===`vercel`?createCompiledSandboxBackendPrunePlugin():null,u=l===null?[]:[l],d=createNitroBundlerConfig(u),f=createNitroBundlerConfig(u),p=collectHostedTraceDependencies(e),m=resolveNitroBuildDirectory(e.appRoot,i),h=includesApplicationSurface(i)&&(t||manifestHasWebSocketChannel(e.compileResult.manifest)),g=[];manifestEnablesCodeMode(e.compileResult.manifest)&&g.push(resolvePackageSourceFilePath(`src/internal/nitro/host/code-mode-runtime-dependency-plugin.ts`)),e.compiledArtifacts.instrumentationPluginPath!==void 0&&g.push(e.compiledArtifacts.instrumentationPluginPath),g.push(e.compiledArtifacts.bootstrapPath),await prepareAshVersionedCacheDirectory(m);let _=await createNitro({_cli:{command:t?`dev`:`build`},buildDir:m,dev:t,features:{websocket:h},logLevel:t?1:void 0,output:r.outputDir===void 0?void 0:{dir:r.outputDir},preset:c,plugins:g,publicAssets:[],scanDirs:includesWorkflowStepRegistrations(i)?[resolvePackageSourceDirectoryPath(`src/execution`)]:void 0,rolldownConfig:d,rollupConfig:f,rootDir:e.appRoot,serverDir:!1,traceDeps:p,vercel:createAshVercelOptions(c===`vercel`&&includesApplicationSurface(i))},t?{watch:!0}:void 0);if(await writeAshVersionedCacheMetadata(m),addNitroRoutingImportSpecifierPlugin(_),includesWorkflowSurface(i)){let t=resolveWorkflowAliases();for(let[e,n]of Object.entries(t))_.options.alias[e]=n;addWorkflowModuleSideEffectsPlugin(_,e.workflowBuildDir),patchWorkflowTransformExcludePath(_,e.workflowBuildDir)}if(includesWorkflowStepRegistrations(i)){let t=resolveWorkflowStepEntrypointPath(_,e);addNitroStepModuleSideEffectsPlugin(_,{stepEntrypointPath:t}),addNitroStepTransformPlugin(_,{stepEntrypointPath:t})}if(addDynamicToolTransformPlugin(_),e.compiledArtifacts.instrumentationSourcePath!==void 0&&addInstrumentationModuleSideEffectsPlugin(_,e.compiledArtifacts.instrumentationSourcePath),t&&includesWorkflowSurface(i)){let t=e.workflowBuildDir,r=new Set([normalizePath(join(t,`workflows.mjs`))]);_.hooks.hook(`rollup:before`,(e,t)=>{let n=t.external;t.external=(e,...t)=>{if(r.has(normalizePath(e)))return!0;if(typeof n==`function`)return n(e,...t)}})}return a&&(applyAshCronHandlerRoute(_),registerScheduleTaskHandlers(_,{artifactsConfig:createNitroArtifactsConfig({appRoot:e.appRoot,dev:_.options.dev}),dispatchModulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/schedule-task.ts`),registrations:e.scheduleRegistrations})),await configureNitroRoutes(_,e,{surface:i}),includesWorkflowStepRegistrations(i)&&await addNitroStepNoExternals(_,resolveWorkflowStepEntrypointPath(_,e)),_}export{createApplicationNitro};
1
+ import{dirname,isAbsolute,join,relative,resolve}from"node:path";import{readFile}from"node:fs/promises";import{resolveNitroBuildDirectory}from"#internal/application/paths.js";import{resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath}from"#internal/application/package.js";import{resolveCodeModeEnabled}from"#shared/code-mode.js";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";import{createNitro}from"nitro/builder";import{prepareAshVersionedCacheDirectory,writeAshVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{createCompiledSandboxBackendPrunePlugin}from"#internal/nitro/host/compiled-sandbox-backend-prune-plugin.js";import{configureNitroRoutes}from"#internal/nitro/host/configure-nitro-routes.js";import{applyAshCronHandlerRoute}from"#internal/nitro/host/cron-handler-route.js";import{createNitroBundlerConfig}from"#internal/nitro/host/nitro-bundler-config.js";import{addNitroRoutingImportSpecifierPlugin}from"#internal/nitro/host/nitro-routing-import-specifier-plugin.js";import{registerScheduleTaskHandlers}from"#internal/nitro/host/schedule-task-routes.js";import{SERVER_EXTERNAL_PACKAGES}from"#internal/nitro/host/server-external-packages.js";import{createAshVercelOptions}from"#internal/nitro/host/vercel-build-output-config.js";import{applyWorkflowTransform}from"#internal/workflow-bundle/workflow-builders.js";import{transformDynamicToolExecute}from"#internal/workflow-bundle/dynamic-tool-transform.js";const WORKFLOW_ALIAS_SPECIFIERS=[`workflow`,`workflow/api`,`workflow/errors`,`workflow/internal/builtins`,`workflow/internal/private`,`workflow/runtime`],WORKFLOW_TRANSFORM_PATCHED=Symbol(`ash.workflow-transform-patched`),FRAMEWORK_HOSTED_EXTERNAL_PACKAGES=[`@napi-rs/keyring`];function resolveWorkflowAliases(){let e={};for(let t of WORKFLOW_ALIAS_SPECIFIERS)e[t]=resolveWorkflowModulePath(t);return e}function resolveNitroPreset(e){if(!e&&process.env.VERCEL)return`vercel`}function includesApplicationSurface(e){return e===`all`||e===`app`}function includesWorkflowSurface(e){return e===`all`||e===`flow`}function includesWorkflowStepRegistrations(e){return includesWorkflowSurface(e)}function manifestEnablesCodeMode(e){return[e.config,...e.subagents.map(e=>e.agent.config)].some(e=>resolveCodeModeEnabled(e.experimental?.codeMode))}function manifestHasWebSocketChannel(e){return e.channels.some(e=>e.kind===`channel`&&e.method===`WEBSOCKET`)}function resolveWorkflowStepEntrypointPath(e,t){return e.options.dev?join(e.options.buildDir,`workflow`,`steps.mjs`):join(t.workflowBuildDir,`steps.mjs`)}function collectHostedTraceDependencies(e){let t=e.compileResult.manifest.config.build;return[...new Set([...FRAMEWORK_HOSTED_EXTERNAL_PACKAGES,...SERVER_EXTERNAL_PACKAGES,...t?.externalDependencies??[]])].filter(e=>e!==ASH_PACKAGE_NAME)}function createDevelopmentWatchOptions(e){if(e.length!==0)return{ignored:[e,join(e,`**`)]}}function normalizePath(e){return e.replaceAll(`\\`,`/`)}function stripPathQueryAndHash(e){let t=e.indexOf(`?`),n=e.indexOf(`#`),r=t===-1?n:n===-1?t:Math.min(t,n);return r===-1?e:e.slice(0,r)}function stripFileSystemPrefix(e){return e.startsWith(`/@fs/`)?e.slice(4):e}function resolveNitroModuleComparisonPath(e,n){return n.startsWith(`file://`)?normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(fileURLToPath(n)))):isAbsolute(n)?normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(n))):normalizePath(stripFileSystemPrefix(stripPathQueryAndHash(resolve(e,n))))}function isWorkflowBundlePath(e,t){let n=normalizePath(e);return n.startsWith(t)||n.includes(`/.ash/workflow-cache/`)}function normalizeStepTransformComparisonPath(e){let t=normalizePath(e);return process.platform===`win32`?t.toLowerCase():t}function parseImportedModuleSpecifiers(e){let t=/^\s*import\s+(?:.+?\s+from\s+)?["']([^"']+)["'];?\s*$/gm,n=[];for(let r of e.matchAll(t)){let e=r[1];e!==void 0&&n.push(e)}return n}function resolveNitroImportPath(t,n,r){return n.startsWith(`workflow`)?resolveWorkflowModulePath(n):n.startsWith(`.`)||n.startsWith(`/`)||n.startsWith(`file://`)?resolveNitroModuleComparisonPath(r===void 0?t:dirname(resolveNitroModuleComparisonPath(t,r)),n):null}async function collectNitroStepTransformTargets(e,t){let n=await readFile(e,`utf8`),r=new Set;for(let i of parseImportedModuleSpecifiers(n)){let n=resolveNitroImportPath(t,i,e);n!==null&&r.add(normalizeStepTransformComparisonPath(n))}return r}async function addNitroStepNoExternals(e,t){if(e.options.noExternals===!0)return;let n;try{n=await collectNitroStepTransformTargets(t,e.options.rootDir)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}let r=Array.isArray(e.options.noExternals)?[...e.options.noExternals]:[];e.options.noExternals=[...new Set([...r,...n])]}function createRelativeTransformFilename(e,t){let n=normalizePath(e).replace(/\/$/,``),i=normalizePath(t),a=n.toLowerCase(),o=i.toLowerCase();if(o.startsWith(`${a}/`))return i.slice(n.length+1);if(o===a)return`.`;let s=relative(n,i).replaceAll(`\\`,`/`);if(s.startsWith(`../`)&&(s=s.split(`/`).filter(e=>e!==`..`).join(`/`)),s.includes(`:`)||s.startsWith(`/`)){let e=i.split(`/`).pop();return e===void 0||e.length===0?`unknown.ts`:e}return s}function addWorkflowModuleSideEffectsPlugin(e,t){let r=[t,join(e.options.buildDir,`workflow`)].map(t=>resolveNitroModuleComparisonPath(e.options.rootDir,t));e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({name:`ash:workflow-module-side-effects`,resolveId(t,n){let i=resolveNitroImportPath(e.options.rootDir,t,n)??resolveNitroModuleComparisonPath(e.options.rootDir,t);return r.some(e=>isWorkflowBundlePath(i,e))?{id:i,moduleSideEffects:`no-treeshake`}:null}})})}function addNitroStepModuleSideEffectsPlugin(e,t){let n=null,getStepTransformTargets=async()=>(n===null&&(n=await collectNitroStepTransformTargets(t.stepEntrypointPath,e.options.rootDir)),n);e.hooks.hook(`build:before`,()=>{n=null}),e.options.dev&&e.hooks.hook(`dev:reload`,()=>{n=null}),e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({name:`ash:workflow-step-module-side-effects`,async resolveId(t,n){let r=resolveNitroImportPath(e.options.rootDir,t,n);return r===null||!(await getStepTransformTargets()).has(normalizeStepTransformComparisonPath(r))?null:{id:r,moduleSideEffects:`no-treeshake`}}})})}function addNitroStepTransformPlugin(e,t){let n=null,getStepTransformTargets=async()=>(n===null&&(n=await collectNitroStepTransformTargets(t.stepEntrypointPath,e.options.rootDir)),n);e.hooks.hook(`build:before`,()=>{n=null}),e.options.dev&&e.hooks.hook(`dev:reload`,()=>{n=null}),e.hooks.hook(`rollup:before`,(t,n)=>{Array.isArray(n.plugins)&&n.plugins.unshift({async transform(t,n){let r=await getStepTransformTargets(),i=resolveNitroModuleComparisonPath(e.options.rootDir,n);return r.has(normalizeStepTransformComparisonPath(i))?{code:(await applyWorkflowTransform(createRelativeTransformFilename(e.options.rootDir,i),t,`step`,i,e.options.rootDir)).code,map:null}:null},name:`ash:workflow-step-transform`})})}function addDynamicToolTransformPlugin(e){e.hooks.hook(`rollup:before`,(e,t)=>{Array.isArray(t.plugins)&&t.plugins.unshift({async transform(e,t){if(!t.includes(`/tools/`))return null;let n=await transformDynamicToolExecute(t,e);return n===null?null:{code:n.code,map:null}},name:`ash:dynamic-tool-transform`})})}function addInstrumentationModuleSideEffectsPlugin(e,t){let n=normalizePath(t);e.hooks.hook(`rollup:before`,(e,t)=>{Array.isArray(t.plugins)&&t.plugins.unshift({name:`ash:instrumentation-module-side-effects`,resolveId(e){return normalizePath(e)===n?{id:e,moduleSideEffects:`no-treeshake`}:null}})})}function patchWorkflowTransformExcludePath(e,t){let n=normalizePath(t);e.hooks.hook(`rollup:before`,(e,t)=>{if(Array.isArray(t.plugins))for(let e of t.plugins){if(typeof e!=`object`||!e)continue;let t=e;if(t.name!==`workflow:transform`||t[WORKFLOW_TRANSFORM_PATCHED]===!0||typeof t.transform!=`function`)continue;let r=t.transform;t.transform=function(e,t,...i){return isWorkflowBundlePath(t,n)?null:r.call(this,e,t,...i)},t[WORKFLOW_TRANSFORM_PATCHED]=!0}})}async function createApplicationNitro(e,t,r={}){let i=r.surface??`all`,a=!t&&includesApplicationSurface(i)&&e.scheduleRegistrations.length>0,c=resolveNitroPreset(t),l=c===`vercel`?createCompiledSandboxBackendPrunePlugin():null,u=l===null?[]:[l],d=createNitroBundlerConfig(u),f=createNitroBundlerConfig(u),p=collectHostedTraceDependencies(e),m=resolveNitroBuildDirectory(e.appRoot,i),h=includesApplicationSurface(i)&&(t||manifestHasWebSocketChannel(e.compileResult.manifest)),g=[];manifestEnablesCodeMode(e.compileResult.manifest)&&g.push(resolvePackageSourceFilePath(`src/internal/nitro/host/code-mode-runtime-dependency-plugin.ts`)),e.compiledArtifacts.instrumentationPluginPath!==void 0&&g.push(e.compiledArtifacts.instrumentationPluginPath),g.push(e.compiledArtifacts.bootstrapPath),await prepareAshVersionedCacheDirectory(m);let _=await createNitro({_cli:{command:t?`dev`:`build`},buildDir:m,dev:t,features:{websocket:h},logLevel:t?1:void 0,output:r.outputDir===void 0?void 0:{dir:r.outputDir},preset:c,plugins:g,publicAssets:[],scanDirs:includesWorkflowStepRegistrations(i)?[resolvePackageSourceDirectoryPath(`src/execution`)]:void 0,rolldownConfig:d,rollupConfig:f,rootDir:e.appRoot,serverDir:!1,traceDeps:p,vercel:createAshVercelOptions(c===`vercel`&&includesApplicationSurface(i)),watchOptions:t?createDevelopmentWatchOptions(e.appRoot):void 0},t?{watch:!0}:void 0);if(await writeAshVersionedCacheMetadata(m),addNitroRoutingImportSpecifierPlugin(_),includesWorkflowSurface(i)){let t=resolveWorkflowAliases();for(let[e,n]of Object.entries(t))_.options.alias[e]=n;addWorkflowModuleSideEffectsPlugin(_,e.workflowBuildDir),patchWorkflowTransformExcludePath(_,e.workflowBuildDir)}if(includesWorkflowStepRegistrations(i)){let t=resolveWorkflowStepEntrypointPath(_,e);addNitroStepModuleSideEffectsPlugin(_,{stepEntrypointPath:t}),addNitroStepTransformPlugin(_,{stepEntrypointPath:t})}if(addDynamicToolTransformPlugin(_),e.compiledArtifacts.instrumentationSourcePath!==void 0&&addInstrumentationModuleSideEffectsPlugin(_,e.compiledArtifacts.instrumentationSourcePath),t&&includesWorkflowSurface(i)){let t=e.workflowBuildDir,r=new Set([normalizePath(join(t,`workflows.mjs`))]);_.hooks.hook(`rollup:before`,(e,t)=>{let n=t.external;t.external=(e,...t)=>{if(r.has(normalizePath(e)))return!0;if(typeof n==`function`)return n(e,...t)}})}return a&&(applyAshCronHandlerRoute(_),registerScheduleTaskHandlers(_,{artifactsConfig:createNitroArtifactsConfig({appRoot:e.appRoot,dev:_.options.dev}),dispatchModulePath:resolvePackageSourceFilePath(`src/internal/nitro/routes/schedule-task.ts`),registrations:e.scheduleRegistrations})),await configureNitroRoutes(_,e,{surface:i}),includesWorkflowStepRegistrations(i)&&await addNitroStepNoExternals(_,resolveWorkflowStepEntrypointPath(_,e)),_}export{createApplicationNitro};
@@ -1 +1 @@
1
- import{createRequire}from"node:module";import{dirname,isAbsolute,join,resolve}from"node:path";import{readFile,readdir}from"node:fs/promises";import{existsSync}from"node:fs";import{toErrorMessage}from"#shared/errors.js";import{getDevelopmentEnvironmentFilePaths,loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{clearCompiledRuntimeAgentBundleCache}from"#runtime/sessions/compiled-agent-cache.js";import{parse}from"#compiled/jsonc-parser/index.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{computeChannelRouteRegistrations,syncChannelVirtualHandlers}from"#internal/nitro/host/channel-routes.js";import{watch}from"#compiled/chokidar/index.js";import{prewarmAppSandboxes}from"#execution/sandbox/prewarm.js";const WATCHED_LOCKFILE_NAMES=[`pnpm-lock.yaml`,`package-lock.json`,`yarn.lock`,`bun.lock`,`bun.lockb`],WATCH_ROOT_MARKER_NAMES=[`.git`,`pnpm-workspace.yaml`],WATCHER_IGNORED_PATTERNS=[`**/.ash/**`,`**/.git/**`,`**/.output/**`,`**/.turbo/**`,`**/.vercel/**`,`**/.workflow-data/**`,`**/node_modules/**`];async function startAuthoredSourceWatcher(e){let t=e.preparedHost,n=!1,r=Promise.resolve(),i,a=new Set,o=new Set,s=await resolveAuthoredWatchPaths(t),c=createWatchPathMap(s),l=watch(s,{awaitWriteFinish:{pollInterval:50,stabilityThreshold:160},followSymlinks:!1,ignoreInitial:!0,ignored:WATCHER_IGNORED_PATTERNS}),d=waitForWatcherReady(l),flush=()=>{n||(r=r.then(async()=>{if(n)return;let r=a.size,i=[...o];a.clear(),o.clear();let s=t,u=hasDevelopmentEnvironmentFileChange(s.appRoot,i);console.log(`[ash:dev] change detected (${r} event${r===1?``:`s`}), rebuilding authored artifacts...`);try{u&&loadDevelopmentEnvironmentFiles(s.appRoot);let n=await prepareApplicationHost(s.appRoot);await prewarmAppSandboxes({appRoot:n.appRoot,log:e=>console.log(e)});let r=createNitroArtifactsConfig({appRoot:n.appRoot,dev:e.nitro.options.dev===!0}),i=syncChannelVirtualHandlers(e.nitro,{artifactsConfig:r,next:computeChannelRouteRegistrations(n),previous:computeChannelRouteRegistrations(s)});clearCompiledRuntimeAgentBundleCache(),t=n,i||u?(console.log(`[ash:dev] structural change detected, reloading Nitro worker...`),await e.nitro.hooks.callHook(`rollup:reload`)):console.log(`[ash:dev] authored artifacts updated.`),c=syncWatcherPaths({nextWatchPaths:await resolveAuthoredWatchPaths(n),previousWatchPathsByKey:c,watcher:l})}catch(e){console.error(`[ash:dev] rebuild failed: ${toErrorMessage(e)}`)}}).catch(e=>{console.error(`[ash:dev] rebuild queue error: ${toErrorMessage(e)}`)}))};return l.on(`all`,(e,t)=>{n||(a.add(`${e}:${t}`),o.add(t),i!==void 0&&clearTimeout(i),i=setTimeout(()=>{i=void 0,flush()},120))}),await d,{async close(){n=!0,i!==void 0&&(clearTimeout(i),i=void 0),await l.close(),await r}}}async function waitForWatcherReady(e){await new Promise((t,n)=>{e.on(`ready`,()=>{t()}),e.on(`error`,e=>{n(e)})})}async function resolveAuthoredWatchPaths(e){let t=new Set([e.compileResult.project.agentRoot,join(e.appRoot,`package.json`),join(e.appRoot,`jsconfig.json`),join(e.appRoot,`tsconfig.json`),join(e.appRoot,`tsconfig.*.json`)]),n=await resolveTsConfigWatchPaths(e.appRoot);for(let n of getDevelopmentEnvironmentFilePaths(e.appRoot))t.add(n);for(let e of n)t.add(e);for(let n of resolveLockfileSearchDirectories(e.appRoot))for(let e of WATCHED_LOCKFILE_NAMES)t.add(join(n,e));return[...t].sort((e,t)=>e.localeCompare(t))}function createWatchPathMap(e){let t=new Map;for(let n of e)t.set(toWatchPathKey(n),n);return t}function syncWatcherPaths(e){let t=createWatchPathMap(e.nextWatchPaths),n=[],r=[];for(let[r,i]of t)e.previousWatchPathsByKey.has(r)||n.push(i);for(let[n,i]of e.previousWatchPathsByKey)t.has(n)||r.push(i);return n.length>0&&e.watcher.add(n),r.length>0&&e.watcher.unwatch(r),t}function toWatchPathKey(e){return e.replaceAll(`\\`,`/`)}function hasDevelopmentEnvironmentFileChange(e,t){let n=new Set(getDevelopmentEnvironmentFilePaths(e).map(e=>toWatchPathKey(resolve(e))));return t.some(e=>n.has(toWatchPathKey(resolve(e))))}function resolveLockfileSearchDirectories(e){let n=resolve(e),r=[n],a=n;for(;;){if(hasWatchRootMarker(a))return r;let e=dirname(a);if(e===a)return[n];a=e,r.push(a)}}function hasWatchRootMarker(e){return WATCH_ROOT_MARKER_NAMES.some(t=>existsSync(join(e,t)))}async function resolveTsConfigWatchPaths(e){let t=await resolveRootTsConfigPaths(e),n=new Set,r=new Set;for(let e of t)await collectTsConfigWatchPaths({configPath:e,resolvedConfigPaths:n,visitingConfigPaths:r});return[...n].sort((e,t)=>e.localeCompare(t))}async function resolveRootTsConfigPaths(e){let t=new Set([join(e,`tsconfig.json`),join(e,`jsconfig.json`)]);try{let n=await readdir(e,{withFileTypes:!0});for(let i of n)i.isFile()&&/^tsconfig\..+\.json$/i.test(i.name)&&t.add(join(e,i.name))}catch{}return[...t]}async function collectTsConfigWatchPaths(e){let t=resolve(e.configPath);if(e.resolvedConfigPaths.has(t)||e.visitingConfigPaths.has(t))return;let n=await readTextFileIfExists(t);if(n!==void 0){e.resolvedConfigPaths.add(t),e.visitingConfigPaths.add(t);try{let r=extractTsConfigExtendsSpecifiers(n);for(let n of r)for(let r of resolveTsConfigExtendsTargetPaths({configPath:t,extendsSpecifier:n}))await collectTsConfigWatchPaths({configPath:r,resolvedConfigPaths:e.resolvedConfigPaths,visitingConfigPaths:e.visitingConfigPaths})}finally{e.visitingConfigPaths.delete(t)}}}async function readTextFileIfExists(e){try{return await readFile(e,`utf8`)}catch{return}}function extractTsConfigExtendsSpecifiers(e){let t=[],n=parse(e,t,{allowTrailingComma:!0});if(t.length>0||typeof n!=`object`||!n||Array.isArray(n))return[];let r=n.extends;return typeof r==`string`?r.length>0?[r]:[]:Array.isArray(r)?r.filter(e=>typeof e==`string`&&e.length>0):[]}function resolveTsConfigExtendsTargetPaths(e){let t=new Set;if(isTsConfigFilePath(e.extendsSpecifier))for(let n of resolveFileExtendsCandidates({configPath:e.configPath,extendsSpecifier:e.extendsSpecifier}))t.add(n);else for(let n of resolvePackageExtendsCandidates({configPath:e.configPath,extendsSpecifier:e.extendsSpecifier}))t.add(n);return[...t]}function resolveFileExtendsCandidates(e){let n=resolve(dirname(e.configPath),e.extendsSpecifier),a=new Set;return a.add(n),n.endsWith(`.json`)||(a.add(`${n}.json`),a.add(join(n,`tsconfig.json`))),[...a]}function resolvePackageExtendsCandidates(t){let n=new Set([t.extendsSpecifier]);t.extendsSpecifier.endsWith(`.json`)||(n.add(`${t.extendsSpecifier}.json`),n.add(`${t.extendsSpecifier}/tsconfig.json`));let r=new Set,i=createRequire(t.configPath);for(let e of n)try{r.add(i.resolve(e))}catch{}return[...r]}function isTsConfigFilePath(e){return e.startsWith(`.`)||isAbsolute(e)?!0:/^[A-Za-z]:[\\/]/.test(e)}export{startAuthoredSourceWatcher};
1
+ import{createRequire}from"node:module";import{dirname,isAbsolute,join,resolve}from"node:path";import{readFile,readdir}from"node:fs/promises";import{existsSync}from"node:fs";import{toErrorMessage}from"#shared/errors.js";import{getDevelopmentEnvironmentFilePaths,loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{clearCompiledRuntimeAgentBundleCache}from"#runtime/sessions/compiled-agent-cache.js";import{parse}from"#compiled/jsonc-parser/index.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{computeChannelRouteRegistrations,syncChannelVirtualHandlers}from"#internal/nitro/host/channel-routes.js";import{watch}from"#compiled/chokidar/index.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{prewarmAppSandboxes}from"#execution/sandbox/prewarm.js";const WATCHED_LOCKFILE_NAMES=[`pnpm-lock.yaml`,`package-lock.json`,`yarn.lock`,`bun.lock`,`bun.lockb`],WATCH_ROOT_MARKER_NAMES=[`.git`,`pnpm-workspace.yaml`],WATCHER_IGNORED_PATTERNS=[`**/.ash/**`,`**/.git/**`,`**/.output/**`,`**/.turbo/**`,`**/.vercel/**`,`**/.workflow-data/**`,`**/node_modules/**`];async function startAuthoredSourceWatcher(e){let t=e.preparedHost,n=!1,r=Promise.resolve(),i,a=new Set,o=new Set,s=await resolveAuthoredWatchPaths(t),c=createWatchPathMap(s),l=watch(s,{awaitWriteFinish:{pollInterval:50,stabilityThreshold:160},followSymlinks:!1,ignoreInitial:!0,ignored:WATCHER_IGNORED_PATTERNS}),d=waitForWatcherReady(l),flush=()=>{n||(r=r.then(async()=>{if(n)return;let r=a.size,i=[...o];a.clear(),o.clear();let s=t,u=hasDevelopmentEnvironmentFileChange(s.appRoot,i);console.log(`[ash:dev] change detected (${r} event${r===1?``:`s`}), rebuilding authored artifacts...`);try{u&&loadDevelopmentEnvironmentFiles(s.appRoot);let n=await prepareApplicationHost(s.appRoot,{dev:e.nitro.options.dev===!0}),r=createNitroArtifactsConfig({appRoot:n.appRoot,dev:e.nitro.options.dev===!0});await prewarmAppSandboxes({appRoot:n.appRoot,compiledArtifactsSource:resolveNitroCompiledArtifactsSource(r),log:e=>console.log(e)});let i=syncChannelVirtualHandlers(e.nitro,{artifactsConfig:r,next:computeChannelRouteRegistrations(n),previous:computeChannelRouteRegistrations(s)});clearCompiledRuntimeAgentBundleCache(),t=n,i||u?(console.log(`[ash:dev] structural change detected, reloading Nitro worker...`),await e.nitro.hooks.callHook(`rollup:reload`)):console.log(`[ash:dev] authored artifacts updated.`),c=syncWatcherPaths({nextWatchPaths:await resolveAuthoredWatchPaths(n),previousWatchPathsByKey:c,watcher:l})}catch(e){console.error(`[ash:dev] rebuild failed: ${toErrorMessage(e)}`)}}).catch(e=>{console.error(`[ash:dev] rebuild queue error: ${toErrorMessage(e)}`)}))};return l.on(`all`,(e,t)=>{n||(a.add(`${e}:${t}`),o.add(t),i!==void 0&&clearTimeout(i),i=setTimeout(()=>{i=void 0,flush()},120))}),await d,{async close(){n=!0,i!==void 0&&(clearTimeout(i),i=void 0),await l.close(),await r}}}async function waitForWatcherReady(e){await new Promise((t,n)=>{e.on(`ready`,()=>{t()}),e.on(`error`,e=>{n(e)})})}async function resolveAuthoredWatchPaths(e){let t=new Set([e.compileResult.project.agentRoot,join(e.appRoot,`package.json`),join(e.appRoot,`jsconfig.json`),join(e.appRoot,`tsconfig.json`),join(e.appRoot,`tsconfig.*.json`)]),n=await resolveTsConfigWatchPaths(e.appRoot);for(let n of getDevelopmentEnvironmentFilePaths(e.appRoot))t.add(n);for(let e of n)t.add(e);for(let n of resolveLockfileSearchDirectories(e.appRoot))for(let e of WATCHED_LOCKFILE_NAMES)t.add(join(n,e));return[...t].sort((e,t)=>e.localeCompare(t))}function createWatchPathMap(e){let t=new Map;for(let n of e)t.set(toWatchPathKey(n),n);return t}function syncWatcherPaths(e){let t=createWatchPathMap(e.nextWatchPaths),n=[],r=[];for(let[r,i]of t)e.previousWatchPathsByKey.has(r)||n.push(i);for(let[n,i]of e.previousWatchPathsByKey)t.has(n)||r.push(i);return n.length>0&&e.watcher.add(n),r.length>0&&e.watcher.unwatch(r),t}function toWatchPathKey(e){return e.replaceAll(`\\`,`/`)}function hasDevelopmentEnvironmentFileChange(e,t){let n=new Set(getDevelopmentEnvironmentFilePaths(e).map(e=>toWatchPathKey(resolve(e))));return t.some(e=>n.has(toWatchPathKey(resolve(e))))}function resolveLockfileSearchDirectories(e){let n=resolve(e),r=[n],a=n;for(;;){if(hasWatchRootMarker(a))return r;let e=dirname(a);if(e===a)return[n];a=e,r.push(a)}}function hasWatchRootMarker(e){return WATCH_ROOT_MARKER_NAMES.some(t=>existsSync(join(e,t)))}async function resolveTsConfigWatchPaths(e){let t=await resolveRootTsConfigPaths(e),n=new Set,r=new Set;for(let e of t)await collectTsConfigWatchPaths({configPath:e,resolvedConfigPaths:n,visitingConfigPaths:r});return[...n].sort((e,t)=>e.localeCompare(t))}async function resolveRootTsConfigPaths(e){let t=new Set([join(e,`tsconfig.json`),join(e,`jsconfig.json`)]);try{let n=await readdir(e,{withFileTypes:!0});for(let i of n)i.isFile()&&/^tsconfig\..+\.json$/i.test(i.name)&&t.add(join(e,i.name))}catch{}return[...t]}async function collectTsConfigWatchPaths(e){let t=resolve(e.configPath);if(e.resolvedConfigPaths.has(t)||e.visitingConfigPaths.has(t))return;let n=await readTextFileIfExists(t);if(n!==void 0){e.resolvedConfigPaths.add(t),e.visitingConfigPaths.add(t);try{let r=extractTsConfigExtendsSpecifiers(n);for(let n of r)for(let r of resolveTsConfigExtendsTargetPaths({configPath:t,extendsSpecifier:n}))await collectTsConfigWatchPaths({configPath:r,resolvedConfigPaths:e.resolvedConfigPaths,visitingConfigPaths:e.visitingConfigPaths})}finally{e.visitingConfigPaths.delete(t)}}}async function readTextFileIfExists(e){try{return await readFile(e,`utf8`)}catch{return}}function extractTsConfigExtendsSpecifiers(e){let t=[],n=parse(e,t,{allowTrailingComma:!0});if(t.length>0||typeof n!=`object`||!n||Array.isArray(n))return[];let r=n.extends;return typeof r==`string`?r.length>0?[r]:[]:Array.isArray(r)?r.filter(e=>typeof e==`string`&&e.length>0):[]}function resolveTsConfigExtendsTargetPaths(e){let t=new Set;if(isTsConfigFilePath(e.extendsSpecifier))for(let n of resolveFileExtendsCandidates({configPath:e.configPath,extendsSpecifier:e.extendsSpecifier}))t.add(n);else for(let n of resolvePackageExtendsCandidates({configPath:e.configPath,extendsSpecifier:e.extendsSpecifier}))t.add(n);return[...t]}function resolveFileExtendsCandidates(e){let n=resolve(dirname(e.configPath),e.extendsSpecifier),a=new Set;return a.add(n),n.endsWith(`.json`)||(a.add(`${n}.json`),a.add(join(n,`tsconfig.json`))),[...a]}function resolvePackageExtendsCandidates(t){let n=new Set([t.extendsSpecifier]);t.extendsSpecifier.endsWith(`.json`)||(n.add(`${t.extendsSpecifier}.json`),n.add(`${t.extendsSpecifier}/tsconfig.json`));let r=new Set,i=createRequire(t.configPath);for(let e of n)try{r.add(i.resolve(e))}catch{}return[...r]}function isTsConfigFilePath(e){return e.startsWith(`.`)||isAbsolute(e)?!0:/^[A-Za-z]:[\\/]/.test(e)}export{startAuthoredSourceWatcher};
@@ -3,4 +3,6 @@ import type { PreparedApplicationHost } from "#internal/nitro/host/types.js";
3
3
  * Compiles one authored app and stages the package-owned artifacts needed by
4
4
  * the Nitro host.
5
5
  */
6
- export declare function prepareApplicationHost(startPath: string): Promise<PreparedApplicationHost>;
6
+ export declare function prepareApplicationHost(startPath: string, options?: {
7
+ readonly dev?: boolean;
8
+ }): Promise<PreparedApplicationHost>;
@@ -1 +1 @@
1
- import{resolveWorkflowBuildDirectory}from"#internal/application/paths.js";import{createAuthoredSourceRuntimeCompiledArtifactsSource}from"#internal/application/runtime-compiled-artifacts-source.js";import{createScheduleRegistrations}from"#runtime/schedules/register.js";import{loadResolvedCompiledSchedules}from"#runtime/schedules/resolve-schedule.js";import{compileAgent}from"#compiler/compile-agent.js";import{writeCompiledArtifactsFiles}from"#internal/application/compiled-artifacts.js";async function prepareApplicationHost(e){let t=await compileAgent({startPath:e}),n=await loadResolvedCompiledSchedules({compiledArtifactsSource:createAuthoredSourceRuntimeCompiledArtifactsSource(t.project.appRoot)}),r=createScheduleRegistrations(n),i=resolveWorkflowBuildDirectory(t.project.appRoot),a=await writeCompiledArtifactsFiles({compileResult:t,outDir:t.paths.compileDirectoryPath});return{appRoot:t.project.appRoot,compileResult:t,compiledArtifacts:a,scheduleRegistrations:r,schedules:n,workflowBuildDir:i}}export{prepareApplicationHost};
1
+ import{readFile}from"node:fs/promises";import{resolveWorkflowBuildDirectory}from"#internal/application/paths.js";import{createAuthoredSourceRuntimeCompiledArtifactsSource}from"#internal/application/runtime-compiled-artifacts-source.js";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{activateDevelopmentRuntimeArtifactsSnapshot,stageDevelopmentRuntimeArtifactsSnapshot}from"#internal/nitro/dev-runtime-artifacts.js";import{createScheduleRegistrations}from"#runtime/schedules/register.js";import{loadResolvedCompiledSchedules}from"#runtime/schedules/resolve-schedule.js";import{compileAgent}from"#compiler/compile-agent.js";import{writeCompiledArtifactsFiles}from"#internal/application/compiled-artifacts.js";async function prepareApplicationHost(e,t={}){let n=await compileAgent({startPath:e}),r=await loadResolvedCompiledSchedules({compiledArtifactsSource:createAuthoredSourceRuntimeCompiledArtifactsSource(n.project.appRoot)}),i=createScheduleRegistrations(r),a=resolveWorkflowBuildDirectory(n.project.appRoot),o=t.dev===!0?await stageDevelopmentRuntimeArtifactsSnapshot(n):n.project.appRoot,s=resolveRuntimeCompilerArtifactPaths(o),c=await writeCompiledArtifactsFiles({compileResult:t.dev===!0?{...n,manifest:JSON.parse(await readFile(s.compiledManifestPath,`utf8`))}:n,outDir:s.compileDirectoryPath});return t.dev===!0&&await activateDevelopmentRuntimeArtifactsSnapshot({appRoot:n.project.appRoot,snapshotRoot:o}),{appRoot:n.project.appRoot,compileResult:n,compiledArtifacts:c,scheduleRegistrations:i,schedules:r,workflowBuildDir:a}}export{prepareApplicationHost};
@@ -1 +1 @@
1
- import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{build,createDevServer,prepare}from"nitro/builder";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{prewarmAppSandboxes}from"#execution/sandbox/prewarm.js";const MAX_ALLOWED_DEVELOPMENT_SERVER_PORT=65535,WORKFLOW_LOCAL_BASE_URL_ENV=`WORKFLOW_LOCAL_BASE_URL`,PORT_ENV=`PORT`,WILDCARD_LISTEN_HOSTNAMES=new Set([`[::]`,`::`,`0.0.0.0`]);function normalizeDevelopmentServerClientUrl(e){let t=new URL(e);return WILDCARD_LISTEN_HOSTNAMES.has(t.hostname)?(t.hostname=`127.0.0.1`,t.toString()):e}function isAddressInUseError(e){return e instanceof Error&&`code`in e&&e.code===`EADDRINUSE`}function resolveDevelopmentServerPort(e){let t=typeof e==`string`?Number(e):e??3e3;if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid development server port "${String(e)}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}function readEnvironmentPort(){let e=process.env[PORT_ENV];if(e===void 0||e.trim()===``)return;let t=Number(e);if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid ${PORT_ENV} environment variable "${e}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}function resolveDevelopmentServerPorts(e){let t=resolveDevelopmentServerPort(e.port);if(t===0||!e.retryOnAddressInUse)return[t];let n=[];for(let e=0;e<10;e+=1){let r=t+e;if(r>65535)break;n.push(r)}return n}function installWorkflowLocalQueueEnvironment(e){let t=process.env[WORKFLOW_LOCAL_BASE_URL_ENV],n=process.env[PORT_ENV],r=new URL(normalizeDevelopmentServerClientUrl(e));return process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=r.origin,r.port&&(process.env[PORT_ENV]=r.port),()=>{t===void 0?delete process.env[WORKFLOW_LOCAL_BASE_URL_ENV]:process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=t,n===void 0?delete process.env[PORT_ENV]:process.env[PORT_ENV]=n}}function attachTemporarySocketErrorHandler(e){let onSocketError=()=>{};return e.once(`error`,onSocketError),()=>{e.off(`error`,onSocketError)}}function shouldProxyDevelopmentServerWebSocketUpgrades(e){return e.options.features.websocket===!0||e.options.experimental.websocket===!0}function guardDevelopmentServerWebSocketUpgrades(e,t){let n=t.upgrade.bind(t),r=shouldProxyDevelopmentServerWebSocketUpgrades(e);t.upgrade=async(e,t,i)=>{if(!r){t.destroyed||t.destroy();return}let a=attachTemporarySocketErrorHandler(t);try{await n(e,t,i)}catch{t.destroyed||t.destroy()}finally{a()}}}async function listenForDevelopmentServer(e){let t=resolveDevelopmentServerPorts({port:e.port,retryOnAddressInUse:e.retryOnAddressInUse}),n;for(let r of t){let t=e.devServer.listen({hostname:e.host,port:r,silent:!0});try{return await t.ready(),t}catch(r){if(n=r,await t.close().catch(()=>{}),!isAddressInUseError(r)||!e.retryOnAddressInUse)throw r}}throw Error(`Failed to start Nitro dev server after ${t.length} attempts. Tried ports ${t.join(`, `)}.`,{cause:n})}async function startDevelopmentServer(o,s={}){loadDevelopmentEnvironmentFiles(o);let c=await prepareApplicationHost(o);await prewarmAppSandboxes({appRoot:c.appRoot,log:e=>console.log(e)});let l=await createApplicationNitro(c,!0),u=createDevServer(l);guardDevelopmentServerWebSocketUpgrades(l,u);let d=s.host??l.options.devServer.hostname,f=s.port??readEnvironmentPort(),p=f??l.options.devServer.port,m=f===void 0,h,g;try{let e=await listenForDevelopmentServer({devServer:u,host:d,port:p,retryOnAddressInUse:m});if(!e.url)throw Error(`Nitro dev server did not expose a URL.`);h=installWorkflowLocalQueueEnvironment(e.url),await prepare(l),await build(l);let{startAuthoredSourceWatcher:n}=await import(`#internal/nitro/host/dev-authored-source-watcher.js`);g=await n({nitro:l,preparedHost:c});let i=h;if(i===void 0)throw Error(`Workflow local queue environment was not initialized.`);let a=g;return{async close(){try{await a.close(),await u.close(),await l.close()}finally{i()}},url:normalizeDevelopmentServerClientUrl(e.url)}}catch(e){throw await g?.close().catch(()=>{}),h?.(),await u.close().catch(()=>{}),await l.close().catch(()=>{}),e}}export{normalizeDevelopmentServerClientUrl,startDevelopmentServer};
1
+ import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{build,createDevServer,prepare}from"nitro/builder";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{prewarmAppSandboxes}from"#execution/sandbox/prewarm.js";const MAX_ALLOWED_DEVELOPMENT_SERVER_PORT=65535,WORKFLOW_LOCAL_BASE_URL_ENV=`WORKFLOW_LOCAL_BASE_URL`,PORT_ENV=`PORT`,WILDCARD_LISTEN_HOSTNAMES=new Set([`[::]`,`::`,`0.0.0.0`]);function normalizeDevelopmentServerClientUrl(e){let t=new URL(e);return WILDCARD_LISTEN_HOSTNAMES.has(t.hostname)?(t.hostname=`127.0.0.1`,t.toString()):e}function isAddressInUseError(e){return e instanceof Error&&`code`in e&&e.code===`EADDRINUSE`}function resolveDevelopmentServerPort(e){let t=typeof e==`string`?Number(e):e??3e3;if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid development server port "${String(e)}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}function readEnvironmentPort(){let e=process.env[PORT_ENV];if(e===void 0||e.trim()===``)return;let t=Number(e);if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid ${PORT_ENV} environment variable "${e}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}function resolveDevelopmentServerPorts(e){let t=resolveDevelopmentServerPort(e.port);if(t===0||!e.retryOnAddressInUse)return[t];let n=[];for(let e=0;e<10;e+=1){let r=t+e;if(r>65535)break;n.push(r)}return n}function installWorkflowLocalQueueEnvironment(e){let t=process.env[WORKFLOW_LOCAL_BASE_URL_ENV],n=process.env[PORT_ENV],r=new URL(normalizeDevelopmentServerClientUrl(e));return process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=r.origin,r.port&&(process.env[PORT_ENV]=r.port),()=>{t===void 0?delete process.env[WORKFLOW_LOCAL_BASE_URL_ENV]:process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=t,n===void 0?delete process.env[PORT_ENV]:process.env[PORT_ENV]=n}}function attachTemporarySocketErrorHandler(e){let onSocketError=()=>{};return e.once(`error`,onSocketError),()=>{e.off(`error`,onSocketError)}}function shouldProxyDevelopmentServerWebSocketUpgrades(e){return e.options.features.websocket===!0||e.options.experimental.websocket===!0}function guardDevelopmentServerWebSocketUpgrades(e,t){let n=t.upgrade.bind(t),r=shouldProxyDevelopmentServerWebSocketUpgrades(e);t.upgrade=async(e,t,i)=>{if(!r){t.destroyed||t.destroy();return}let a=attachTemporarySocketErrorHandler(t);try{await n(e,t,i)}catch{t.destroyed||t.destroy()}finally{a()}}}async function listenForDevelopmentServer(e){let t=resolveDevelopmentServerPorts({port:e.port,retryOnAddressInUse:e.retryOnAddressInUse}),n;for(let r of t){let t=e.devServer.listen({hostname:e.host,port:r,silent:!0});try{return await t.ready(),t}catch(r){if(n=r,await t.close().catch(()=>{}),!isAddressInUseError(r)||!e.retryOnAddressInUse)throw r}}throw Error(`Failed to start Nitro dev server after ${t.length} attempts. Tried ports ${t.join(`, `)}.`,{cause:n})}async function startDevelopmentServer(o,s={}){loadDevelopmentEnvironmentFiles(o);let c=await prepareApplicationHost(o,{dev:!0}),l=resolveNitroCompiledArtifactsSource(createNitroArtifactsConfig({appRoot:c.appRoot,dev:!0}));await prewarmAppSandboxes({appRoot:c.appRoot,compiledArtifactsSource:l,log:e=>console.log(e)});let u=await createApplicationNitro(c,!0),d=createDevServer(u);guardDevelopmentServerWebSocketUpgrades(u,d);let f=s.host??u.options.devServer.hostname,p=s.port??readEnvironmentPort(),m=p??u.options.devServer.port,h=p===void 0,g,_;try{let e=await listenForDevelopmentServer({devServer:d,host:f,port:m,retryOnAddressInUse:h});if(!e.url)throw Error(`Nitro dev server did not expose a URL.`);g=installWorkflowLocalQueueEnvironment(e.url),await prepare(u),await build(u);let{startAuthoredSourceWatcher:n}=await import(`#internal/nitro/host/dev-authored-source-watcher.js`);_=await n({nitro:u,preparedHost:c});let i=g;if(i===void 0)throw Error(`Workflow local queue environment was not initialized.`);let a=_;return{async close(){try{await a.close(),await d.close(),await u.close()}finally{i()}},url:normalizeDevelopmentServerClientUrl(e.url)}}catch(e){throw await _?.close().catch(()=>{}),g?.(),await d.close().catch(()=>{}),await u.close().catch(()=>{}),e}}export{normalizeDevelopmentServerClientUrl,startDevelopmentServer};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Builds the dev-only runtime artifact revision response.
3
+ *
4
+ * Auth: none. The route is mounted only by the local dev server and exposes
5
+ * only an opaque revision token that changes when HMR publishes a new runtime
6
+ * snapshot.
7
+ */
8
+ export declare function handleDevRuntimeArtifactsRequest(input: {
9
+ appRoot: string;
10
+ }): Response;
@@ -0,0 +1 @@
1
+ import{readDevelopmentRuntimeArtifactsRevision}from"#internal/nitro/dev-runtime-artifacts.js";function handleDevRuntimeArtifactsRequest(e){return Response.json(readDevelopmentRuntimeArtifactsRevision(e.appRoot),{headers:{"cache-control":`no-store`}})}export{handleDevRuntimeArtifactsRequest};
@@ -7,6 +7,7 @@ import { type RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts
7
7
  export interface NitroArtifactsConfig {
8
8
  readonly appRoot?: string;
9
9
  readonly dev?: boolean;
10
+ readonly devRuntimeArtifactsPointerPath?: string;
10
11
  readonly moduleMapLoaderPath?: string;
11
12
  }
12
13
  /**
@@ -1 +1 @@
1
- import{createBundledRuntimeCompiledArtifactsSource,createDiskRuntimeCompiledArtifactsSource}from"#runtime/compiled-artifacts-source.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";function resolveNitroCompiledArtifactsSource(e){let{appRoot:t,dev:n}=e;if(n&&t!==void 0){if(e.moduleMapLoaderPath===void 0)throw Error(`Ash Nitro development routes require "moduleMapLoaderPath" in the artifacts config.`);return createDiskRuntimeCompiledArtifactsSource(t,{moduleMapLoaderPath:e.moduleMapLoaderPath})}if(readBundledCompiledArtifacts()!==null)return createBundledRuntimeCompiledArtifactsSource();if(t!==void 0)return createDiskRuntimeCompiledArtifactsSource(t);throw Error(`Ash Nitro route requires bundled artifacts or an Ash Nitro runtime configuration app root.`)}export{resolveNitroCompiledArtifactsSource};
1
+ import{createBundledRuntimeCompiledArtifactsSource,createDiskRuntimeCompiledArtifactsSource}from"#runtime/compiled-artifacts-source.js";import{readBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";import{readDevelopmentRuntimeArtifactsSnapshotRoot}from"#internal/nitro/dev-runtime-artifacts.js";function resolveNitroCompiledArtifactsSource(e){let{appRoot:t,dev:n}=e;if(n&&t!==void 0){if(e.moduleMapLoaderPath===void 0)throw Error(`Ash Nitro development routes require "moduleMapLoaderPath" in the artifacts config.`);return createDiskRuntimeCompiledArtifactsSource(readDevelopmentRuntimeArtifactsSnapshotRoot(e.devRuntimeArtifactsPointerPath)??t,{moduleMapLoaderPath:e.moduleMapLoaderPath})}if(readBundledCompiledArtifacts()!==null)return createBundledRuntimeCompiledArtifactsSource();if(t!==void 0)return createDiskRuntimeCompiledArtifactsSource(t);throw Error(`Ash Nitro route requires bundled artifacts or an Ash Nitro runtime configuration app root.`)}export{resolveNitroCompiledArtifactsSource};
@@ -1 +1 @@
1
- import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{createWorkflowRuntime}from"#execution/workflow-runtime.js";import{loadResolvedCompiledScheduleByTaskName}from"#runtime/schedules/resolve-schedule.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{ScheduleDispatcher,expectScheduleRun}from"#channel/schedule.js";import{loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function dispatchScheduleTask(r,i){let a=resolveNitroCompiledArtifactsSource(i),o=await loadResolvedCompiledScheduleByTaskName(r,{compiledArtifactsSource:a}),s=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:a}),c=new ScheduleDispatcher({runtime:createWorkflowRuntime({compiledArtifactsSource:a}),channels:s.graph.root.channels}),l={scheduleId:o.name};o.hasRun&&(l.run=await loadScheduleRun(o,s.moduleMap)),o.markdown!==void 0&&(l.markdown=o.markdown);let u=await c.trigger(l);return u.waitUntilTasks.length>0&&await Promise.allSettled(u.waitUntilTasks),{scheduleId:o.name,sessionIds:u.sessions.map(e=>e.id)}}async function loadScheduleRun(e,t){if(e.sourceKind!==`module`)throw Error(`Schedule "${e.name}" claims hasRun but is not a module-backed schedule.`);let n=e;return expectScheduleRun(await loadResolvedModuleExport({definition:{exportName:n.exportName,logicalPath:n.logicalPath,sourceId:n.sourceId},kindLabel:`schedule`,moduleMap:t,nodeId:void 0}),n.logicalPath,n.exportName)}export{dispatchScheduleTask};
1
+ import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{createWorkflowRuntime}from"#execution/workflow-runtime.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{loadResolvedCompiledScheduleByTaskName}from"#runtime/schedules/resolve-schedule.js";import{ScheduleDispatcher,expectScheduleRun}from"#channel/schedule.js";import{loadResolvedModuleExport}from"#runtime/resolve-helpers.js";async function dispatchScheduleTask(r,i){let a=resolveNitroCompiledArtifactsSource(i),o=await loadResolvedCompiledScheduleByTaskName(r,{compiledArtifactsSource:a}),s=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:a}),c=new ScheduleDispatcher({runtime:createWorkflowRuntime({compiledArtifactsSource:a}),channels:s.graph.root.channels}),l={scheduleId:o.name};o.hasRun&&(l.run=await loadScheduleRun(o,s.moduleMap)),o.markdown!==void 0&&(l.markdown=o.markdown);let u=await c.trigger(l);return u.waitUntilTasks.length>0&&await Promise.allSettled(u.waitUntilTasks),{scheduleId:o.name,sessionIds:u.sessions.map(e=>e.id)}}async function loadScheduleRun(e,t){if(e.sourceKind!==`module`)throw Error(`Schedule "${e.name}" claims hasRun but is not a module-backed schedule.`);let n=e;return expectScheduleRun(await loadResolvedModuleExport({definition:{exportName:n.exportName,logicalPath:n.logicalPath,sourceId:n.sourceId},kindLabel:`schedule`,moduleMap:t,nodeId:void 0}),n.logicalPath,n.exportName)}export{dispatchScheduleTask};
@@ -1,4 +1,4 @@
1
- import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.63.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.165`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
1
+ import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.64.1`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.165`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
2
2
  import { slackChannel } from "experimental-ash/channels/slack";
3
3
 
4
4
  export default slackChannel({
@@ -1,18 +1,5 @@
1
1
  const WEB_APP_TEMPLATE_FILES={"agent/channels/ash.ts":`import { ashChannel } from "experimental-ash/channels/ash";
2
- import { type AuthFn, localDev, vercelOidc } from "experimental-ash/channels/auth";
3
-
4
- // Replace with your real auth (Auth.js, Clerk, …): return a SessionAuthContext
5
- // for signed-in users, or null to reject. Throws in production until you do.
6
- function exampleProductionAuth(): AuthFn<Request> {
7
- return () => {
8
- if (process.env.VERCEL_ENV === "production") {
9
- throw new Error(
10
- "Configure production auth in agent/channels/ash.ts (e.g. Auth.js or Clerk).",
11
- );
12
- }
13
- return null;
14
- };
15
- }
2
+ import { localDev, placeholderAuth, vercelOidc } from "experimental-ash/channels/auth";
16
3
 
17
4
  export default ashChannel({
18
5
  auth: [
@@ -20,8 +7,10 @@ export default ashChannel({
20
7
  localDev(),
21
8
  // Lets the Ash TUI and your Vercel deployments reach the deployed agent.
22
9
  vercelOidc(),
23
- // Your end-user auth replace the placeholder above.
24
- exampleProductionAuth(),
10
+ // This placeholder will not allow browser requests in production.
11
+ // Replace it with your app's auth provider, like Auth.js or Clerk,
12
+ // or use none() for a public demo.
13
+ placeholderAuth(),
25
14
  ],
26
15
  });
27
16
  `,"app/_components/agent-chat.tsx":`"use client";
@@ -46,6 +46,15 @@ export declare const ASH_MESSAGE_STREAM_ROUTE_PATTERN = "/ash/v1/session/:sessio
46
46
  * `agent/schedules/heartbeat.ts` -> `"heartbeat"`).
47
47
  */
48
48
  export declare const ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN = "/ash/v1/dev/schedules/:scheduleId";
49
+ /**
50
+ * Dev-only route exposing the current runtime artifact revision.
51
+ *
52
+ * Local development clients use this to decide when an HMR rebuild has
53
+ * published new runtime artifacts, so their next normal prompt can start a
54
+ * fresh server-side session while in-flight sessions keep their original
55
+ * snapshot.
56
+ */
57
+ export declare const ASH_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH = "/ash/v1/dev/runtime-artifacts";
49
58
  /**
50
59
  * Builds the dev-only schedule dispatch URL for one named authored
51
60
  * schedule. The path encodes the schedule id so reserved characters in
@@ -1 +1 @@
1
- const ASH_ROUTE_PREFIX=`/ash/v1`,ASH_HEALTH_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/health`,ASH_INFO_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/info`,ASH_CREATE_SESSION_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/session`,ASH_CONTINUE_SESSION_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId`,ASH_MESSAGE_STREAM_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId/stream`,ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/dev/schedules/:scheduleId`;function createAshDevDispatchSchedulePath(e){return`${ASH_ROUTE_PREFIX}/dev/schedules/${encodeURIComponent(e)}`}const ASH_CONNECTION_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/connections/:name/callback/:token`,ASH_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/callback/:token`;function createAshMessageStreamRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createAshContinueSessionRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createAshConnectionCallbackRoutePath(e,t){return`${ASH_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createAshCallbackRoutePath(e){return`${ASH_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{ASH_CALLBACK_ROUTE_PATTERN,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN,ASH_CONTINUE_SESSION_ROUTE_PATTERN,ASH_CREATE_SESSION_ROUTE_PATH,ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH,ASH_MESSAGE_STREAM_ROUTE_PATTERN,ASH_ROUTE_PREFIX,createAshCallbackRoutePath,createAshConnectionCallbackRoutePath,createAshContinueSessionRoutePath,createAshDevDispatchSchedulePath,createAshMessageStreamRoutePath};
1
+ const ASH_ROUTE_PREFIX=`/ash/v1`,ASH_HEALTH_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/health`,ASH_INFO_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/info`,ASH_CREATE_SESSION_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/session`,ASH_CONTINUE_SESSION_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId`,ASH_MESSAGE_STREAM_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId/stream`,ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/dev/schedules/:scheduleId`,ASH_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/dev/runtime-artifacts`;function createAshDevDispatchSchedulePath(e){return`${ASH_ROUTE_PREFIX}/dev/schedules/${encodeURIComponent(e)}`}const ASH_CONNECTION_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/connections/:name/callback/:token`,ASH_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/callback/:token`;function createAshMessageStreamRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createAshContinueSessionRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createAshConnectionCallbackRoutePath(e,t){return`${ASH_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createAshCallbackRoutePath(e){return`${ASH_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{ASH_CALLBACK_ROUTE_PATTERN,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN,ASH_CONTINUE_SESSION_ROUTE_PATTERN,ASH_CREATE_SESSION_ROUTE_PATH,ASH_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,ASH_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH,ASH_MESSAGE_STREAM_ROUTE_PATTERN,ASH_ROUTE_PREFIX,createAshCallbackRoutePath,createAshConnectionCallbackRoutePath,createAshContinueSessionRoutePath,createAshDevDispatchSchedulePath,createAshMessageStreamRoutePath};
@@ -1,2 +1,2 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{ASH_MESSAGE_STREAM_CONTENT_TYPE,ASH_MESSAGE_STREAM_FORMAT,ASH_MESSAGE_STREAM_VERSION,ASH_SESSION_ID_HEADER,ASH_STREAM_FORMAT_HEADER,ASH_STREAM_VERSION_HEADER}from"#protocol/message.js";import"ai";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{parseSessionCallback}from"#channel/session-callback.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";import{GET,POST,defineChannel}from"#public/definitions/defineChannel.js";const log=createLogger(`ash.channel`);function defaultAshAuth(e){return e.ash.caller}function ashChannel(e){let t=mergeUploadPolicy(e.uploadPolicy);return defineChannel({routes:[POST(`/ash/v1/session`,async(n,{send:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let o=i,s;try{s=await n.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof s!=`object`||!s)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let c=parseCreateBody(s);if(c instanceof Response)return c;let l=checkUploadPolicy(c,t);if(l!==null)return l;let u=await resolveOnMessage({auth:o,config:e,message:c.message,request:n});if(u instanceof Response)return u;if(!u.dispatch)return droppedMessageResponse();let d=`ash:${crypto.randomUUID()}`,f=await r(createSendPayload(c,mergeContext(c.context,u.context)),{auth:u.auth,callback:c.callback,continuationToken:d,mode:c.mode});return Response.json({continuationToken:f.continuationToken,ok:!0,sessionId:f.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:f.id},status:202})}),POST(`/ash/v1/session/:sessionId`,async(n,{send:r,getSession:i,params:o})=>{let s=await routeAuth(n,e.auth);if(s instanceof Response)return s;let c=s,l=o.sessionId;if(!l)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(l)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let u;try{u=await n.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof u!=`object`||!u)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let d=parseContinueBody(u);if(d instanceof Response)return d;let f=checkUploadPolicy(d,t);if(f!==null)return f;let p=d.context,m=c;if(d.message!==void 0){let t=await resolveOnMessage({auth:c,config:e,message:d.message,request:n,sessionId:l});if(t instanceof Response)return t;if(!t.dispatch)return droppedMessageResponse();p=mergeContext(d.context,t.context),m=t.auth}let h=await r({inputResponses:d.inputResponses,message:d.message,context:p,outputSchema:d.outputSchema},{auth:m,continuationToken:d.continuationToken});return Response.json({ok:!0,sessionId:h.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:h.id},status:200})}),GET(`/ash/v1/session/:sessionId/stream`,async(t,{getSession:c,params:l})=>{let u=await routeAuth(t,e.auth);if(u instanceof Response)return u;let d=l.sessionId;if(!d)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let f=parseStartIndex(t);if(f instanceof Response)return f;try{let e=serializeAsNdjson(await c(d).getEventStream({startIndex:f}));return new Response(e,{headers:{"cache-control":`no-store`,"content-type":ASH_MESSAGE_STREAM_CONTENT_TYPE,[ASH_SESSION_ID_HEADER]:d,[ASH_STREAM_FORMAT_HEADER]:ASH_MESSAGE_STREAM_FORMAT,[ASH_STREAM_VERSION_HEADER]:ASH_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({ash: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:defaultAshAuth(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}}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});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:
1
+ import{createLogger,logError}from"#internal/logging.js";import{ASH_MESSAGE_STREAM_CONTENT_TYPE,ASH_MESSAGE_STREAM_FORMAT,ASH_MESSAGE_STREAM_VERSION,ASH_SESSION_ID_HEADER,ASH_STREAM_FORMAT_HEADER,ASH_STREAM_VERSION_HEADER}from"#protocol/message.js";import"ai";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{parseSessionCallback}from"#channel/session-callback.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";import{GET,POST,defineChannel}from"#public/definitions/defineChannel.js";const log=createLogger(`ash.channel`);function defaultAshAuth(e){return e.ash.caller}function ashChannel(e){let t=mergeUploadPolicy(e.uploadPolicy);return defineChannel({routes:[POST(`/ash/v1/session`,async(n,{send:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let o=i,s;try{s=await n.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof s!=`object`||!s)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let c=parseCreateBody(s);if(c instanceof Response)return c;let l=checkUploadPolicy(c,t);if(l!==null)return l;let u=await resolveOnMessage({auth:o,config:e,message:c.message,request:n});if(u instanceof Response)return u;if(!u.dispatch)return droppedMessageResponse();let d=`ash:${crypto.randomUUID()}`,f=await r(createSendPayload(c,mergeContext(c.context,u.context)),{auth:u.auth,callback:c.callback,continuationToken:d,mode:c.mode});return Response.json({continuationToken:f.continuationToken,ok:!0,sessionId:f.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:f.id},status:202})}),POST(`/ash/v1/session/:sessionId`,async(n,{send:r,getSession:i,params:o})=>{let s=await routeAuth(n,e.auth);if(s instanceof Response)return s;let c=s,l=o.sessionId;if(!l)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(l)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let u;try{u=await n.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof u!=`object`||!u)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let d=parseContinueBody(u);if(d instanceof Response)return d;let f=checkUploadPolicy(d,t);if(f!==null)return f;let p=d.context,m=c;if(d.message!==void 0){let t=await resolveOnMessage({auth:c,config:e,message:d.message,request:n,sessionId:l});if(t instanceof Response)return t;if(!t.dispatch)return droppedMessageResponse();p=mergeContext(d.context,t.context),m=t.auth}let h=await r({inputResponses:d.inputResponses,message:d.message,context:p,outputSchema:d.outputSchema},{auth:m,continuationToken:d.continuationToken});return Response.json({ok:!0,sessionId:h.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:h.id},status:200})}),GET(`/ash/v1/session/:sessionId/stream`,async(t,{getSession:c,params:l})=>{let u=await routeAuth(t,e.auth);if(u instanceof Response)return u;let d=l.sessionId;if(!d)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let f=parseStartIndex(t);if(f instanceof Response)return f;try{let e=serializeAsNdjson(await c(d).getEventStream({startIndex:f}));return new Response(e,{headers:{"cache-control":`no-store, no-transform`,"content-type":ASH_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[ASH_SESSION_ID_HEADER]:d,[ASH_STREAM_FORMAT_HEADER]:ASH_MESSAGE_STREAM_FORMAT,[ASH_STREAM_VERSION_HEADER]:ASH_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({ash: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:defaultAshAuth(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}}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});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
2
  ${e}`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number.parseInt(t,10);return!Number.isSafeInteger(n)||n<0?Response.json({error:`Expected startIndex to be a non-negative 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{ashChannel,defaultAshAuth};
@@ -157,6 +157,32 @@ export interface UnauthorizedResponseOptions {
157
157
  * headers (one per challenge), and a `{ ok: false, code, error }` body.
158
158
  */
159
159
  export declare function createUnauthorizedResponse(opts?: UnauthorizedResponseOptions): Response;
160
+ /**
161
+ * Options accepted by auth error classes. The class chooses the HTTP status.
162
+ */
163
+ export type AuthErrorOptions = Omit<UnauthorizedResponseOptions, "status">;
164
+ /**
165
+ * Error thrown by auth callbacks to reject a route with a structured 401
166
+ * response.
167
+ *
168
+ * `routeAuth` catches this error and returns its response. Other errors still
169
+ * propagate through the normal channel failure path.
170
+ */
171
+ export declare class UnauthenticatedError extends Error {
172
+ readonly response: Response;
173
+ constructor(opts?: AuthErrorOptions);
174
+ }
175
+ /**
176
+ * Error thrown by auth callbacks to reject a route with a structured 403
177
+ * response.
178
+ *
179
+ * `routeAuth` catches this error and returns its response. Other errors still
180
+ * propagate through the normal channel failure path.
181
+ */
182
+ export declare class ForbiddenError extends Error {
183
+ readonly response: Response;
184
+ constructor(opts?: AuthErrorOptions);
185
+ }
160
186
  /**
161
187
  * Route auth callback. Returned value semantics inside {@link routeAuth}:
162
188
  *
@@ -164,9 +190,10 @@ export declare function createUnauthorizedResponse(opts?: UnauthorizedResponseOp
164
190
  * - `null` or `undefined` skips to the next entry in the array.
165
191
  *
166
192
  * If every entry skips (including the degenerate `[]` case), the walker
167
- * returns a 401. To accept anonymous traffic, include {@link none} as
168
- * the final entry it returns a synthetic anonymous
169
- * {@link SessionAuthContext} that terminates the walk.
193
+ * returns a 401. To reject with a specific response, throw an
194
+ * {@link UnauthenticatedError} or {@link ForbiddenError}. To accept anonymous
195
+ * traffic, include {@link none} as the final entry — it returns a synthetic
196
+ * anonymous {@link SessionAuthContext} that terminates the walk.
170
197
  */
171
198
  export type AuthFn<TEvent = Request> = (event: TEvent) => SessionAuthContext | null | undefined | Promise<SessionAuthContext | null | undefined>;
172
199
  /**
@@ -181,6 +208,21 @@ export type AuthFn<TEvent = Request> = (event: TEvent) => SessionAuthContext | n
181
208
  * `routeAuth` rather than re-implement the walk.
182
209
  */
183
210
  export declare function routeAuth(request: Request, auth: AuthFn<Request> | readonly AuthFn<Request>[]): Promise<SessionAuthContext | Response>;
211
+ /**
212
+ * Returns an {@link AuthFn} for scaffolded apps that makes unfinished
213
+ * production auth fail as an intentional 401 instead of an internal route
214
+ * error.
215
+ *
216
+ * Replace this before serving real users:
217
+ *
218
+ * ```ts
219
+ * ashChannel({ auth: [localDev(), vercelOidc(), placeholderAuth()] });
220
+ * ```
221
+ *
222
+ * In non-production environments it returns `null`, so the auth walk keeps
223
+ * the same local development behavior as any other skipped auth entry.
224
+ */
225
+ export declare function placeholderAuth(): AuthFn<Request>;
184
226
  /**
185
227
  * Returns an {@link AuthFn} that accepts any request anonymously by
186
228
  * producing a synthetic principal with `principalType: "anonymous"`.
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";const vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let r=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return r.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){return e===null||e.length===0?{kind:`not-authenticated`}:await authenticateOidcStrategy({strategy:{acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}async function routeAuth(e,t){let n=Array.isArray(t)?t:[t];for(let t of n){let n=await t(e);if(n)return n}return createUnauthorizedResponse({challenges:[{scheme:`Bearer`}]})}function none(){return()=>ANONYMOUS_SESSION_AUTH_CONTEXT}function localDev(){return e=>process.env.VERCEL&&process.env.VERCEL_ENV===`development`||isLoopbackRequest(e)?LOCAL_DEV_SESSION_AUTH_CONTEXT:null}const LOOPBACK_HOSTNAMES=new Set([`localhost`,`[::1]`]),LOOPBACK_IPV4_PREFIX=/^127\./;function isLoopbackRequest(e){let t;try{t=new URL(e.url).hostname}catch{return!1}return!!(LOOPBACK_HOSTNAMES.has(t)||LOOPBACK_IPV4_PREFIX.test(t)||t.endsWith(`.localhost`))}const ANONYMOUS_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`none`,principalId:`anonymous`,principalType:`anonymous`},LOCAL_DEV_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`local-dev`,principalId:`local-dev`,principalType:`local-dev`};async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(`https://oidc.vercel.com/`))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};let r=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,issuer:n.issuer,subjects:t.subjects??[]});return r.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:r.principal.principalType,subject:r.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:r.kind,subjectsConfigured:(t.subjects??[]).length>0,...r.kind===`misconfigured`?{detail:r.message}:{}}),{ok:!1})}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return async t=>{let n=await verifyVercelOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function httpBasic(e){return t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null}}function jwtHmac(e){return async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function jwtEcdsa(e){return async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function oidc(e){return async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function decodeUnverifiedJwtClaims(e){let n;try{n=decodeJwt(e)}catch{return null}return typeof n.iss!=`string`||n.iss.length===0?null:{audiences:typeof n.aud==`string`?[n.aud]:Array.isArray(n.aud)?n.aud.filter(e=>typeof e==`string`):[],issuer:n.iss}}export{createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,jwtEcdsa,jwtHmac,localDev,none,oidc,routeAuth,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc};
1
+ import{createLogger}from"#internal/logging.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";const vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let r=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return r.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){return e===null||e.length===0?{kind:`not-authenticated`}:await authenticateOidcStrategy({strategy:{acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}var UnauthenticatedError=class extends Error{response;constructor(e={}){super(e.message??`Authorization is required for this route.`),this.name=`UnauthenticatedError`,this.response=createUnauthorizedResponse({...e,status:401})}},ForbiddenError=class extends Error{response;constructor(e={}){super(e.message??`Forbidden.`),this.name=`ForbiddenError`,this.response=createUnauthorizedResponse({...e,status:403})}};async function routeAuth(e,t){let n=Array.isArray(t)?t:[t];try{for(let t of n){let n=await t(e);if(n)return n}}catch(e){if(typeof e==`object`&&e&&`response`in e&&e.response instanceof Response)return e.response;throw e}return createUnauthorizedResponse({challenges:[{scheme:`Bearer`}]})}function placeholderAuth(){return()=>{if(process.env.VERCEL_ENV!==`production`)return null;throw new UnauthenticatedError({code:`ash_production_auth_not_configured`,message:`Production auth is not configured. Replace placeholderAuth() in agent/channels/ash.ts with your app's auth provider.`})}}function none(){return()=>ANONYMOUS_SESSION_AUTH_CONTEXT}function localDev(){return e=>process.env.VERCEL&&process.env.VERCEL_ENV===`development`||isLoopbackRequest(e)?LOCAL_DEV_SESSION_AUTH_CONTEXT:null}const LOOPBACK_HOSTNAMES=new Set([`localhost`,`[::1]`]),LOOPBACK_IPV4_PREFIX=/^127\./;function isLoopbackRequest(e){let t;try{t=new URL(e.url).hostname}catch{return!1}return!!(LOOPBACK_HOSTNAMES.has(t)||LOOPBACK_IPV4_PREFIX.test(t)||t.endsWith(`.localhost`))}const ANONYMOUS_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`none`,principalId:`anonymous`,principalType:`anonymous`},LOCAL_DEV_SESSION_AUTH_CONTEXT={attributes:{},authenticator:`local-dev`,principalId:`local-dev`,principalType:`local-dev`};async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(`https://oidc.vercel.com/`))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};let r=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,issuer:n.issuer,subjects:t.subjects??[]});return r.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:r.principal.principalType,subject:r.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:r.kind,subjectsConfigured:(t.subjects??[]).length>0,...r.kind===`misconfigured`?{detail:r.message}:{}}),{ok:!1})}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return async t=>{let n=await verifyVercelOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function httpBasic(e){return t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null}}function jwtHmac(e){return async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function jwtEcdsa(e){return async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function oidc(e){return async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function decodeUnverifiedJwtClaims(e){let n;try{n=decodeJwt(e)}catch{return null}return typeof n.iss!=`string`||n.iss.length===0?null:{audiences:typeof n.aud==`string`?[n.aud]:Array.isArray(n.aud)?n.aud.filter(e=>typeof e==`string`):[],issuer:n.iss}}export{ForbiddenError,UnauthenticatedError,createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,jwtEcdsa,jwtHmac,localDev,none,oidc,placeholderAuth,routeAuth,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc};
@@ -93,7 +93,9 @@ export declare function parseAppMentionEvent(envelope: SlackEventCallback): Slac
93
93
  * Returns `null` when:
94
94
  * - the envelope is not an IM `message` event,
95
95
  * - required fields (channel id, ts) are missing,
96
- * - the message carries a `subtype` (edits, deletes, joins, etc.), or
96
+ * - the message carries a system `subtype` (edits, deletes, joins, etc.)
97
+ * other than `file_share` — file uploads are real user messages and
98
+ * must reach the handler with their attachments intact, or
97
99
  * - the message was posted by a bot (`bot_id` set) — this prevents the
98
100
  * bot's own DM replies from re-triggering the handler.
99
101
  */
@@ -1,2 +1,2 @@
1
- import{slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";function parseAppMentionEvent(e){if(e.type!==`event_callback`)return null;let t=e.event;return!t||t.type!==`app_mention`?null:buildSlackMessage(t,e.team_id)}function parseDirectMessageEvent(e){if(e.type!==`event_callback`)return null;let t=e.event;if(!t||t.type!==`message`)return null;let n=t;return n.channel_type!==`im`||typeof n.subtype==`string`&&n.subtype.length>0||typeof n.bot_id==`string`&&n.bot_id.length>0?null:buildSlackMessage(n,e.team_id)}function buildSlackMessage(t,n){let r=typeof t.channel==`string`?t.channel:``,i=typeof t.ts==`string`?t.ts:``;if(!r||!i)return null;let a=typeof t.text==`string`?t.text:``,o=typeof t.thread_ts==`string`?t.thread_ts:i,s=typeof n==`string`?n:void 0;return{text:a,markdown:slackMrkdwnToGfm(a),ts:i,threadTs:o,channelId:r,teamId:s,author:parseAuthor(t),attachments:parseAttachments(t.files),raw:t}}function parseAuthor(e){let t=typeof e.user==`string`?e.user:``;if(t)return{userId:t,userName:typeof e.username==`string`?e.username:void 0,fullName:void 0,isBot:typeof e.bot_id==`string`&&e.bot_id.length>0,isMe:!1}}function parseAttachments(e){return Array.isArray(e)?e.map(toAttachment):[]}function toAttachment(e){let t=typeof e.mimetype==`string`?e.mimetype:void 0,n=typeof e.url_private==`string`?e.url_private:void 0;return{id:typeof e.id==`string`?e.id:``,type:inferAttachmentType(t),url:n,name:typeof e.name==`string`?e.name:void 0,mimeType:t,size:typeof e.size==`number`?e.size:void 0}}function inferAttachmentType(e){return e===void 0?`file`:e.startsWith(`image/`)?`image`:e.startsWith(`video/`)?`video`:e.startsWith(`audio/`)?`audio`:`file`}function formatSlackContextBlock(e){return[`<slack_context>`,`user_id: ${e.userId}`,...e.userName?[`user_name: ${e.userName}`]:[],...e.fullName?[`full_name: ${e.fullName}`]:[],`channel_id: ${e.channelId}`,`thread_ts: ${e.threadTs}`,...e.teamId?[`team_id: ${e.teamId}`]:[],`</slack_context>`].join(`
1
+ import{slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";function parseAppMentionEvent(e){if(e.type!==`event_callback`)return null;let t=e.event;return!t||t.type!==`app_mention`?null:buildSlackMessage(t,e.team_id)}function parseDirectMessageEvent(e){if(e.type!==`event_callback`)return null;let t=e.event;if(!t||t.type!==`message`)return null;let n=t;return n.channel_type!==`im`||typeof n.subtype==`string`&&n.subtype.length>0&&n.subtype!==`file_share`||typeof n.bot_id==`string`&&n.bot_id.length>0?null:buildSlackMessage(n,e.team_id)}function buildSlackMessage(t,n){let r=typeof t.channel==`string`?t.channel:``,i=typeof t.ts==`string`?t.ts:``;if(!r||!i)return null;let a=typeof t.text==`string`?t.text:``,o=typeof t.thread_ts==`string`?t.thread_ts:i,s=typeof n==`string`?n:void 0;return{text:a,markdown:slackMrkdwnToGfm(a),ts:i,threadTs:o,channelId:r,teamId:s,author:parseAuthor(t),attachments:parseAttachments(t.files),raw:t}}function parseAuthor(e){let t=typeof e.user==`string`?e.user:``;if(t)return{userId:t,userName:typeof e.username==`string`?e.username:void 0,fullName:void 0,isBot:typeof e.bot_id==`string`&&e.bot_id.length>0,isMe:!1}}function parseAttachments(e){return Array.isArray(e)?e.map(toAttachment):[]}function toAttachment(e){let t=typeof e.mimetype==`string`?e.mimetype:void 0,n=typeof e.url_private==`string`?e.url_private:void 0;return{id:typeof e.id==`string`?e.id:``,type:inferAttachmentType(t),url:n,name:typeof e.name==`string`?e.name:void 0,mimeType:t,size:typeof e.size==`number`?e.size:void 0}}function inferAttachmentType(e){return e===void 0?`file`:e.startsWith(`image/`)?`image`:e.startsWith(`video/`)?`video`:e.startsWith(`audio/`)?`audio`:`file`}function formatSlackContextBlock(e){return[`<slack_context>`,`user_id: ${e.userId}`,...e.userName?[`user_name: ${e.userName}`]:[],...e.fullName?[`full_name: ${e.fullName}`]:[],`channel_id: ${e.channelId}`,`thread_ts: ${e.threadTs}`,...e.teamId?[`team_id: ${e.teamId}`]:[],`</slack_context>`].join(`
2
2
  `)}export{formatSlackContextBlock,parseAppMentionEvent,parseDirectMessageEvent};
@@ -1,5 +1,6 @@
1
1
  import type { UserContent } from "ai";
2
2
  import { type SessionState } from "#client/index.js";
3
+ import type { ClientSession } from "#client/session.js";
3
4
  import type { HandleMessageStreamEvent } from "#protocol/message.js";
4
5
  import type { InputResponse } from "#runtime/input/types.js";
5
6
  import type { JsonObject } from "#shared/json.js";
@@ -40,6 +41,32 @@ export interface DevelopmentMessageClient {
40
41
  }): void;
41
42
  }): Promise<DevelopmentClientSendResult>;
42
43
  }
44
+ /**
45
+ * Tracks local dev runtime-artifact revisions and starts a fresh session for
46
+ * normal prompts after HMR, while preserving the current session for
47
+ * input-response resumes.
48
+ */
49
+ export interface DevelopmentRuntimeArtifactSessionRefresher {
50
+ /**
51
+ * Clears the remembered runtime-artifact revision.
52
+ */
53
+ clear(): void;
54
+ /**
55
+ * Returns the session that should dispatch the next turn.
56
+ */
57
+ refresh(input: {
58
+ readonly createSession: () => ClientSession;
59
+ readonly inputResponses?: readonly InputResponse[];
60
+ readonly message?: string | UserContent;
61
+ readonly session: ClientSession;
62
+ }): Promise<ClientSession>;
63
+ }
64
+ /**
65
+ * Creates a revision-aware local dev session refresher.
66
+ */
67
+ export declare function createDevelopmentRuntimeArtifactSessionRefresher(input: {
68
+ readonly serverUrl: string;
69
+ }): DevelopmentRuntimeArtifactSessionRefresher;
43
70
  /**
44
71
  * Creates a stateful development client bound to one Ash server URL.
45
72
  */