experimental-ash 0.62.0 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/docs/public/advanced/hooks.mdx +8 -2
- package/dist/docs/public/advanced/runs-and-streaming.md +6 -3
- package/dist/docs/public/advanced/typescript-api.md +32 -0
- package/dist/docs/public/channels/custom.mdx +23 -0
- package/dist/docs/public/frontend/README.md +8 -4
- package/dist/docs/public/frontend/meta.json +9 -1
- package/dist/docs/public/frontend/nextjs.md +4 -4
- package/dist/docs/public/frontend/nuxt.md +168 -0
- package/dist/docs/public/frontend/sveltekit.md +177 -0
- package/dist/docs/public/frontend/use-ash-agent-svelte.md +185 -0
- package/dist/docs/public/frontend/use-ash-agent-vue.md +236 -0
- package/dist/docs/public/frontend/use-ash-agent.md +14 -14
- package/dist/docs/public/getting-started.mdx +2 -0
- package/dist/src/channel/websocket-upgrade-server.d.ts +26 -0
- package/dist/src/channel/websocket-upgrade-server.js +1 -0
- package/dist/src/chunks/use-ash-agent-BQJLh7KU.js +1224 -0
- package/dist/src/chunks/use-ash-agent-CRWVA4i-.js +1192 -0
- package/dist/src/client/ash-agent-store.d.ts +61 -0
- package/dist/src/client/ash-agent-store.js +2 -0
- package/dist/src/client/index.d.ts +2 -0
- package/dist/src/client/index.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +3 -3
- package/dist/src/compiled/@chat-adapter/slack/index.js +25 -25
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +8 -0
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +1 -0
- package/dist/src/compiled/@workflow/core/runtime.js +29 -29
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/error-codes.d.ts +2 -0
- package/dist/src/compiled/@workflow/errors/index.d.ts +14 -0
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/world/queue.d.ts +8 -0
- package/dist/src/compiled/_chunks/workflow/dist-zpK2YVVA.js +3 -0
- package/dist/src/compiled/_chunks/workflow/resume-hook-BFK9mgsb.js +12 -0
- package/dist/src/compiled/_chunks/workflow/{sleep-Bg0t23kF.js → sleep-CeJckNg2.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/{symbols-u476uwyR.js → symbols-BWCAoPHE.js} +1 -1
- package/dist/src/internal/application/package.d.ts +1 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/channel-routes.js +2 -2
- package/dist/src/internal/workflow-bundle/ash-service-route-output.js +11 -1
- package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
- package/dist/src/public/channels/index.d.ts +1 -0
- package/dist/src/public/channels/index.js +1 -1
- package/dist/src/public/nuxt/dev-server.d.ts +24 -0
- package/dist/src/public/nuxt/dev-server.js +1 -0
- package/dist/src/public/nuxt/index.d.ts +1 -0
- package/dist/src/public/nuxt/index.js +1 -0
- package/dist/src/public/nuxt/module.d.ts +31 -0
- package/dist/src/public/nuxt/module.js +1 -0
- package/dist/src/public/nuxt/routing.d.ts +55 -0
- package/dist/src/public/nuxt/routing.js +1 -0
- package/dist/src/public/nuxt/vercel-json.d.ts +17 -0
- package/dist/src/public/nuxt/vercel-json.js +1 -0
- package/dist/src/public/sveltekit/dev-server.d.ts +24 -0
- package/dist/src/public/sveltekit/dev-server.js +1 -0
- package/dist/src/public/sveltekit/index.d.ts +39 -0
- package/dist/src/public/sveltekit/index.js +1 -0
- package/dist/src/public/sveltekit/routing.d.ts +32 -0
- package/dist/src/public/sveltekit/routing.js +1 -0
- package/dist/src/public/sveltekit/vercel-json.d.ts +17 -0
- package/dist/src/public/sveltekit/vercel-json.js +1 -0
- package/dist/src/react/use-ash-agent.d.ts +5 -27
- package/dist/src/react/use-ash-agent.js +1 -2
- package/dist/src/svelte/index.d.ts +3 -0
- package/dist/src/svelte/index.js +3 -0
- package/dist/src/svelte/use-ash-agent.d.ts +80 -0
- package/dist/src/svelte/use-ash-agent.js +3 -0
- package/dist/src/vue/index.d.ts +3 -0
- package/dist/src/vue/index.js +3 -0
- package/dist/src/vue/use-ash-agent.d.ts +78 -0
- package/dist/src/vue/use-ash-agent.js +3 -0
- package/package.json +51 -6
- package/dist/src/compiled/_chunks/workflow/dist-C4EHshZE.js +0 -3
- package/dist/src/compiled/_chunks/workflow/resume-hook-BlALLgSA.js +0 -12
|
@@ -18,6 +18,7 @@ export declare function resolvePackageSourceFilePath(relativeSourcePath: string)
|
|
|
18
18
|
* Resolves one package-owned source directory from the currently executing Ash installation.
|
|
19
19
|
*/
|
|
20
20
|
export declare function resolvePackageSourceDirectoryPath(relativeSourcePath: string): string;
|
|
21
|
+
export declare function resolvePackageDependencyPath(specifier: string): string;
|
|
21
22
|
/**
|
|
22
23
|
* Resolves the installed Ash package identity from package.json.
|
|
23
24
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.
|
|
1
|
+
import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.63.0`}const FALLBACK_PACKAGE_INFO={name:ASH_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageDependencyPath(e){return require.resolve(e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),ASH_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${ASH_PACKAGE_NAME}/package.json`),ASH_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageDependencyPath,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname,join,resolve}from"node:path";import{readFile}from"node:fs/promises";import{resolveNitroSurfaceOutputDirectory}from"#internal/application/paths.js";import{resolvePackageRoot}from"#internal/application/package.js";import{build,copyPublicAssets,prepare,prerender}from"nitro/builder";import{prepareAshVersionedCacheDirectory,writeAshVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{WorkflowBundleBuilder}from"#internal/workflow-bundle/builder.js";import{normalizeAshVercelFunctionOutput}from"#internal/workflow-bundle/vercel-workflow-output.js";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{emitVercelAgentSummary}from"#internal/nitro/host/build-vercel-agent-summary.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{runVercelBuildPrewarm}from"#internal/nitro/host/vercel-build-prewarm.js";import{findClosestVercelOutputDirectory}from"#shared/vercel-output-directory.js";function trimTrailingSlash(e){return e.replace(/[\\/]+$/,``)}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function normalizeEntrypoint(e,t){return typeof t!=`string`||t.trim().length===0?null:resolve(e,t)}function normalizeServicePrefix(e){return typeof e.routePrefix==`string`?e.routePrefix.trim():typeof e.mount==`string`?e.mount.trim():isRecord(e.mount)&&typeof e.mount.path==`string`&&e.mount.path.trim().length>0?e.mount.path.trim():``}function
|
|
1
|
+
import{dirname,join,resolve}from"node:path";import{readFile}from"node:fs/promises";import{resolveNitroSurfaceOutputDirectory}from"#internal/application/paths.js";import{resolvePackageRoot}from"#internal/application/package.js";import{build,copyPublicAssets,prepare,prerender}from"nitro/builder";import{prepareAshVersionedCacheDirectory,writeAshVersionedCacheMetadata}from"#internal/application/cache-metadata.js";import{WorkflowBundleBuilder}from"#internal/workflow-bundle/builder.js";import{normalizeAshVercelFunctionOutput}from"#internal/workflow-bundle/vercel-workflow-output.js";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{emitVercelAgentSummary}from"#internal/nitro/host/build-vercel-agent-summary.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{runVercelBuildPrewarm}from"#internal/nitro/host/vercel-build-prewarm.js";import{findClosestVercelOutputDirectory}from"#shared/vercel-output-directory.js";function trimTrailingSlash(e){return e.replace(/[\\/]+$/,``)}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function normalizeEntrypoint(e,t){return typeof t!=`string`||t.trim().length===0?null:resolve(e,t)}function normalizeServicePrefix(e){return typeof e.routePrefix==`string`?e.routePrefix.trim():typeof e.mount==`string`?e.mount.trim():isRecord(e.mount)&&typeof e.mount.path==`string`&&e.mount.path.trim().length>0?e.mount.path.trim():``}function resolveCoDeployedAshServicePrefix(e){if(!isRecord(e.config)||!isRecord(e.config.experimentalServices))return;let t=!1,n;for(let r of Object.values(e.config.experimentalServices)){if(!isRecord(r))continue;if(r.framework!==`ash`){t=!0;continue}let i=normalizeEntrypoint(e.configRoot,r.entrypoint),a=normalizeServicePrefix(r);i===e.appRoot&&a.length>0&&a!==`/`&&(n=a)}return t?n:void 0}async function resolveCoDeployedAshServicePrefixForVercelFunctionOutput(n){let i=await findClosestVercelOutputDirectory(n);if(i!==void 0)try{let e=resolveCoDeployedAshServicePrefix({appRoot:n,configRoot:n,config:JSON.parse(await readFile(join(i,`config.json`),`utf8`))});if(e!==void 0)return e}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}let a=n;for(;;){for(let e of[join(a,`vercel.json`),join(a,`.vercel`,`output`,`config.json`)])try{let t=JSON.parse(await readFile(e,`utf8`)),i=resolveCoDeployedAshServicePrefix({appRoot:n,configRoot:e.endsWith(`vercel.json`)?a:n,config:t});if(i!==void 0)return i}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}let i=dirname(a);if(i===a)return;a=i}}async function readVercelServerRuntime(e){try{return JSON.parse(await readFile(join(e,`functions`,`__server.func`,`.vc-config.json`),`utf8`)).runtime}catch{return}}async function emitVercelWorkflowFunctions(e){let t=new WorkflowBundleBuilder({appRoot:e.appRoot,compiledArtifactsBootstrapPath:e.compiledArtifactsBootstrapPath,outDir:e.workflowBuildDir,rootDir:resolvePackageRoot(),watch:!1}),n=await readVercelServerRuntime(e.outputDir);await t.buildVercelOutput({flowNitroOutputDir:e.flowNitroOutputDir,outputDir:e.outputDir,runtime:n})}async function buildNitroOutput(e){let t=trimTrailingSlash(e.options.output.dir);return await prepareAshVersionedCacheDirectory(t),await prepare(e),await copyPublicAssets(e),await prerender(e),await build(e),await writeAshVersionedCacheMetadata(t),t}async function buildVercelNitroSurface(e,t){let n=await createApplicationNitro(e,!1,{outputDir:resolveNitroSurfaceOutputDirectory(e.appRoot,t),surface:t});try{return await buildNitroOutput(n)}finally{await n.close()}}async function buildApplication(e){let t=await prepareApplicationHost(e);if(!process.env.VERCEL){let e=await createApplicationNitro(t,!1);try{let n=await buildNitroOutput(e);return await emitVercelAgentSummary({manifest:t.compileResult.manifest,appRoot:t.appRoot}),n}finally{await e.close()}}let n=await resolveCoDeployedAshServicePrefixForVercelFunctionOutput(t.appRoot),r=await createApplicationNitro(t,!1,{surface:`app`});try{let e=await buildNitroOutput(r);await runVercelBuildPrewarm({appRoot:t.appRoot,log(e){console.log(e)}});let i=await buildVercelNitroSurface(t,`flow`);return await emitVercelWorkflowFunctions({appRoot:t.appRoot,compiledArtifactsBootstrapPath:t.compiledArtifacts.bootstrapPath,flowNitroOutputDir:i,outputDir:e,workflowBuildDir:t.workflowBuildDir}),n!==void 0&&await normalizeAshVercelFunctionOutput(e,{servicePrefix:n}),await emitVercelAgentSummary({manifest:t.compileResult.manifest,appRoot:t.appRoot}),e}finally{await r.close()}}export{buildApplication};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{resolvePackageSourceFilePath}from"#internal/application/package.js";import{stringifyEsmImportSpecifier}from"#internal/application/import-specifier.js";import{getAllFrameworkChannelNames,getFrameworkChannelDefinitions}from"#runtime/framework-channels/index.js";const ASH_CHANNEL_VIRTUAL_ID_PREFIX=`#ash-channel/`;function computeChannelRouteRegistrations(e){let t=e.compileResult.manifest.channels,
|
|
2
|
-
`);return}
|
|
1
|
+
import{resolvePackageDependencyPath,resolvePackageSourceFilePath}from"#internal/application/package.js";import{stringifyEsmImportSpecifier}from"#internal/application/import-specifier.js";import{getAllFrameworkChannelNames,getFrameworkChannelDefinitions}from"#runtime/framework-channels/index.js";const ASH_CHANNEL_VIRTUAL_ID_PREFIX=`#ash-channel/`;function computeChannelRouteRegistrations(e){let t=e.compileResult.manifest.channels,n=new Set,a=[],o=new Set,s=getAllFrameworkChannelNames();for(let e of t){if(e.kind===`disabled`){if(!s.has(e.name))throw Error(`agent/channels/${e.name}.ts exports disableRoute() but "${e.name}" is not a framework channel. Rename the file to one of: ${[...s].sort().join(`, `)}.`);o.add(e.name);continue}n.add(e.name),a.push({method:e.method,route:e.urlPath})}let c=getFrameworkChannelDefinitions().filter(e=>!n.has(e.name)&&!o.has(e.name)).map(e=>({method:e.method,route:e.urlPath})),l=new Set,u=[];for(let e of[...c,...a]){let t=createChannelRouteKey(e);l.has(t)||(l.add(t),u.push(e))}return u}function registerChannelVirtualHandlers(e,t){for(let n of t.registrations)addChannelVirtualHandler(e,{artifactsConfig:t.artifactsConfig,method:n.method,route:n.route})}function syncChannelVirtualHandlers(e,t){return areChannelRouteRegistrationsEqual(t.previous,t.next)?!1:(removeChannelVirtualHandlers(e),registerChannelVirtualHandlers(e,{artifactsConfig:t.artifactsConfig,registrations:t.next}),e.routing.sync(),!0)}function createChannelRouteKey(e){return`${e.method.toUpperCase()} ${e.route}`}function addChannelVirtualHandler(r,i){let o=createChannelRouteKey(i),s=`${ASH_CHANNEL_VIRTUAL_ID_PREFIX}${o}`,c=stringifyEsmImportSpecifier(resolvePackageSourceFilePath(`src/internal/nitro/routes/channel-dispatch.ts`)),l=stringifyEsmImportSpecifier(resolvePackageDependencyPath(`nitro`));if(i.method===`WEBSOCKET`){r.options.handlers.push({handler:s,route:i.route}),r.options.virtual[s]=[`import { defineWebSocketHandler } from ${l};`,`import { dispatchChannelWebSocketRequest } from ${c};`,`const config = ${JSON.stringify(i.artifactsConfig)};`,`export default defineWebSocketHandler((event) => dispatchChannelWebSocketRequest(event, ${JSON.stringify(o)}, config));`].join(`
|
|
2
|
+
`);return}r.options.handlers.push({handler:s,method:i.method,route:i.route}),r.options.virtual[s]=[`import { dispatchChannelRequest } from ${c};`,`const config = ${JSON.stringify(i.artifactsConfig)};`,`export default (event) => dispatchChannelRequest(event, ${JSON.stringify(o)}, config);`].join(`
|
|
3
3
|
`)}function removeChannelVirtualHandlers(e){for(let t=e.options.handlers.length-1;t>=0;--t){let n=e.options.handlers[t];n!==void 0&&isChannelVirtualHandler(n)&&e.options.handlers.splice(t,1)}for(let t of Object.keys(e.options.virtual))t.startsWith(ASH_CHANNEL_VIRTUAL_ID_PREFIX)&&delete e.options.virtual[t]}function isChannelVirtualHandler(e){return e.handler.startsWith(ASH_CHANNEL_VIRTUAL_ID_PREFIX)}function areChannelRouteRegistrationsEqual(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1){let r=e[n],i=t[n];if(r===void 0||i===void 0||r.method!==i.method||r.route!==i.route)return!1}return!0}export{computeChannelRouteRegistrations,registerChannelVirtualHandlers,syncChannelVirtualHandlers};
|
|
@@ -29,7 +29,7 @@ if (!globalThis[PATCH_SYMBOL]) {
|
|
|
29
29
|
globalThis[PATCH_SYMBOL] = true;
|
|
30
30
|
const originalEmit = Server.prototype.emit;
|
|
31
31
|
Server.prototype.emit = function patchedEmit(event, request, ...args) {
|
|
32
|
-
if (event === "request" && request && typeof request.url === "string") {
|
|
32
|
+
if ((event === "request" || event === "upgrade") && request && typeof request.url === "string") {
|
|
33
33
|
request.url = stripServiceRoutePrefix(request.url);
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -40,5 +40,15 @@ if (!globalThis[PATCH_SYMBOL]) {
|
|
|
40
40
|
const originalModule = await import("./index.mjs");
|
|
41
41
|
const entrypoint = originalModule?.default ?? originalModule;
|
|
42
42
|
|
|
43
|
+
export const handleUpgrade = originalModule.handleUpgrade
|
|
44
|
+
? (request, socket, head) => {
|
|
45
|
+
if (request && typeof request.url === "string") {
|
|
46
|
+
request.url = stripServiceRoutePrefix(request.url);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return originalModule.handleUpgrade(request, socket, head);
|
|
50
|
+
}
|
|
51
|
+
: undefined;
|
|
52
|
+
|
|
43
53
|
export default entrypoint;
|
|
44
54
|
`.trimStart()}function normalizeServiceRoutePrefix(e){let t=(e.startsWith(`/`)?e:`/${e}`).replace(/\/+$/,``);return t.length===0?`/`:t}export{ASH_SHARED_SERVER_FUNCTION_PATH,applyAshServiceRoutePrefixWrapper,isAshVercelFunctionPath,normalizeAshVercelRoutes};
|
|
@@ -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.
|
|
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";
|
|
2
2
|
import { slackChannel } from "experimental-ash/channels/slack";
|
|
3
3
|
|
|
4
4
|
export default slackChannel({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { defineChannel, GET, POST, PUT, PATCH, DELETE, WS, type Channel, type ChannelDefinition, type ChannelSessionOps, type ChannelEvents, type InferChannelMetadata, type Session, type SessionHandle, type RouteDefinition, type RouteHandlerArgs, type SendFn, type SendOptions, type SendPayload, type GetSessionFn, type HttpRouteDefinition, type WebSocketMessage, type WebSocketPeer, type WebSocketRouteDefinition, type WebSocketRouteHandler, type WebSocketRouteHooks, type WebSocketUpgradeRequest, type WebSocketUpgradeResult, } from "#public/definitions/defineChannel.js";
|
|
2
|
+
export { createWebSocketUpgradeServer, type WebSocketUpgradeServerBridge, } from "#channel/websocket-upgrade-server.js";
|
|
2
3
|
import type { Channel } from "#public/definitions/defineChannel.js";
|
|
3
4
|
/**
|
|
4
5
|
* Base channel metadata shape used by framework channel kinds.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getChannelInstrumentationKind}from"#channel/compiled-channel.js";import{DELETE,GET,PATCH,POST,PUT,WS,defineChannel}from"#public/definitions/defineChannel.js";function isChannel(e,t){return e.kind===getChannelInstrumentationKind(t)}export{DELETE,GET,PATCH,POST,PUT,WS,defineChannel,isChannel};
|
|
1
|
+
import{getChannelInstrumentationKind}from"#channel/compiled-channel.js";import{DELETE,GET,PATCH,POST,PUT,WS,defineChannel}from"#public/definitions/defineChannel.js";import{createWebSocketUpgradeServer}from"#channel/websocket-upgrade-server.js";function isChannel(e,t){return e.kind===getChannelInstrumentationKind(t)}export{DELETE,GET,PATCH,POST,PUT,WS,createWebSocketUpgradeServer,defineChannel,isChannel};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
export declare const ASH_BASE_URL_ENV = "ASH_BASE_URL";
|
|
3
|
+
export interface AshProcessHandle {
|
|
4
|
+
readonly origin: string;
|
|
5
|
+
readonly process?: ChildProcess;
|
|
6
|
+
}
|
|
7
|
+
export interface AshDevServerRegistry {
|
|
8
|
+
readonly appRoot: string;
|
|
9
|
+
readonly origin: string;
|
|
10
|
+
readonly pid: number | null;
|
|
11
|
+
readonly updatedAt: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse and validate a persisted dev-server registry record. Returns
|
|
15
|
+
* `undefined` for anything that is not a well-formed registry so callers fall
|
|
16
|
+
* back to spawning a fresh server.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeDevServerRegistry(value: unknown): AshDevServerRegistry | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a shared Ash dev server for {@link appRoot}, reusing a healthy
|
|
21
|
+
* registered server when one exists and otherwise spawning a new one behind a
|
|
22
|
+
* cross-process lock so concurrent Nuxt processes don't each boot Ash.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveSharedAshDevServer(appRoot: string): Promise<AshProcessHandle>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{joinRoutePrefix,normalizeOrigin}from"./routing.js";import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";import{join}from"node:path";import{mkdir,open,readFile,rm,stat,writeFile}from"node:fs/promises";import{spawn}from"node:child_process";import{resolvePackageRoot}from"#internal/application/package.js";const ASH_BASE_URL_ENV=`ASH_BASE_URL`,DEFAULT_SERVER_READY_TIMEOUT_MS=3e4,DEV_SERVER_REGISTRY_TIMEOUT_MS=3e4,LOCAL_SERVER_URL_PATTERN=/https?:\/\/(?:\[[^\]\s]+\]|[^\s/:[\]]+)(?::\d+)?/;function isNodeErrorWithCode(e,t){return e instanceof Error&&`code`in e&&e.code===t}function delay(e){return new Promise(t=>setTimeout(t,e))}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveAshCacheDirectory(e){return join(e,`.ash`)}function resolveAshDevServerRegistryPath(e){return join(resolveAshCacheDirectory(e),`nuxt-dev-server.json`)}function resolveAshDevServerLockPath(e){return join(resolveAshCacheDirectory(e),`nuxt-dev-server.lock`)}function normalizeDevServerRegistry(e){if(isRecord(e)&&!(typeof e.appRoot!=`string`||typeof e.origin!=`string`||typeof e.updatedAt!=`string`)&&!(e.pid!==null&&typeof e.pid!=`number`))try{return{appRoot:e.appRoot,origin:normalizeOrigin(e.origin),pid:e.pid,updatedAt:e.updatedAt}}catch{return}}async function isAshServerHealthy(t){let r=new AbortController,i=setTimeout(()=>r.abort(),1e3);try{return(await fetch(joinRoutePrefix(t,`${ASH_ROUTE_PREFIX}/health`),{signal:r.signal})).ok}catch{return!1}finally{clearTimeout(i)}}async function readUsableAshDevServerRegistry(e){try{let t=normalizeDevServerRegistry(JSON.parse(await readFile(resolveAshDevServerRegistryPath(e),`utf8`)));return t===void 0||t.appRoot!==e||!await isAshServerHealthy(t.origin)?void 0:t.origin}catch(e){if(isNodeErrorWithCode(e,`ENOENT`))return;throw e}}async function writeAshDevServerRegistry(e,t){await mkdir(resolveAshCacheDirectory(e),{recursive:!0}),await writeFile(resolveAshDevServerRegistryPath(e),`${JSON.stringify({appRoot:e,origin:t.origin,pid:t.process?.pid??null,updatedAt:new Date().toISOString()},null,2)}\n`)}async function removeStaleAshDevServerLock(e){try{let t=await stat(e);Date.now()-t.mtimeMs>3e4&&await rm(e,{force:!0})}catch(e){if(!isNodeErrorWithCode(e,`ENOENT`))throw e}}async function acquireAshDevServerLock(e){let t=resolveAshCacheDirectory(e),n=resolveAshDevServerLockPath(e),r=Date.now()+DEV_SERVER_REGISTRY_TIMEOUT_MS;for(await mkdir(t,{recursive:!0});;)try{let e=await open(n,`wx`);return await e.writeFile(`${String(process.pid)}\n`),await e.close(),async()=>{await rm(n,{force:!0})}}catch(t){if(!isNodeErrorWithCode(t,`EEXIST`))throw t;if(await readUsableAshDevServerRegistry(e)!==void 0)return async()=>{};if(await removeStaleAshDevServerLock(n),Date.now()>r)throw Error(`Timed out after ${DEV_SERVER_REGISTRY_TIMEOUT_MS}ms waiting for another Nuxt process to start Ash.`);await delay(100)}}function createAshBinaryPath(){return join(resolvePackageRoot(),`bin`,`ash.js`)}function startServerProcess(e){return new Promise((n,r)=>{let i=spawn(e.command,e.args,{cwd:e.cwd,env:{...process.env,...e.env},stdio:[`ignore`,`pipe`,`pipe`]}),a=setTimeout(()=>{i.kill(),r(Error(`Timed out after ${DEFAULT_SERVER_READY_TIMEOUT_MS}ms waiting for Ash to print its server URL.`))},DEFAULT_SERVER_READY_TIMEOUT_MS),cleanup=()=>{clearTimeout(a),i.off(`error`,handleError),i.off(`exit`,handleEarlyExit)},handleError=e=>{cleanup(),r(e)},handleEarlyExit=(e,t)=>{cleanup(),r(Error(`Ash server process exited before printing its server URL (code ${String(e)}, signal ${String(t)}).`))},o=!1,handleOutput=e=>{if(o)return;let r=LOCAL_SERVER_URL_PATTERN.exec(e.toString(`utf8`));r!==null&&(o=!0,cleanup(),n({origin:normalizeOrigin(r[0]),process:i}))};i.once(`error`,handleError),i.once(`exit`,handleEarlyExit),i.stdout.on(`data`,e=>{process.stdout.write(e),handleOutput(e)}),i.stderr.on(`data`,e=>{process.stderr.write(e),handleOutput(e)})})}function installProcessShutdown(e){let t=e.process;if(t===void 0)return e;let close=()=>{process.off(`beforeExit`,close),process.off(`exit`,close),t.killed||t.kill()};return process.once(`beforeExit`,close),process.once(`exit`,close),e}function startAshDevServer(e){return startServerProcess({args:[createAshBinaryPath(),`dev`,`--no-repl`,`--port`,`0`],command:process.execPath,cwd:e}).then(e=>(process.env[ASH_BASE_URL_ENV]=e.origin,installProcessShutdown(e)))}async function resolveSharedAshDevServer(e){let t=await readUsableAshDevServerRegistry(e);if(t!==void 0)return process.env[ASH_BASE_URL_ENV]=t,{origin:t};let n=await acquireAshDevServerLock(e);try{let t=await readUsableAshDevServerRegistry(e);if(t!==void 0)return process.env[ASH_BASE_URL_ENV]=t,{origin:t};let n=await startAshDevServer(e);return await writeAshDevServerRegistry(e,n),n}finally{await n()}}export{ASH_BASE_URL_ENV,normalizeDevServerRegistry,resolveSharedAshDevServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, ASH_NUXT_SERVICE_PREFIX, type AshNuxtModuleOptions } from "./module.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ASH_NUXT_SERVICE_PREFIX}from"./routing.js";import module_default from"./module.js";export{ASH_NUXT_SERVICE_PREFIX,module_default as default};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ASH_NUXT_SERVICE_PREFIX } from "./routing.js";
|
|
2
|
+
export { ASH_NUXT_SERVICE_PREFIX };
|
|
3
|
+
/**
|
|
4
|
+
* Options for the Ash Nuxt module.
|
|
5
|
+
*/
|
|
6
|
+
export interface AshNuxtModuleOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Path to the Ash application root, relative to the Nuxt project root
|
|
9
|
+
* unless absolute. Defaults to the Nuxt project root.
|
|
10
|
+
*/
|
|
11
|
+
ashRoot?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Build command for the generated Ash Vercel service.
|
|
14
|
+
* Defaults to `"ash build"`.
|
|
15
|
+
*/
|
|
16
|
+
ashBuildCommand?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Set to `false` to skip creating or updating `vercel.json`.
|
|
19
|
+
*
|
|
20
|
+
* By default the module ensures `vercel.json` contains
|
|
21
|
+
* `experimentalServices` for the Nuxt app and Ash app.
|
|
22
|
+
*/
|
|
23
|
+
configureVercelJson?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Private Vercel service prefix for the Ash deployment. Must match the
|
|
26
|
+
* Ash service's `routePrefix` in `vercel.json`.
|
|
27
|
+
*/
|
|
28
|
+
servicePrefix?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const _default: import("nuxt/schema").NuxtModule<AshNuxtModuleOptions, AshNuxtModuleOptions, false>;
|
|
31
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ASH_NUXT_SERVICE_PREFIX,createAshVercelRewriteRoute,joinRoutePrefix,normalizeOrigin,normalizeRoutePrefix,resolveProductionTarget}from"./routing.js";import{ASH_BASE_URL_ENV,resolveSharedAshDevServer}from"./dev-server.js";import{ensureAshVercelJson}from"./vercel-json.js";import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";import{isAbsolute,resolve}from"node:path";import{addImports,defineNuxtModule,extendRouteRules}from"@nuxt/kit";function resolveApplicationRoot(e,t){return t===void 0||t.length===0?e:isAbsolute(t)?t:resolve(e,t)}async function resolveAshProxyTarget(e){if(!e.dev)return resolveProductionTarget(e.servicePrefix);let t=process.env[ASH_BASE_URL_ENV]?.trim();if(t&&t.length>0)return joinRoutePrefix(normalizeOrigin(t),ASH_ROUTE_PREFIX);let i=await resolveSharedAshDevServer(e.appRoot);return i.process!==void 0&&e.onDevServerSpawned?.(i.process),joinRoutePrefix(i.origin,ASH_ROUTE_PREFIX)}var module_default=defineNuxtModule({meta:{name:`experimental-ash`,configKey:`ash`,compatibility:{nuxt:`>=4.0.0`}},defaults:{},async setup(e,n){let r=n.options.rootDir,a=resolveApplicationRoot(r,e.ashRoot),o=normalizeRoutePrefix(e.servicePrefix??`/_ash_internal/ash`),s=e.configureVercelJson!==!1;if(addImports({name:`useAshAgent`,from:`experimental-ash/vue`}),!n.options.dev&&process.env.VERCEL){let e=createAshVercelRewriteRoute(o),r=n.options.nitro,i=r.vercel?.config;r.vercel={...r.vercel,config:{version:3,...i,routes:[e,...i?.routes??[]]}}}else n.hook(`modules:done`,async()=>{let e=await resolveAshProxyTarget({appRoot:a,dev:n.options.dev,servicePrefix:o,onDevServerSpawned:e=>{n.hook(`close`,()=>{e.killed||e.kill()})}});extendRouteRules(`${ASH_ROUTE_PREFIX}/**`,{proxy:`${e}/**`})});s&&await ensureAshVercelJson({appRoot:a,ashBuildCommand:e.ashBuildCommand??`ash build`,nuxtRoot:r,servicePrefix:o})}});export{ASH_NUXT_SERVICE_PREFIX,module_default as default};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private route namespace used when a Vercel deployment hosts Ash as a
|
|
3
|
+
* separate experimental service behind the Nuxt app.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ASH_NUXT_SERVICE_PREFIX = "/_ash_internal/ash";
|
|
6
|
+
/**
|
|
7
|
+
* Normalize a user-supplied service prefix into a leading-slash, no-trailing-
|
|
8
|
+
* slash route. Throws when the prefix resolves to the root route, which would
|
|
9
|
+
* collide with the Nuxt web service.
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizeRoutePrefix(prefix: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Join a route prefix and a path with exactly one separating slash.
|
|
14
|
+
*/
|
|
15
|
+
export declare function joinRoutePrefix(prefix: string, path: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Reduce an origin string to its canonical `protocol://host[:port]` form.
|
|
18
|
+
*/
|
|
19
|
+
export declare function normalizeOrigin(origin: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve the local production port the module proxies to when an Ash service
|
|
22
|
+
* runs alongside a non-Vercel Nuxt deployment. Defaults to
|
|
23
|
+
* {@link DEFAULT_ASH_NUXT_PRODUCTION_PORT}.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readLocalProductionPort(): number;
|
|
26
|
+
/**
|
|
27
|
+
* An edge-level Vercel rewrite expressed in Build Output API v3 form.
|
|
28
|
+
*/
|
|
29
|
+
export interface AshVercelRewriteRoute {
|
|
30
|
+
readonly src: string;
|
|
31
|
+
readonly dest: string;
|
|
32
|
+
/**
|
|
33
|
+
* Re-run route matching against the rewritten `dest`. Required so the
|
|
34
|
+
* rewritten Ash service path is routed to the sibling Ash service instead of
|
|
35
|
+
* being resolved inside the host service's own filesystem (which 404s).
|
|
36
|
+
*/
|
|
37
|
+
readonly check: true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the edge-level Vercel rewrite that forwards Ash transport requests
|
|
41
|
+
* (`/ash/v1/**`) to the Ash service prefix (`/_ash_internal/ash/ash/v1/**`).
|
|
42
|
+
*
|
|
43
|
+
* Mirrors the Next.js integration's `beforeFiles` rewrite. A Nitro runtime
|
|
44
|
+
* `proxy` route rule cannot reach a sibling Vercel service — the proxied
|
|
45
|
+
* request loops back into the Nuxt function and 404s — so production routing
|
|
46
|
+
* must happen at the edge via the build output config instead.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createAshVercelRewriteRoute(servicePrefix: string): AshVercelRewriteRoute;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the proxy destination for Ash routes in production.
|
|
51
|
+
*
|
|
52
|
+
* On Vercel the destination is the private service prefix. Off Vercel it is an
|
|
53
|
+
* explicit origin override (`ASH_NUXT_PRODUCTION_ORIGIN`) or a local port.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveProductionTarget(servicePrefix: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";const ASH_NUXT_SERVICE_PREFIX=`/_ash_internal/ash`,ASH_NUXT_PRODUCTION_PORT_ENV=`ASH_NUXT_PRODUCTION_PORT`;function normalizeRoutePrefix(e){let t=(e.startsWith(`/`)?e:`/${e}`).replace(/\/+$/,``);if(t.length===0)throw Error(`Ash Nuxt service prefix cannot resolve to the root route.`);return t}function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e.trim()).origin}function readLocalProductionPort(){let e=process.env[ASH_NUXT_PRODUCTION_PORT_ENV];if(e===void 0||e.trim().length===0)return 4274;let t=Number.parseInt(e,10);if(String(t)!==e.trim()||t<1||t>65535)throw Error(`${ASH_NUXT_PRODUCTION_PORT_ENV} must be an integer between 1 and 65535.`);return t}function createAshVercelRewriteRoute(t){let n=joinRoutePrefix(t,ASH_ROUTE_PREFIX);return{src:`^${ASH_ROUTE_PREFIX}/(.*)$`,dest:`${n}/$1`,check:!0}}function resolveProductionTarget(t){if(process.env.VERCEL)return joinRoutePrefix(t,ASH_ROUTE_PREFIX);let n=process.env.ASH_NUXT_PRODUCTION_ORIGIN;return n!==void 0&&n.trim().length>0?joinRoutePrefix(normalizeOrigin(n),ASH_ROUTE_PREFIX):joinRoutePrefix(`http://127.0.0.1:${String(readLocalProductionPort())}`,ASH_ROUTE_PREFIX)}export{ASH_NUXT_SERVICE_PREFIX,createAshVercelRewriteRoute,joinRoutePrefix,normalizeOrigin,normalizeRoutePrefix,readLocalProductionPort,resolveProductionTarget};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface EnsureVercelJsonResult {
|
|
2
|
+
readonly servicePrefix: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Ensure `vercel.json` declares the Nuxt web service and the Ash agent
|
|
6
|
+
* service so a Vercel deployment ships both from one project.
|
|
7
|
+
*
|
|
8
|
+
* Existing services are preserved untouched; an already-configured Ash
|
|
9
|
+
* service's `routePrefix` wins over {@link input.servicePrefix}. The file is
|
|
10
|
+
* only rewritten when the resulting config differs from what is on disk.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureAshVercelJson(input: {
|
|
13
|
+
readonly appRoot: string;
|
|
14
|
+
readonly ashBuildCommand: string;
|
|
15
|
+
readonly nuxtRoot: string;
|
|
16
|
+
readonly servicePrefix: string;
|
|
17
|
+
}): Promise<EnsureVercelJsonResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{join,relative}from"node:path";import{readFile,writeFile}from"node:fs/promises";const VERCEL_JSON_FILE_NAME=`vercel.json`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveRelativeEntrypoint(e,n){let r=relative(e,n);return r.length===0?`.`:r.replaceAll(`\\`,`/`)}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.experimentalServices;if(t!==void 0&&!isRecord(t))throw Error(`${VERCEL_JSON_FILE_NAME} experimentalServices must be a JSON object.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findServiceByFramework(e,t){return Object.values(e).find(e=>e.framework===t)}async function ensureAshVercelJson(t){let n=join(t.nuxtRoot,VERCEL_JSON_FILE_NAME),i=await readVercelJsonConfig(n),a=resolveRelativeEntrypoint(t.nuxtRoot,t.appRoot),o=i.experimentalServices??{},s=findServiceByFramework(o,`ash`),c=findServiceByFramework(o,`nuxtjs`),l=s?.routePrefix??t.servicePrefix,u={...o};c===void 0&&(u.web={entrypoint:`.`,framework:`nuxtjs`,routePrefix:`/`}),s===void 0&&(u.ash={buildCommand:t.ashBuildCommand,entrypoint:a,framework:`ash`,routePrefix:l});let d={...i,$schema:i.$schema??`https://openapi.vercel.sh/vercel.json`,experimentalServices:u};return JSON.stringify(i)!==JSON.stringify(d)&&await writeFile(n,`${JSON.stringify(d,null,2)}\n`),{servicePrefix:l}}export{ensureAshVercelJson};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
export declare const ASH_BASE_URL_ENV = "ASH_BASE_URL";
|
|
3
|
+
export interface AshProcessHandle {
|
|
4
|
+
readonly origin: string;
|
|
5
|
+
readonly process?: ChildProcess;
|
|
6
|
+
}
|
|
7
|
+
export interface AshDevServerRegistry {
|
|
8
|
+
readonly appRoot: string;
|
|
9
|
+
readonly origin: string;
|
|
10
|
+
readonly pid: number | null;
|
|
11
|
+
readonly updatedAt: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse and validate a persisted dev-server registry record. Returns
|
|
15
|
+
* `undefined` for anything that is not a well-formed registry so callers fall
|
|
16
|
+
* back to spawning a fresh server.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeDevServerRegistry(value: unknown): AshDevServerRegistry | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a shared Ash dev server for {@link appRoot}, reusing a healthy
|
|
21
|
+
* registered server when one exists and otherwise spawning a new one behind a
|
|
22
|
+
* cross-process lock so concurrent SvelteKit processes don't each boot Ash.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveSharedAshDevServer(appRoot: string): Promise<AshProcessHandle>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{joinRoutePrefix,normalizeOrigin}from"./routing.js";import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";import{join}from"node:path";import{mkdir,open,readFile,rm,stat,writeFile}from"node:fs/promises";import{spawn}from"node:child_process";import{resolvePackageRoot}from"#internal/application/package.js";const ASH_BASE_URL_ENV=`ASH_BASE_URL`,DEFAULT_SERVER_READY_TIMEOUT_MS=3e4,DEV_SERVER_REGISTRY_TIMEOUT_MS=3e4,LOCAL_SERVER_URL_PATTERN=/https?:\/\/(?:\[[^\]\s]+\]|[^\s/:[\]]+)(?::\d+)?/;function isNodeErrorWithCode(e,t){return e instanceof Error&&`code`in e&&e.code===t}function delay(e){return new Promise(t=>setTimeout(t,e))}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveAshCacheDirectory(e){return join(e,`.ash`)}function resolveAshDevServerRegistryPath(e){return join(resolveAshCacheDirectory(e),`sveltekit-dev-server.json`)}function resolveAshDevServerLockPath(e){return join(resolveAshCacheDirectory(e),`sveltekit-dev-server.lock`)}function normalizeDevServerRegistry(e){if(isRecord(e)&&!(typeof e.appRoot!=`string`||typeof e.origin!=`string`||typeof e.updatedAt!=`string`)&&!(e.pid!==null&&typeof e.pid!=`number`))try{return{appRoot:e.appRoot,origin:normalizeOrigin(e.origin),pid:e.pid,updatedAt:e.updatedAt}}catch{return}}async function isAshServerHealthy(t){let r=new AbortController,i=setTimeout(()=>r.abort(),1e3);try{return(await fetch(joinRoutePrefix(t,`${ASH_ROUTE_PREFIX}/health`),{signal:r.signal})).ok}catch{return!1}finally{clearTimeout(i)}}async function readUsableAshDevServerRegistry(e){try{let t=normalizeDevServerRegistry(JSON.parse(await readFile(resolveAshDevServerRegistryPath(e),`utf8`)));return t===void 0||t.appRoot!==e||!await isAshServerHealthy(t.origin)?void 0:t.origin}catch(e){if(isNodeErrorWithCode(e,`ENOENT`))return;throw e}}async function writeAshDevServerRegistry(e,t){await mkdir(resolveAshCacheDirectory(e),{recursive:!0}),await writeFile(resolveAshDevServerRegistryPath(e),`${JSON.stringify({appRoot:e,origin:t.origin,pid:t.process?.pid??null,updatedAt:new Date().toISOString()},null,2)}\n`)}async function removeStaleAshDevServerLock(e){try{let t=await stat(e);Date.now()-t.mtimeMs>3e4&&await rm(e,{force:!0})}catch(e){if(!isNodeErrorWithCode(e,`ENOENT`))throw e}}async function acquireAshDevServerLock(e){let t=resolveAshCacheDirectory(e),n=resolveAshDevServerLockPath(e),r=Date.now()+DEV_SERVER_REGISTRY_TIMEOUT_MS;for(await mkdir(t,{recursive:!0});;)try{let e=await open(n,`wx`);return await e.writeFile(`${String(process.pid)}\n`),await e.close(),async()=>{await rm(n,{force:!0})}}catch(t){if(!isNodeErrorWithCode(t,`EEXIST`))throw t;if(await readUsableAshDevServerRegistry(e)!==void 0)return async()=>{};if(await removeStaleAshDevServerLock(n),Date.now()>r)throw Error(`Timed out after ${DEV_SERVER_REGISTRY_TIMEOUT_MS}ms waiting for another SvelteKit process to start Ash.`);await delay(100)}}function createAshBinaryPath(){return join(resolvePackageRoot(),`bin`,`ash.js`)}function startServerProcess(e){return new Promise((n,r)=>{let i=spawn(e.command,e.args,{cwd:e.cwd,env:{...process.env,...e.env},stdio:[`ignore`,`pipe`,`pipe`]}),a=setTimeout(()=>{i.kill(),r(Error(`Timed out after ${DEFAULT_SERVER_READY_TIMEOUT_MS}ms waiting for Ash to print its server URL.`))},DEFAULT_SERVER_READY_TIMEOUT_MS),cleanup=()=>{clearTimeout(a),i.off(`error`,handleError),i.off(`exit`,handleEarlyExit)},handleError=e=>{cleanup(),r(e)},handleEarlyExit=(e,t)=>{cleanup(),r(Error(`Ash server process exited before printing its server URL (code ${String(e)}, signal ${String(t)}).`))},o=!1,handleOutput=e=>{if(o)return;let r=LOCAL_SERVER_URL_PATTERN.exec(e.toString(`utf8`));r!==null&&(o=!0,cleanup(),n({origin:normalizeOrigin(r[0]),process:i}))};i.once(`error`,handleError),i.once(`exit`,handleEarlyExit),i.stdout.on(`data`,e=>{process.stdout.write(e),handleOutput(e)}),i.stderr.on(`data`,e=>{process.stderr.write(e),handleOutput(e)})})}function installProcessShutdown(e){let t=e.process;if(t===void 0)return e;let close=()=>{process.off(`beforeExit`,close),process.off(`exit`,close),t.killed||t.kill()};return process.once(`beforeExit`,close),process.once(`exit`,close),e}function startAshDevServer(e){return startServerProcess({args:[createAshBinaryPath(),`dev`,`--no-repl`,`--port`,`0`],command:process.execPath,cwd:e}).then(e=>(process.env[ASH_BASE_URL_ENV]=e.origin,installProcessShutdown(e)))}async function resolveSharedAshDevServer(e){let t=await readUsableAshDevServerRegistry(e);if(t!==void 0)return process.env[ASH_BASE_URL_ENV]=t,{origin:t};let n=await acquireAshDevServerLock(e);try{let t=await readUsableAshDevServerRegistry(e);if(t!==void 0)return process.env[ASH_BASE_URL_ENV]=t,{origin:t};let n=await startAshDevServer(e);return await writeAshDevServerRegistry(e,n),n}finally{await n()}}export{ASH_BASE_URL_ENV,normalizeDevServerRegistry,resolveSharedAshDevServer};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { ASH_SVELTEKIT_SERVICE_PREFIX } from "./routing.js";
|
|
3
|
+
export { ASH_SVELTEKIT_SERVICE_PREFIX };
|
|
4
|
+
/**
|
|
5
|
+
* Options for the Ash SvelteKit Vite plugin.
|
|
6
|
+
*/
|
|
7
|
+
export interface AshSvelteKitPluginOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Path to the Ash application root, relative to the SvelteKit project root
|
|
10
|
+
* unless absolute. Defaults to the SvelteKit project root.
|
|
11
|
+
*/
|
|
12
|
+
readonly ashRoot?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Build command for the generated Ash Vercel service.
|
|
15
|
+
* Defaults to `"ash build"`.
|
|
16
|
+
*/
|
|
17
|
+
readonly ashBuildCommand?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Set to `false` to skip creating or updating `vercel.json`.
|
|
20
|
+
*
|
|
21
|
+
* By default the plugin ensures `vercel.json` contains `experimentalServices`
|
|
22
|
+
* for the SvelteKit app and Ash app.
|
|
23
|
+
*/
|
|
24
|
+
readonly configureVercelJson?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Private Vercel service prefix for the Ash deployment. Must match the
|
|
27
|
+
* Ash service's `routePrefix` in `vercel.json`.
|
|
28
|
+
*/
|
|
29
|
+
readonly servicePrefix?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Vite plugin for running an Ash agent alongside a SvelteKit app.
|
|
33
|
+
*
|
|
34
|
+
* In development and local preview, `ashSvelteKit` starts
|
|
35
|
+
* `ash dev --no-repl --port 0` for the Ash app and proxies Ash protocol
|
|
36
|
+
* endpoints to that local URL. During builds it can ensure `vercel.json`
|
|
37
|
+
* deploys the SvelteKit app and Ash agent as sibling Vercel services.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ashSvelteKit(options?: AshSvelteKitPluginOptions): Plugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ASH_SVELTEKIT_SERVICE_PREFIX,normalizeOrigin,normalizeRoutePrefix}from"./routing.js";import{ASH_BASE_URL_ENV,resolveSharedAshDevServer}from"./dev-server.js";import{ensureAshVercelJson}from"./vercel-json.js";import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";import{isAbsolute,resolve}from"node:path";function resolveApplicationRoot(e,t){return t===void 0||t.length===0?e:isAbsolute(t)?t:resolve(e,t)}function mergeProxyConfig(e,t){return{...e,[ASH_ROUTE_PREFIX]:{changeOrigin:!0,target:t}}}async function resolveAshDevProxyTarget(e){let n=process.env[ASH_BASE_URL_ENV]?.trim();return n&&n.length>0?normalizeOrigin(n):(await resolveSharedAshDevServer(e)).origin}function ashSvelteKit(e={}){let t=process.cwd(),r=resolveApplicationRoot(t,e.ashRoot),i=normalizeRoutePrefix(e.servicePrefix??`/_ash_internal/ash`),a=e.configureVercelJson!==!1;return{name:`experimental-ash:sveltekit`,async config(n,o){if(t=n.root===void 0?process.cwd():resolve(process.cwd(),n.root),r=resolveApplicationRoot(t,e.ashRoot),a&&o.command===`build`&&await ensureAshVercelJson({appRoot:r,ashBuildCommand:e.ashBuildCommand??`ash build`,servicePrefix:i,svelteKitRoot:t}),o.command!==`serve`)return{};let s=await resolveAshDevProxyTarget(r);return o.isPreview?{preview:{proxy:mergeProxyConfig(n.preview?.proxy,s)}}:{server:{proxy:mergeProxyConfig(n.server?.proxy,s)}}}}}export{ASH_SVELTEKIT_SERVICE_PREFIX,ashSvelteKit};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Private route namespace used when a Vercel deployment hosts Ash as a
|
|
3
|
+
* separate experimental service behind the SvelteKit app.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ASH_SVELTEKIT_SERVICE_PREFIX = "/_ash_internal/ash";
|
|
6
|
+
/**
|
|
7
|
+
* Normalize a user-supplied service prefix into a leading-slash, no-trailing-
|
|
8
|
+
* slash route. Throws when the prefix resolves to the root route, which would
|
|
9
|
+
* collide with the SvelteKit web service.
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizeRoutePrefix(prefix: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Join a route prefix and a path with exactly one separating slash.
|
|
14
|
+
*/
|
|
15
|
+
export declare function joinRoutePrefix(prefix: string, path: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Reduce an origin string to its canonical `protocol://host[:port]` form.
|
|
18
|
+
*/
|
|
19
|
+
export declare function normalizeOrigin(origin: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* A Vercel rewrite that forwards Ash transport requests (`/ash/v1/**`) to the
|
|
22
|
+
* private Ash service prefix (`/_ash_internal/ash/ash/v1/**`).
|
|
23
|
+
*/
|
|
24
|
+
export interface AshVercelRewrite {
|
|
25
|
+
readonly destination: string;
|
|
26
|
+
readonly source: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the Vercel rewrite that forwards browser Ash transport requests to the
|
|
30
|
+
* sibling Ash service.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAshVercelRewrite(servicePrefix: string): AshVercelRewrite;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ASH_ROUTE_PREFIX}from"#protocol/routes.js";const ASH_SVELTEKIT_SERVICE_PREFIX=`/_ash_internal/ash`;function normalizeRoutePrefix(e){let t=(e.startsWith(`/`)?e:`/${e}`).replace(/\/+$/,``);if(t.length===0)throw Error(`Ash SvelteKit service prefix cannot resolve to the root route.`);return t}function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e.trim()).origin}function createAshVercelRewrite(t){return{destination:`${joinRoutePrefix(t,ASH_ROUTE_PREFIX)}/:path*`,source:`${ASH_ROUTE_PREFIX}/:path*`}}export{ASH_SVELTEKIT_SERVICE_PREFIX,createAshVercelRewrite,joinRoutePrefix,normalizeOrigin,normalizeRoutePrefix};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface EnsureVercelJsonResult {
|
|
2
|
+
readonly servicePrefix: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Ensure `vercel.json` declares the SvelteKit web service and the Ash agent
|
|
6
|
+
* service so a Vercel deployment ships both from one project.
|
|
7
|
+
*
|
|
8
|
+
* Existing services are preserved untouched; an already-configured Ash
|
|
9
|
+
* service's `routePrefix` wins over {@link input.servicePrefix}. The file is
|
|
10
|
+
* only rewritten when the resulting config differs from what is on disk.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensureAshVercelJson(input: {
|
|
13
|
+
readonly appRoot: string;
|
|
14
|
+
readonly ashBuildCommand: string;
|
|
15
|
+
readonly servicePrefix: string;
|
|
16
|
+
readonly svelteKitRoot: string;
|
|
17
|
+
}): Promise<EnsureVercelJsonResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createAshVercelRewrite}from"./routing.js";import{join,relative}from"node:path";import{readFile,writeFile}from"node:fs/promises";const VERCEL_JSON_FILE_NAME=`vercel.json`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveRelativeEntrypoint(e,t){let r=relative(e,t);return r.length===0?`.`:r.replaceAll(`\\`,`/`)}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.experimentalServices;if(t!==void 0&&!isRecord(t))throw Error(`${VERCEL_JSON_FILE_NAME} experimentalServices must be a JSON object.`);let n=e.rewrites;if(n!==void 0&&!Array.isArray(n))throw Error(`${VERCEL_JSON_FILE_NAME} rewrites must be an array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findServiceByFramework(e,t){return Object.values(e).find(e=>e.framework===t)}function hasRewrite(e,t){return e.some(e=>e.source===t.source&&e.destination===t.destination)}async function ensureAshVercelJson(n){let r=join(n.svelteKitRoot,VERCEL_JSON_FILE_NAME),i=await readVercelJsonConfig(r),a=resolveRelativeEntrypoint(n.svelteKitRoot,n.appRoot),o=i.experimentalServices??{},s=findServiceByFramework(o,`ash`),c=findServiceByFramework(o,`sveltekit`),l=s?.routePrefix??n.servicePrefix,u={...o};c===void 0&&(u.web={entrypoint:`.`,framework:`sveltekit`,routePrefix:`/`}),s===void 0&&(u.ash={buildCommand:n.ashBuildCommand,entrypoint:a,framework:`ash`,routePrefix:l});let d=createAshVercelRewrite(l),f=i.rewrites??[],p={...i,$schema:i.$schema??`https://openapi.vercel.sh/vercel.json`,experimentalServices:u,rewrites:hasRewrite(f,d)?f:[d,...f]};return JSON.stringify(i)!==JSON.stringify(p)&&await writeFile(r,`${JSON.stringify(p,null,2)}\n`),{servicePrefix:l}}export{ensureAshVercelJson};
|
|
@@ -1,36 +1,15 @@
|
|
|
1
|
+
import { type AshAgentStoreCallbacks, type AshAgentStoreSnapshot, type AshAgentStoreStatus, type PrepareSend } from "#client/ash-agent-store.js";
|
|
1
2
|
import type { AshAgentReducer } from "#client/reducer.js";
|
|
2
3
|
import type { ClientSession } from "#client/session.js";
|
|
3
4
|
import { type AshMessageData } from "#client/message-reducer.js";
|
|
4
5
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
5
6
|
import type { ClientAuth, HeadersValue, SendMessageOptions, SendTurnInput, SessionState } from "#client/types.js";
|
|
6
|
-
export type
|
|
7
|
-
|
|
8
|
-
* Prepares one outbound turn immediately before the client sends it.
|
|
9
|
-
*
|
|
10
|
-
* Use this to attach fresh, one-turn client state such as page context via
|
|
11
|
-
* `clientContext`.
|
|
12
|
-
*/
|
|
13
|
-
export type PrepareSend = (input: SendTurnInput) => SendTurnInput | Promise<SendTurnInput>;
|
|
7
|
+
export type { PrepareSend };
|
|
8
|
+
export type UseAshAgentStatus = AshAgentStoreStatus;
|
|
14
9
|
/**
|
|
15
10
|
* Current projected state for an Ash agent session.
|
|
16
11
|
*/
|
|
17
|
-
export
|
|
18
|
-
readonly data: TData;
|
|
19
|
-
readonly error: Error | undefined;
|
|
20
|
-
readonly events: readonly HandleMessageStreamEvent[];
|
|
21
|
-
readonly session: SessionState;
|
|
22
|
-
readonly status: UseAshAgentStatus;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Lifecycle callbacks invoked while `useAshAgent` processes a turn.
|
|
26
|
-
*/
|
|
27
|
-
interface UseAshAgentCallbacks<TData> {
|
|
28
|
-
readonly onError?: (error: Error) => void;
|
|
29
|
-
readonly onEvent?: (event: HandleMessageStreamEvent) => void;
|
|
30
|
-
readonly onFinish?: (snapshot: UseAshAgentSnapshot<TData>) => void;
|
|
31
|
-
readonly onSessionChange?: (session: SessionState) => void;
|
|
32
|
-
readonly prepareSend?: PrepareSend;
|
|
33
|
-
}
|
|
12
|
+
export type UseAshAgentSnapshot<TData> = AshAgentStoreSnapshot<TData>;
|
|
34
13
|
/**
|
|
35
14
|
* Snapshot plus commands returned by `useAshAgent`.
|
|
36
15
|
*/
|
|
@@ -52,7 +31,7 @@ export interface UseAshAgentHelpers<TData> extends UseAshAgentSnapshot<TData> {
|
|
|
52
31
|
* values to `auth` or `headers`; the underlying client resolves those before
|
|
53
32
|
* each HTTP request.
|
|
54
33
|
*/
|
|
55
|
-
export interface UseAshAgentOptions<TData> extends
|
|
34
|
+
export interface UseAshAgentOptions<TData> extends AshAgentStoreCallbacks<TData> {
|
|
56
35
|
readonly auth?: ClientAuth;
|
|
57
36
|
readonly headers?: HeadersValue;
|
|
58
37
|
/**
|
|
@@ -85,4 +64,3 @@ export declare function useAshAgent(options?: UseAshAgentOptions<AshMessageData>
|
|
|
85
64
|
export declare function useAshAgent<TData>(options: UseAshAgentOptions<TData> & {
|
|
86
65
|
readonly reducer: AshAgentReducer<TData>;
|
|
87
66
|
}): UseAshAgentHelpers<TData>;
|
|
88
|
-
export {};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)}function isAbortError(e){return e instanceof Error&&e.name===`AbortError`}function toTerminalStreamFailureError(e){if(e.type!==`session.failed`)return;let t=Error(e.data.message);return t.name=e.data.code,t}export{useAshAgent};
|
|
1
|
+
import{AshAgentStore}from"#client/ash-agent-store.js";import{defaultMessageReducer}from"#client/message-reducer.js";import{useCallback,useMemo,useRef,useSyncExternalStore}from"react";function useAshAgent(r={}){let i=useRef(void 0);if(!i.current){let n=r.reducer??defaultMessageReducer();i.current=new AshAgentStore({auth:r.auth,headers:r.headers,host:r.host,initialEvents:r.initialEvents,initialSession:r.initialSession,maxReconnectAttempts:r.maxReconnectAttempts,optimistic:r.optimistic,reducer:n,session:r.session})}let a=i.current;a.setCallbacks({onError:r.onError,onEvent:r.onEvent,onFinish:r.onFinish,onSessionChange:r.onSessionChange,prepareSend:r.prepareSend});let o=useSyncExternalStore(useCallback(e=>a.subscribe(e),[a]),()=>a.snapshot,()=>a.snapshot),s=useCallback(()=>a.reset(),[a]),c=useCallback((e,t)=>a.send(e,t),[a]),l=useCallback((e,t)=>a.sendMessage(e,t),[a]),u=useCallback(()=>a.stop(),[a]);return useMemo(()=>({...o,reset:s,send:c,sendMessage:l,stop:u}),[s,c,l,o,u])}export{useAshAgent};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { useAshAgent, type PrepareSend, type UseAshAgentOptions, type UseAshAgentReturn, type UseAshAgentSnapshot, type UseAshAgentStatus, } from "#svelte/use-ash-agent.js";
|
|
2
|
+
export { type AshAgentReducer, type AshAgentReducerEvent, type ClientInputRespondedEvent, type ClientMessageFailedEvent, type ClientMessageSubmittedEvent, } from "#client/reducer.js";
|
|
3
|
+
export { defaultMessageReducer, type AshMessageData, type AshDynamicToolPart, type AshMessageInputRequest, type AshMessage, type AshMessageMetadata, type AshMessagePart, type AshMessageToolMetadata, } from "#client/message-reducer.js";
|