@vite-hub/workflow 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +56 -6
  2. package/dist/{cloudflare-env-BVUMOgFK.d.ts → cloudflare-env-CIjdFTv6.d.ts} +2 -1
  3. package/dist/{cloudflare-env-g0Rf3ClH.js → cloudflare-env-mFp2Uj6Z.js} +7 -3
  4. package/dist/{cloudflare-vite-DcM5YVTP.js → cloudflare-vite-B0zel2Do.js} +4 -5
  5. package/dist/{config-DkgsQuXz.js → config-BDqB6I4E.js} +43 -5
  6. package/dist/index.d.ts +43 -18
  7. package/dist/index.js +99 -111
  8. package/dist/provider-operation-CWIV4k42.js +62 -0
  9. package/dist/runtime/cloudflare-runner.d.ts +2 -2
  10. package/dist/runtime/cloudflare-runner.js +15 -14
  11. package/dist/runtime/cloudflare-shared.d.ts +2 -2
  12. package/dist/runtime/cloudflare-shared.js +2 -2
  13. package/dist/runtime/cloudflare-vite.d.ts +3 -3
  14. package/dist/runtime/cloudflare-vite.js +1 -1
  15. package/dist/runtime/execute.d.ts +1 -1
  16. package/dist/runtime/openworkflow-worker.d.ts +4 -2
  17. package/dist/runtime/openworkflow-worker.js +63 -6
  18. package/dist/runtime/openworkflow.d.ts +22 -1
  19. package/dist/runtime/openworkflow.js +110 -37
  20. package/dist/runtime/state.d.ts +1 -1
  21. package/dist/runtime/vercel-vite.d.ts +58 -3
  22. package/dist/runtime/vercel-vite.js +3 -2
  23. package/dist/{types-ThDitg7Z.d.ts → types-BUlYBZwH.d.ts} +48 -6
  24. package/dist/vercel-D2_J5D_Y.js +217 -0
  25. package/dist/vite.d.ts +2 -5
  26. package/dist/vite.js +1753 -143
  27. package/package.json +45 -48
  28. package/dist/module-UYEnVfxy.js +0 -1546
  29. package/dist/nitro.d.ts +0 -19
  30. package/dist/nitro.js +0 -2
  31. package/dist/openworkflow-amN7IkGO.d.ts +0 -24
  32. package/dist/runtime/nitro-plugin.d.ts +0 -6
  33. package/dist/runtime/nitro-plugin.js +0 -14
  34. /package/dist/{_app-BVWpnNHo.d.ts → _app-DgwN4ulW.d.ts} +0 -0
  35. /package/dist/{app-BE3EYOWn.js → app-BZpq2cwC.js} +0 -0
  36. /package/dist/{cloudflare-CeHVSHoN.js → cloudflare-Cds1VIWa.js} +0 -0
  37. /package/dist/{cloudflare-shared-BIeY2kak.d.ts → cloudflare-shared-BVVgDSdq.d.ts} +0 -0
package/dist/vite.js CHANGED
@@ -1,10 +1,11 @@
1
- import { t as normalizeWorkflowOptions } from "./config-DkgsQuXz.js";
2
- import { r as getCloudflareWorkflowClassName, t as createCloudflareWorkflowBindings } from "./cloudflare-CeHVSHoN.js";
3
- import { a as createImportPath, i as computePackageDir, n as discoverWorkflowDefinitions, o as ensureGeneratedDir, r as createRuntimeRegistryContents, s as resolveRuntimeModule$1, t as workflowNitroModule } from "./module-UYEnVfxy.js";
4
- import { cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
5
- import { basename, resolve } from "node:path";
6
- import { existsSync } from "node:fs";
7
- import { dirname, relative as relative$1, resolve as resolve$1 } from "pathe";
1
+ import { t as normalizeWorkflowOptions } from "./config-BDqB6I4E.js";
2
+ import { r as getCloudflareWorkflowClassName, t as createCloudflareWorkflowBindings } from "./cloudflare-Cds1VIWa.js";
3
+ import { builtinModules, createRequire } from "node:module";
4
+ import { cp, mkdir, readFile, readdir, rm, rmdir, stat, symlink, writeFile } from "node:fs/promises";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
7
+ import { basename as basename$1, dirname as dirname$1, normalize, relative as relative$1, resolve as resolve$1 } from "pathe";
8
+ import { fileURLToPath } from "node:url";
8
9
  import { build } from "esbuild";
9
10
  const VITEHUB_MODES = {
10
11
  e2e: "e2e",
@@ -47,7 +48,7 @@ async function copyClientOutput(clientDir, targetDir) {
47
48
  force: true,
48
49
  recursive: true
49
50
  });
50
- await mkdir(dirname(resolvedTargetDir), { recursive: true });
51
+ await mkdir(dirname$1(resolvedTargetDir), { recursive: true });
51
52
  const targetRelativePath = relative$1(resolvedClientDir, resolvedTargetDir);
52
53
  if (targetRelativePath && !targetRelativePath.startsWith("../")) {
53
54
  const [targetRootEntry] = targetRelativePath.split("/", 1);
@@ -58,25 +59,135 @@ async function copyClientOutput(clientDir, targetDir) {
58
59
  await cp(resolvedClientDir, resolvedTargetDir, { recursive: true });
59
60
  }
60
61
  //#endregion
61
- //#region ../internal/src/build/esbuild.ts
62
- async function bundleEsmEntry(entryFile, outfile, options = {}) {
63
- const format = options.format || "esm";
64
- const platform = options.platform || "neutral";
65
- await build({
66
- alias: options.alias,
67
- banner: format === "esm" && platform === "node" ? { js: "import { createRequire as __createRequire } from \"node:module\";\nvar require = __createRequire(import.meta.url);\n" } : void 0,
68
- bundle: true,
69
- conditions: options.conditions,
70
- entryPoints: [entryFile],
71
- external: options.external,
72
- format,
73
- logLevel: "silent",
74
- outfile,
75
- platform,
76
- sourcemap: false,
77
- target: "es2022",
78
- write: true
62
+ //#region ../internal/src/build/provider-output-config.ts
63
+ function isProviderJsonArray(value, ancestors) {
64
+ if (Object.getPrototypeOf(value) !== Array.prototype || ancestors.has(value)) return false;
65
+ if (Reflect.ownKeys(value).length !== value.length + 1) return false;
66
+ ancestors.add(value);
67
+ try {
68
+ for (let index = 0; index < value.length; index++) {
69
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
70
+ if (!descriptor?.enumerable || !("value" in descriptor) || !isProviderJsonValue(descriptor.value, ancestors)) return false;
71
+ }
72
+ return true;
73
+ } finally {
74
+ ancestors.delete(value);
75
+ }
76
+ }
77
+ function isProviderJsonRecordValue(value, ancestors) {
78
+ const prototype = Object.getPrototypeOf(value);
79
+ if (prototype !== Object.prototype && prototype !== null || ancestors.has(value)) return false;
80
+ ancestors.add(value);
81
+ try {
82
+ return Reflect.ownKeys(value).every((key) => {
83
+ if (typeof key !== "string") return false;
84
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
85
+ return descriptor?.enumerable === true && "value" in descriptor && isProviderJsonValue(descriptor.value, ancestors);
86
+ });
87
+ } finally {
88
+ ancestors.delete(value);
89
+ }
90
+ }
91
+ function isProviderJsonValue(value, ancestors) {
92
+ if (value === null || typeof value === "boolean" || typeof value === "string") return true;
93
+ if (typeof value === "number") return Number.isFinite(value);
94
+ if (Array.isArray(value)) return isProviderJsonArray(value, ancestors);
95
+ return typeof value === "object" && isProviderJsonRecordValue(value, ancestors);
96
+ }
97
+ function isProviderJsonRecord(value) {
98
+ try {
99
+ return typeof value === "object" && value !== null && !Array.isArray(value) && isProviderJsonRecordValue(value, /* @__PURE__ */ new Set());
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+ function assertProviderJsonRecord(value) {
105
+ if (!isProviderJsonRecord(value)) throw new TypeError("[vitehub] Provider output config must be a JSON object.");
106
+ }
107
+ function isFileNotFoundError(error) {
108
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
109
+ }
110
+ async function readProviderJsonRecord(file) {
111
+ try {
112
+ const parsed = JSON.parse(await readFile(file, "utf8"));
113
+ assertProviderJsonRecord(parsed);
114
+ return parsed;
115
+ } catch (error) {
116
+ if (isFileNotFoundError(error)) return;
117
+ throw error;
118
+ }
119
+ }
120
+ function deleteOwnedFields(value, ownership) {
121
+ const next = { ...value };
122
+ for (const key of ownership.keys ?? []) delete next[key];
123
+ for (const field of Object.keys(ownership.arrays ?? {})) delete next[field];
124
+ return next;
125
+ }
126
+ function getKeyedArrayEntryValue(value, key) {
127
+ if (key === void 0) return value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string" ? value : void 0;
128
+ if (!isProviderJsonRecord(value)) return;
129
+ const entryValue = value[key];
130
+ return entryValue === null || typeof entryValue === "boolean" || typeof entryValue === "number" || typeof entryValue === "string" ? entryValue : void 0;
131
+ }
132
+ function preserveUnownedKeyedArrayEntries(value, ownership, replacements = []) {
133
+ const current = Array.isArray(value) ? value : [];
134
+ const replacementKeys = replacements.flatMap((entry) => {
135
+ const key = getKeyedArrayEntryValue(entry, ownership.key);
136
+ return key === void 0 ? [] : [key];
79
137
  });
138
+ const ownedKeys = new Set([...ownership.values ?? [], ...replacementKeys]);
139
+ return current.filter((entry) => {
140
+ const key = getKeyedArrayEntryValue(entry, ownership.key);
141
+ return key === void 0 || !ownedKeys.has(key);
142
+ });
143
+ }
144
+ function mergeOwnedArrays(existing, value, arrays) {
145
+ const next = { ...value };
146
+ for (const [field, ownership] of Object.entries(arrays ?? {})) {
147
+ const incoming = Array.isArray(value[field]) ? value[field] : [];
148
+ const merged = [...preserveUnownedKeyedArrayEntries(existing[field], ownership, incoming), ...incoming];
149
+ if (merged.length) next[field] = merged;
150
+ else delete next[field];
151
+ }
152
+ return next;
153
+ }
154
+ async function persistProviderJsonRecord(file, value, removeIfEmpty) {
155
+ if (removeIfEmpty && !Object.keys(value).length) {
156
+ await rm(file, { force: true });
157
+ return;
158
+ }
159
+ await writeFile(file, `${JSON.stringify(value, null, 2)}\n`, "utf8");
160
+ }
161
+ async function writeProviderOutputConfig(file, value, ownership = {}, options = {}) {
162
+ await persistProviderJsonRecord(file, mergeProviderOutputConfig(await readProviderJsonRecord(file) ?? {}, value, ownership), options.removeIfEmpty === true);
163
+ }
164
+ function mergeProviderOutputConfig(existing, value, ownership = {}) {
165
+ assertProviderJsonRecord(existing);
166
+ assertProviderJsonRecord(value);
167
+ return {
168
+ ...deleteOwnedFields(existing, ownership),
169
+ ...mergeOwnedArrays(existing, value, ownership.arrays)
170
+ };
171
+ }
172
+ function stringifyProviderOutputConfig(value) {
173
+ assertProviderJsonRecord(value);
174
+ return JSON.stringify(value, null, 2);
175
+ }
176
+ async function cleanProviderOutputConfig(file, ownership) {
177
+ if (!ownership.keys?.length && !Object.keys(ownership.arrays ?? {}).length) return;
178
+ const existing = await readProviderJsonRecord(file);
179
+ if (!existing) return;
180
+ const next = deleteOwnedFields(existing, ownership);
181
+ let changed = (ownership.keys ?? []).some((key) => key in existing);
182
+ for (const [field, arrayOwnership] of Object.entries(ownership.arrays ?? {})) {
183
+ if (!(field in existing)) continue;
184
+ const current = existing[field];
185
+ const preserved = preserveUnownedKeyedArrayEntries(current, arrayOwnership);
186
+ changed ||= !Array.isArray(current) || preserved.length !== current.length || preserved.length === 0;
187
+ if (preserved.length) next[field] = preserved;
188
+ }
189
+ if (!changed) return;
190
+ await persistProviderJsonRecord(file, next, true);
80
191
  }
81
192
  //#endregion
82
193
  //#region ../internal/src/build/user-entry.ts
@@ -99,6 +210,344 @@ function resolveUserAppEntry(rootDir, options = {}) {
99
210
  return names.map((name) => resolve(rootDir, srcSubdir, name)).find(existsSync);
100
211
  }
101
212
  //#endregion
213
+ //#region ../internal/src/build/cloudflare.ts
214
+ const defaultCloudflareCompatibilityDate = "2026-04-20";
215
+ function createDefaultCloudflareOutputRoot(rootDir) {
216
+ return resolve(rootDir, "dist", toSafeAppName(rootDir));
217
+ }
218
+ async function writeCloudflareWranglerConfig(options) {
219
+ const outputRoot = options.outputRoot ?? createDefaultCloudflareOutputRoot(options.rootDir);
220
+ const configFile = resolve(outputRoot, "wrangler.json");
221
+ if (!options.wranglerConfig) {
222
+ await cleanProviderOutputConfig(configFile, options.wranglerConfigOwnership ?? {});
223
+ return;
224
+ }
225
+ await mkdir(outputRoot, { recursive: true });
226
+ await writeProviderOutputConfig(configFile, options.wranglerConfig, options.wranglerConfigOwnership, { removeIfEmpty: true });
227
+ }
228
+ //#endregion
229
+ //#region ../internal/src/build/vite.ts
230
+ const projectRootDirectoryMarkers = [
231
+ ["server", "agents"],
232
+ ["server", "browsers"],
233
+ ["server", "schedules"],
234
+ ["server", "templates"],
235
+ ["server", "workspaces"]
236
+ ];
237
+ const projectRootDefinitionFileMarkers = [
238
+ ".ts",
239
+ ".mts",
240
+ ".cts",
241
+ ".js",
242
+ ".mjs",
243
+ ".cjs"
244
+ ].flatMap((extension) => [["server", `email${extension}`], [`server.email${extension}`]]);
245
+ const projectRootFileMarkers = [["package.json"]];
246
+ function createNoExternalMerger(packageName) {
247
+ return (current) => {
248
+ if (current === true) return true;
249
+ if (!current) return [packageName];
250
+ const values = Array.isArray(current) ? current : [current];
251
+ return values.includes(packageName) ? values : [...values, packageName];
252
+ };
253
+ }
254
+ function isServerEnvironment(name, config) {
255
+ return name === "ssr" || config.consumer === "server";
256
+ }
257
+ function includesNitroVitePlugin(value) {
258
+ if (Array.isArray(value)) return value.some(includesNitroVitePlugin);
259
+ if (!value || typeof value !== "object") return false;
260
+ return "name" in value && value.name === "nitro:main";
261
+ }
262
+ function hasNitroConfigContext(config) {
263
+ return config["__vitehubNitroConfigContext"] === true || includesNitroVitePlugin(config.plugins);
264
+ }
265
+ function resolveNitroVercelFunctionName(config, product, env = process.env) {
266
+ const preset = config.nitro?.preset || env.NITRO_PRESET || env.SERVER_PRESET;
267
+ const nitro = Boolean(preset) || hasNitroConfigContext(config);
268
+ const clientOutDir = config.environments?.client?.build?.outDir;
269
+ const vercel = preset ? preset.startsWith("vercel") : env.VITEHUB_HOSTING === "vercel" || Boolean(env.VERCEL) || Boolean(clientOutDir && /(^|[/\\])\.vercel[/\\]output([/\\]|$)/.test(clientOutDir));
270
+ return nitro && vercel ? `__${product}.func` : void 0;
271
+ }
272
+ function shouldSkipViteProviderBuild(command, mode) {
273
+ return command === "serve" || mode === "e2e";
274
+ }
275
+ function resolveViteHubProjectRoot(root, options = {}) {
276
+ const resolvedRoot = resolve(root);
277
+ if (options.projectRoot) return resolve(resolvedRoot, options.projectRoot);
278
+ if (basename(resolvedRoot) === "app") {
279
+ const parent = dirname(resolvedRoot);
280
+ if (hasProjectRootDirectoryMarker(parent) || hasProjectRootDefinitionFileMarker(parent)) return parent;
281
+ }
282
+ let current = resolvedRoot;
283
+ while (true) {
284
+ if (hasProjectRootMarker(current)) return current;
285
+ const parent = dirname(current);
286
+ if (parent === current) return resolvedRoot;
287
+ current = parent;
288
+ }
289
+ }
290
+ function hasProjectRootDirectoryMarker(root) {
291
+ for (const marker of projectRootDirectoryMarkers) try {
292
+ if (statSync(resolve(root, ...marker)).isDirectory()) return true;
293
+ } catch (error) {
294
+ if (error.code !== "ENOENT") throw error;
295
+ }
296
+ return false;
297
+ }
298
+ function hasProjectRootMarker(root) {
299
+ if (hasProjectRootDirectoryMarker(root)) return true;
300
+ if (hasProjectRootDefinitionFileMarker(root)) return true;
301
+ for (const marker of projectRootFileMarkers) try {
302
+ if (statSync(resolve(root, ...marker)).isFile()) return true;
303
+ } catch (error) {
304
+ if (error.code !== "ENOENT") throw error;
305
+ }
306
+ return false;
307
+ }
308
+ function hasProjectRootDefinitionFileMarker(root) {
309
+ for (const marker of projectRootDefinitionFileMarkers) try {
310
+ if (statSync(resolve(root, ...marker)).isFile()) return true;
311
+ } catch (error) {
312
+ if (error.code !== "ENOENT") throw error;
313
+ }
314
+ return false;
315
+ }
316
+ //#endregion
317
+ //#region ../internal/src/build/esbuild.ts
318
+ const viteRawNamespace = "vitehub-vite-raw";
319
+ const viteMarkdownTemplateNamespace = "vitehub-markdown-template";
320
+ const markdownTemplateFileSuffix = ".template.md";
321
+ const markdownTemplateModuleQuery = "markdown-template";
322
+ const markdownTemplateRegistryId = "#vitehub/templates";
323
+ const markdownTemplateRegistryPath = ".vitehub/markdown-template/templates.mjs";
324
+ const skipMarkdownTemplateResolve = "vitehubSkipMarkdownTemplateResolve";
325
+ const markdownTemplateRuntimeSpecifier = "@vite-hub/markdown-template";
326
+ function resolveEsbuildAliases(aliases) {
327
+ if (!aliases) return;
328
+ return Object.fromEntries(Object.entries(aliases).filter(([specifier]) => !specifier.endsWith("/")));
329
+ }
330
+ function stripMarkdownCode(template) {
331
+ let fence;
332
+ let inList = false;
333
+ let previousLineBlank = true;
334
+ return template.split("\n").map((line) => {
335
+ const content = line.replace(/^(?: {0,3}> ?)+/, "");
336
+ if (!fence) {
337
+ const listIndented = inList && /^ {4}(?:`{3,}|~{3,})/.test(content);
338
+ const opening = (listIndented ? content.slice(4) : content).match(/^ {0,3}(`{3,}|~{3,})/);
339
+ if (!opening) {
340
+ if (/^ {0,3}(?:[-+*]|\d+[.)])\s+/.test(content)) inList = true;
341
+ else if (content.trim() && !/^ {2,}/.test(content)) inList = false;
342
+ const indentedCode = !inList && previousLineBlank && /^(?: {4}|\t)/.test(content) || inList && previousLineBlank && /^(?: {8}| {4}\t|\t{2})/.test(content);
343
+ previousLineBlank = content.trim() === "";
344
+ return indentedCode ? "" : line;
345
+ }
346
+ fence = {
347
+ marker: opening[1][0],
348
+ length: opening[1].length,
349
+ listIndented
350
+ };
351
+ previousLineBlank = false;
352
+ return "";
353
+ }
354
+ const closing = (fence.listIndented ? content.replace(/^ {4}/, "") : content).match(/^ {0,3}(`+|~+)\s*$/)?.[1];
355
+ if (closing?.[0] === fence.marker && closing.length >= fence.length) fence = void 0;
356
+ previousLineBlank = false;
357
+ return "";
358
+ }).join("\n");
359
+ }
360
+ function extractMarkdownTemplateImportSpecifiers(template) {
361
+ const visible = stripMarkdownCode(template).replace(/(`+)[\s\S]*?\1/g, "").replace(/(!?\[[^\]]*\])\([^)]*\)/g, "$1").replace(/^ {0,3}\[[^\]]+\]:\s*\S+/gm, "").replace(/<[^>]*>/g, "");
362
+ const specifiers = /* @__PURE__ */ new Set();
363
+ for (const match of visible.matchAll(/@(\.\.?\/[^\s<>{}[\]]+)/g)) {
364
+ const token = match[1];
365
+ const trailing = token.match(/[.,;:!?)]*$/)?.[0] || "";
366
+ specifiers.add(token.slice(0, token.length - trailing.length));
367
+ }
368
+ return [...specifiers];
369
+ }
370
+ function parseMarkdownTemplateRequest(id) {
371
+ const queryIndex = id.indexOf("?");
372
+ const path = id.split(/[?#]/, 1)[0];
373
+ if (queryIndex === -1) return path.endsWith(markdownTemplateFileSuffix) ? { path } : void 0;
374
+ const query = id.slice(queryIndex + 1).split("#", 1)[0];
375
+ if (!new URLSearchParams(query).has(markdownTemplateModuleQuery)) return;
376
+ return { path };
377
+ }
378
+ function renderMarkdownTemplateModule(template, sourceId, imports = {}) {
379
+ return [
380
+ `import { renderMarkdownTemplate as vitehubRenderMarkdownTemplate } from ${JSON.stringify(markdownTemplateRuntimeSpecifier)}`,
381
+ `const vitehubMarkdownTemplate = ${JSON.stringify(template)}`,
382
+ `const vitehubMarkdownTemplateSourceId = ${JSON.stringify(sourceId)}`,
383
+ `const vitehubMarkdownTemplateImports = ${JSON.stringify(imports)}`,
384
+ "export default function render(data = {}) {",
385
+ " return vitehubRenderMarkdownTemplate(vitehubMarkdownTemplate, { data, sourceId: vitehubMarkdownTemplateSourceId, resolveImport: (specifier, importer) => vitehubMarkdownTemplateImports[`${importer}\\0${specifier}`] })",
386
+ "}",
387
+ ""
388
+ ].join("\n");
389
+ }
390
+ function hasViteRawQuery(path) {
391
+ const queryIndex = path.indexOf("?");
392
+ return queryIndex !== -1 && /(?:^|&)raw(?:&|$)/.test(path.slice(queryIndex + 1));
393
+ }
394
+ async function resolveViteRawSpecifier(path, rootDir) {
395
+ if (path.startsWith("/@fs/")) return path.slice(5);
396
+ if (!rootDir || !path.startsWith("/")) return path;
397
+ const rootRelativePath = path.slice(1);
398
+ const publicPath = resolve(rootDir, "public", rootRelativePath);
399
+ try {
400
+ await stat(publicPath);
401
+ return publicPath;
402
+ } catch (error) {
403
+ if (error.code !== "ENOENT") throw error;
404
+ return resolve(rootDir, rootRelativePath);
405
+ }
406
+ }
407
+ function createViteRawPlugin(rootDir, frameworkRuntime) {
408
+ return {
409
+ name: "vitehub-vite-raw",
410
+ setup(build) {
411
+ build.onResolve({
412
+ filter: /^@vite-hub\/markdown-template$/,
413
+ namespace: viteMarkdownTemplateNamespace
414
+ }, async (args) => {
415
+ if (!frameworkRuntime) return { path: fileURLToPath(import.meta.resolve(markdownTemplateRuntimeSpecifier)) };
416
+ return build.resolve("vite-hub/_internal/markdown-template", {
417
+ importer: args.importer,
418
+ kind: args.kind,
419
+ resolveDir: args.resolveDir
420
+ });
421
+ });
422
+ build.onResolve({ filter: /\?|\.template\.md$/ }, async (args) => {
423
+ if (args.pluginData?.[skipMarkdownTemplateResolve]) return;
424
+ const markdownTemplate = parseMarkdownTemplateRequest(args.path);
425
+ const raw = hasViteRawQuery(args.path);
426
+ if (!markdownTemplate && !raw) return;
427
+ const specifier = await resolveViteRawSpecifier(markdownTemplate?.path ?? args.path.slice(0, args.path.indexOf("?")), rootDir);
428
+ const resolved = await build.resolve(specifier, {
429
+ importer: args.importer,
430
+ kind: args.kind,
431
+ namespace: args.namespace,
432
+ pluginData: markdownTemplate ? {
433
+ ...args.pluginData && typeof args.pluginData === "object" ? args.pluginData : {},
434
+ [skipMarkdownTemplateResolve]: true
435
+ } : args.pluginData,
436
+ resolveDir: args.resolveDir,
437
+ with: args.with
438
+ });
439
+ if (resolved.errors.length) return {
440
+ errors: resolved.errors,
441
+ warnings: resolved.warnings
442
+ };
443
+ if (resolved.external) return {
444
+ external: true,
445
+ namespace: resolved.namespace,
446
+ path: resolved.path,
447
+ pluginData: resolved.pluginData,
448
+ sideEffects: resolved.sideEffects,
449
+ suffix: resolved.suffix,
450
+ warnings: resolved.warnings
451
+ };
452
+ if (resolved.namespace !== "file") return {
453
+ errors: [{ text: markdownTemplate ? `[vitehub] Markdown template fallback cannot load ${JSON.stringify(args.path)} from the ${JSON.stringify(resolved.namespace)} namespace. Handle this template import in a caller plugin.` : `[vitehub] Vite raw fallback cannot load ${JSON.stringify(args.path)} from the ${JSON.stringify(resolved.namespace)} namespace. Handle this raw import in a caller plugin.` }],
454
+ warnings: resolved.warnings
455
+ };
456
+ return {
457
+ namespace: markdownTemplate ? viteMarkdownTemplateNamespace : viteRawNamespace,
458
+ path: resolved.path,
459
+ pluginData: resolved.pluginData,
460
+ sideEffects: resolved.sideEffects,
461
+ suffix: resolved.suffix,
462
+ warnings: resolved.warnings
463
+ };
464
+ });
465
+ build.onLoad({
466
+ filter: /.*/,
467
+ namespace: viteRawNamespace
468
+ }, async (args) => ({
469
+ contents: await readFile(args.path),
470
+ loader: "text"
471
+ }));
472
+ build.onLoad({
473
+ filter: /.*/,
474
+ namespace: viteMarkdownTemplateNamespace
475
+ }, async (args) => ({
476
+ contents: await (async () => {
477
+ const template = await readFile(args.path, "utf8");
478
+ const imports = {};
479
+ const visited = new Set([args.path]);
480
+ const visit = async (source, importer) => {
481
+ for (const specifier of extractMarkdownTemplateImportSpecifiers(source)) {
482
+ const key = `${importer}\0${specifier}`;
483
+ if (imports[key]) continue;
484
+ const resolved = await build.resolve(specifier, {
485
+ importer,
486
+ kind: "import-statement",
487
+ pluginData: {
488
+ ...args.pluginData && typeof args.pluginData === "object" ? args.pluginData : {},
489
+ [skipMarkdownTemplateResolve]: true
490
+ },
491
+ resolveDir: dirname(importer)
492
+ });
493
+ if (resolved.errors.length) return Promise.reject(new Error(resolved.errors.map((error) => error.text).join("\n")));
494
+ if (resolved.external || resolved.namespace !== "file") throw new Error(`[vitehub] Could not resolve Markdown template import ${JSON.stringify(specifier)} from ${JSON.stringify(importer)} to a file.`);
495
+ const imported = {
496
+ id: resolved.path,
497
+ template: await readFile(resolved.path, "utf8")
498
+ };
499
+ imports[key] = imported;
500
+ if (!visited.has(imported.id)) {
501
+ visited.add(imported.id);
502
+ await visit(imported.template, imported.id);
503
+ }
504
+ }
505
+ };
506
+ await visit(template, args.path);
507
+ return renderMarkdownTemplateModule(template, args.path, imports);
508
+ })(),
509
+ loader: "js",
510
+ resolveDir: dirname(args.path)
511
+ }));
512
+ }
513
+ };
514
+ }
515
+ async function bundleEsmEntry(entryFile, outfile, options = {}) {
516
+ const format = options.format || "esm";
517
+ const platform = options.platform || "neutral";
518
+ const markdownTemplateRoot = options.rootDir && resolveViteHubProjectRoot(options.rootDir);
519
+ const aliases = resolveEsbuildAliases({
520
+ ...markdownTemplateRoot ? { [markdownTemplateRegistryId]: resolve(markdownTemplateRoot, markdownTemplateRegistryPath) } : {},
521
+ ...options.alias
522
+ });
523
+ const frameworkRuntime = Object.keys(aliases || {}).some((specifier) => specifier === "vite-hub" || specifier.startsWith("vite-hub/"));
524
+ await build({
525
+ alias: aliases,
526
+ banner: options.banner || format === "esm" && platform === "node" ? { js: [options.banner, ...format === "esm" && platform === "node" ? [
527
+ "import { createRequire as __createRequire } from \"node:module\";",
528
+ "import { dirname as __vitehubDirname } from \"node:path\";",
529
+ "import { fileURLToPath as __vitehubFileURLToPath } from \"node:url\";",
530
+ "globalThis.require = __createRequire(import.meta.url);",
531
+ "globalThis.__filename = __vitehubFileURLToPath(import.meta.url);",
532
+ "globalThis.__dirname = __vitehubDirname(globalThis.__filename);"
533
+ ] : []].filter(Boolean).join("\n") } : void 0,
534
+ bundle: true,
535
+ conditions: options.conditions ?? (platform === "node" ? ["node"] : void 0),
536
+ entryPoints: [entryFile],
537
+ external: options.external,
538
+ format,
539
+ logLevel: "silent",
540
+ mainFields: options.mainFields ?? (platform === "neutral" ? ["module", "main"] : void 0),
541
+ minifyIdentifiers: options.minifyIdentifiers,
542
+ outfile,
543
+ platform,
544
+ plugins: [...options.plugins ?? [], createViteRawPlugin(options.rootDir, frameworkRuntime)],
545
+ sourcemap: false,
546
+ target: "es2022",
547
+ write: true
548
+ });
549
+ }
550
+ //#endregion
102
551
  //#region ../internal/src/build/vercel-config.ts
103
552
  function createVercelConfigJson() {
104
553
  return {
@@ -121,6 +570,7 @@ function createNodeFunctionConfig(extra = {}) {
121
570
  }
122
571
  //#endregion
123
572
  //#region ../internal/src/build/deployment-output.ts
573
+ const providerDeploymentOutputWrites = /* @__PURE__ */ new Map();
124
574
  function resolveClientOutput(rootDir, clientOutDir) {
125
575
  const clientDir = resolve(rootDir, clientOutDir);
126
576
  return {
@@ -128,103 +578,135 @@ function resolveClientOutput(rootDir, clientOutDir) {
128
578
  staticIndex: hasStaticIndex(clientDir)
129
579
  };
130
580
  }
131
- function isJsonObject(value) {
132
- return typeof value === "object" && value !== null && !Array.isArray(value);
133
- }
134
- async function readJsonObject(file) {
135
- try {
136
- const parsed = JSON.parse(await readFile(file, "utf8"));
137
- return isJsonObject(parsed) ? parsed : {};
138
- } catch (error) {
139
- if (error.code === "ENOENT") return {};
140
- throw error;
141
- }
142
- }
143
- function deleteJsonObjectKeys(value, keys) {
144
- if (!keys?.length) return value;
145
- const next = { ...value };
146
- for (const key of keys) delete next[key];
147
- return next;
148
- }
149
- async function writeMergedJsonObject(file, value, ownedKeys) {
150
- const existing = await readJsonObject(file);
151
- await writeFile(file, `${JSON.stringify({
152
- ...deleteJsonObjectKeys(existing, ownedKeys),
153
- ...value
154
- }, null, 2)}\n`, "utf8");
155
- }
156
- async function deleteJsonObjectKeysFromFile(file, keys) {
157
- if (!keys?.length) return;
158
- let existing;
159
- try {
160
- const parsed = JSON.parse(await readFile(file, "utf8"));
161
- existing = isJsonObject(parsed) ? parsed : {};
162
- } catch (error) {
163
- if (error.code === "ENOENT") return;
164
- throw error;
165
- }
166
- const next = { ...existing };
167
- let changed = false;
168
- for (const key of keys) if (key in next) {
169
- delete next[key];
170
- changed = true;
171
- }
172
- if (!changed) return;
173
- await writeFile(file, `${JSON.stringify(next, null, 2)}\n`, "utf8");
174
- }
175
- function shouldSkipViteProviderBuild(command, mode) {
176
- return command === "serve" || mode === "e2e";
177
- }
178
- function createDefaultCloudflareOutputRoot(rootDir) {
179
- return resolve(rootDir, "dist", toSafeAppName(rootDir));
180
- }
181
581
  function createDefaultCloudflareStaticOutputDir(rootDir) {
182
582
  return resolve(rootDir, "dist", "client");
183
583
  }
184
584
  function createDefaultVercelOutputRoot(rootDir) {
185
585
  return resolve(rootDir, ".vercel", "output");
186
586
  }
587
+ function createDefaultNetlifyOutputRoot(rootDir) {
588
+ return resolve(rootDir, ".netlify", "v1");
589
+ }
590
+ function assertNetlifyFunctionName(functionName) {
591
+ if (!functionName || functionName.includes("\\") || functionName.split("/").some((part) => !part || part === "." || part === "..")) throw new Error(`Invalid Netlify function name: ${functionName}`);
592
+ }
593
+ function resolveNetlifyFunctionFile(functionsRoot, functionName) {
594
+ assertNetlifyFunctionName(functionName);
595
+ return resolve(functionsRoot, `${functionName}.mjs`);
596
+ }
597
+ async function appendNetlifyFunctionConfig(outfile, config) {
598
+ if (!config) return;
599
+ await writeFile(outfile, `${(await readFile(outfile, "utf8")).trimEnd()}\n\nexport const config = ${stringifyProviderOutputConfig(config)}\n`, "utf8");
600
+ }
187
601
  async function writeCloudflareDeploymentOutput(options) {
188
602
  const { clientDir, staticIndex } = resolveClientOutput(options.rootDir, options.clientOutDir);
189
603
  const outputRoot = options.outputRoot ?? createDefaultCloudflareOutputRoot(options.rootDir);
190
- const workerOutfile = resolve(outputRoot, options.bundleOutfileName ?? "index.js");
604
+ const files = Object.entries(options.files ?? {});
605
+ const workerOutfile = options.bundleEntry ? resolve(outputRoot, options.bundleOutfileName ?? "index.js") : void 0;
606
+ if (workerOutfile && files.some(([fileName]) => resolve(outputRoot, fileName) === workerOutfile)) throw new Error(`Cloudflare output file conflicts with bundle outfile: ${workerOutfile}`);
191
607
  await mkdir(outputRoot, { recursive: true });
192
- await rm(workerOutfile, {
608
+ const writes = [
609
+ writeCloudflareWranglerConfig({
610
+ outputRoot,
611
+ rootDir: options.rootDir,
612
+ wranglerConfig: options.wranglerConfig,
613
+ wranglerConfigOwnership: options.wranglerConfigOwnership ?? { keys: options.wranglerConfigKeys }
614
+ }),
615
+ options.bundleEntry && staticIndex ? copyClientOutput(clientDir, options.staticOutputDir ?? createDefaultCloudflareStaticOutputDir(options.rootDir)) : Promise.resolve(),
616
+ ...files.map(([fileName, contents]) => writeFile(resolve(outputRoot, fileName), contents, "utf8"))
617
+ ];
618
+ if (options.bundleEntry && workerOutfile) {
619
+ await rm(workerOutfile, {
620
+ force: true,
621
+ recursive: true
622
+ });
623
+ writes.push(bundleEsmEntry(options.bundleEntry, workerOutfile, {
624
+ ...options.bundleOptions,
625
+ rootDir: options.rootDir
626
+ }));
627
+ }
628
+ await Promise.all(writes);
629
+ }
630
+ async function copyVercelClientOutput(rootDir, clientDir, staticOutputDir) {
631
+ const cloudflareOutputRoot = createDefaultCloudflareOutputRoot(rootDir);
632
+ const outputRelativePath = relative(clientDir, cloudflareOutputRoot);
633
+ const excludesCloudflareOutput = outputRelativePath && outputRelativePath !== ".." && !outputRelativePath.startsWith(`..${sep}`) && !isAbsolute(outputRelativePath);
634
+ await copyClientOutput(clientDir, staticOutputDir);
635
+ if (resolve(clientDir) === resolve(staticOutputDir) || !excludesCloudflareOutput) return;
636
+ try {
637
+ await readFile(resolve(cloudflareOutputRoot, "wrangler.json"));
638
+ } catch (error) {
639
+ if (error.code === "ENOENT") return;
640
+ throw error;
641
+ }
642
+ await rm(resolve(staticOutputDir, outputRelativePath), {
193
643
  force: true,
194
644
  recursive: true
195
645
  });
196
- await Promise.all([
197
- bundleEsmEntry(options.bundleEntry, workerOutfile, options.bundleOptions),
198
- writeMergedJsonObject(resolve(outputRoot, "wrangler.json"), options.wranglerConfig, options.wranglerConfigKeys),
199
- staticIndex ? copyClientOutput(clientDir, options.staticOutputDir ?? createDefaultCloudflareStaticOutputDir(options.rootDir)) : Promise.resolve()
200
- ]);
201
646
  }
202
647
  async function writeVercelDeploymentOutput(options) {
203
648
  const { clientDir, staticIndex } = resolveClientOutput(options.rootDir, options.clientOutDir);
204
649
  const outputRoot = options.outputRoot ?? createDefaultVercelOutputRoot(options.rootDir);
205
- const serverDir = resolve(outputRoot, "functions", options.serverFunctionName ?? "__server.func");
650
+ const functionOutput = options.function ?? { kind: "root" };
651
+ const serverFunctionName = functionOutput.kind === "root" ? "__server.func" : functionOutput.name;
652
+ const config = options.config ?? (functionOutput.kind === "root" ? createVercelConfigJson() : {});
653
+ const serverDir = resolve(outputRoot, "functions", serverFunctionName);
206
654
  const serverEntry = resolve(serverDir, "index.mjs");
207
- await rm(serverDir, {
655
+ await mkdir(serverDir, { recursive: true });
656
+ const staleFiles = (await readdir(serverDir)).filter((file) => file !== "node_modules");
657
+ await Promise.all(staleFiles.map((file) => rm(resolve(serverDir, file), {
208
658
  force: true,
209
659
  recursive: true
210
- });
211
- await mkdir(serverDir, { recursive: true });
660
+ })));
212
661
  await Promise.all([
213
- bundleEsmEntry(options.bundleEntry, serverEntry, options.bundleOptions),
214
- writeFile(resolve(serverDir, ".vc-config.json"), `${JSON.stringify(options.functionConfig ?? createNodeFunctionConfig(), null, 2)}\n`, "utf8"),
215
- writeMergedJsonObject(resolve(outputRoot, "config.json"), options.config ?? createVercelConfigJson(), options.configKeys),
216
- staticIndex ? copyClientOutput(clientDir, options.staticOutputDir ?? resolve(outputRoot, "static")) : Promise.resolve()
662
+ bundleEsmEntry(options.bundleEntry, serverEntry, {
663
+ ...options.bundleOptions,
664
+ rootDir: options.rootDir
665
+ }),
666
+ writeFile(resolve(serverDir, ".vc-config.json"), `${stringifyProviderOutputConfig(options.functionConfig ?? createNodeFunctionConfig())}\n`, "utf8"),
667
+ writeProviderOutputConfig(resolve(outputRoot, "config.json"), config, { keys: options.configKeys }),
668
+ staticIndex ? copyVercelClientOutput(options.rootDir, clientDir, options.staticOutputDir ?? resolve(outputRoot, "static")) : Promise.resolve()
217
669
  ]);
218
670
  }
219
- async function cleanupCloudflareDeploymentOutput(rootDir, cleanup) {
671
+ async function writeNetlifyDeploymentOutput(options) {
672
+ const outputRoot = options.outputRoot ?? createDefaultNetlifyOutputRoot(options.rootDir);
673
+ const functionsRoot = resolve(outputRoot, "functions");
674
+ const functionWrites = (options.functions ?? []).map(async (func) => {
675
+ const outfile = resolveNetlifyFunctionFile(functionsRoot, func.functionName);
676
+ await rm(outfile, {
677
+ force: true,
678
+ recursive: true
679
+ });
680
+ await mkdir(dirname(outfile), { recursive: true });
681
+ await bundleEsmEntry(func.bundleEntry, outfile, {
682
+ ...func.bundleOptions,
683
+ minifyIdentifiers: func.config ? true : func.bundleOptions.minifyIdentifiers,
684
+ rootDir: options.rootDir
685
+ });
686
+ await appendNetlifyFunctionConfig(outfile, func.config);
687
+ });
688
+ await mkdir(outputRoot, { recursive: true });
689
+ await Promise.all([writeProviderOutputConfig(resolve(outputRoot, "config.json"), options.config ?? {}, { keys: options.configKeys }), ...functionWrites]);
690
+ }
691
+ async function cleanupCloudflareDeploymentOutput(rootDir, cleanupInput) {
692
+ const cleanup = typeof cleanupInput === "function" ? await cleanupInput() : cleanupInput;
220
693
  const outputRoot = cleanup.outputRoot ?? createDefaultCloudflareOutputRoot(rootDir);
221
- const writes = [];
222
- if (cleanup.bundleOutfileName) writes.push(rm(resolve(outputRoot, cleanup.bundleOutfileName), {
694
+ const writes = (cleanup.fileNames ?? []).map((fileName) => rm(resolve(outputRoot, fileName), {
223
695
  force: true,
224
696
  recursive: true
225
697
  }));
226
- writes.push(deleteJsonObjectKeysFromFile(resolve(outputRoot, "wrangler.json"), cleanup.wranglerConfigKeys));
698
+ writes.push(writeCloudflareWranglerConfig({
699
+ outputRoot,
700
+ rootDir,
701
+ wranglerConfigOwnership: cleanup.wranglerConfigOwnership
702
+ }));
227
703
  await Promise.all(writes);
704
+ try {
705
+ await rmdir(outputRoot);
706
+ } catch (error) {
707
+ const code = error.code;
708
+ if (code !== "ENOENT" && code !== "ENOTEMPTY") throw error;
709
+ }
228
710
  }
229
711
  async function cleanupVercelDeploymentOutput(rootDir, cleanup) {
230
712
  const outputRoot = cleanup.outputRoot ?? createDefaultVercelOutputRoot(rootDir);
@@ -233,10 +715,23 @@ async function cleanupVercelDeploymentOutput(rootDir, cleanup) {
233
715
  force: true,
234
716
  recursive: true
235
717
  }));
236
- writes.push(deleteJsonObjectKeysFromFile(resolve(outputRoot, "config.json"), cleanup.configKeys));
718
+ writes.push(cleanProviderOutputConfig(resolve(outputRoot, "config.json"), { keys: cleanup.configKeys }));
237
719
  await Promise.all(writes);
238
720
  }
239
- async function writeProviderDeploymentOutputs(options) {
721
+ async function cleanupVercelDeploymentOutputs(rootDir, cleanup) {
722
+ await Promise.all((Array.isArray(cleanup) ? cleanup : [cleanup]).map((item) => cleanupVercelDeploymentOutput(rootDir, item)));
723
+ }
724
+ async function cleanupNetlifyDeploymentOutput(rootDir, cleanup) {
725
+ const outputRoot = cleanup.outputRoot ?? createDefaultNetlifyOutputRoot(rootDir);
726
+ const functionsRoot = resolve(outputRoot, "functions");
727
+ const writes = (cleanup.functionNames ?? []).map((functionName) => rm(resolveNetlifyFunctionFile(functionsRoot, functionName), {
728
+ force: true,
729
+ recursive: true
730
+ }));
731
+ writes.push(cleanProviderOutputConfig(resolve(outputRoot, "config.json"), { keys: cleanup.configKeys }));
732
+ await Promise.all(writes);
733
+ }
734
+ async function writeProviderDeploymentOutputsNow(options) {
240
735
  const writes = [];
241
736
  if (options.cloudflare) writes.push(writeCloudflareDeploymentOutput({
242
737
  ...options.cloudflare,
@@ -244,37 +739,836 @@ async function writeProviderDeploymentOutputs(options) {
244
739
  rootDir: options.rootDir
245
740
  }));
246
741
  else if (options.cleanup?.cloudflare) writes.push(cleanupCloudflareDeploymentOutput(options.rootDir, options.cleanup.cloudflare));
742
+ if (options.netlify) writes.push(writeNetlifyDeploymentOutput({
743
+ ...options.netlify,
744
+ clientOutDir: options.clientOutDir,
745
+ rootDir: options.rootDir
746
+ }));
747
+ else if (options.cleanup?.netlify) writes.push(cleanupNetlifyDeploymentOutput(options.rootDir, options.cleanup.netlify));
247
748
  if (options.vercel) writes.push(writeVercelDeploymentOutput({
248
749
  ...options.vercel,
249
750
  clientOutDir: options.clientOutDir,
250
751
  rootDir: options.rootDir
251
752
  }));
252
- else if (options.cleanup?.vercel) writes.push(cleanupVercelDeploymentOutput(options.rootDir, options.cleanup.vercel));
753
+ else if (options.cleanup?.vercel) {
754
+ const cleanup = typeof options.cleanup.vercel === "function" ? await options.cleanup.vercel() : options.cleanup.vercel;
755
+ if (cleanup) writes.push(cleanupVercelDeploymentOutputs(options.rootDir, cleanup));
756
+ }
253
757
  await Promise.all(writes);
758
+ await options.afterWrite?.();
759
+ }
760
+ async function writeProviderDeploymentOutputs(options) {
761
+ const key = resolve(options.rootDir);
762
+ const write = (providerDeploymentOutputWrites.get(key) ?? Promise.resolve()).catch(() => void 0).then(() => writeProviderDeploymentOutputsNow(options));
763
+ providerDeploymentOutputWrites.set(key, write);
764
+ try {
765
+ await write;
766
+ } finally {
767
+ if (providerDeploymentOutputWrites.get(key) === write) providerDeploymentOutputWrites.delete(key);
768
+ }
254
769
  }
255
770
  //#endregion
256
- //#region ../internal/src/build/vite.ts
257
- function createNoExternalMerger(packageName) {
258
- return (current) => {
259
- if (current === true) return true;
260
- if (!current) return [packageName];
261
- const values = Array.isArray(current) ? current : [current];
262
- return values.includes(packageName) ? values : [...values, packageName];
771
+ //#region ../internal/src/build/colocated-agent-files.ts
772
+ function formatSize(bytes) {
773
+ const mebibyte = 1024 * 1024;
774
+ return bytes % mebibyte === 0 ? `${bytes / mebibyte} MiB` : `${bytes} bytes`;
775
+ }
776
+ function isFolderAgentEntry(file) {
777
+ if (!/^(?:agent|index)\.(?:c|m)?[jt]s$/i.test(basename(file))) return false;
778
+ return !(basename(file).toLowerCase().startsWith("agent.") && basename(dirname(file)) === "agents" && basename(dirname(dirname(file))) === "server");
779
+ }
780
+ function readColocatedAgentFiles(handler, directoryName, options = {}) {
781
+ if (!isFolderAgentEntry(handler)) return;
782
+ const root = join(dirname(handler), directoryName);
783
+ if (!existsSync(root)) return;
784
+ if (!(options.rejectUnsupportedEntries ? lstatSync(root) : statSync(root)).isDirectory()) {
785
+ if (options.rejectUnsupportedEntries) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} supports regular files and directories only: ${directoryName}`);
786
+ return;
787
+ }
788
+ const files = {};
789
+ let fileCount = 0;
790
+ let totalSize = 0;
791
+ const visit = (directory) => {
792
+ for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
793
+ const file = join(directory, entry.name);
794
+ const target = relative(root, file).replace(/\\/g, "/");
795
+ if (entry.isDirectory()) {
796
+ visit(file);
797
+ continue;
798
+ }
799
+ if (!entry.isFile()) {
800
+ if (options.rejectUnsupportedEntries) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} supports regular files and directories only: ${target}`);
801
+ continue;
802
+ }
803
+ const size = statSync(file).size;
804
+ fileCount += 1;
805
+ if (options.fileCountLimit !== void 0 && fileCount > options.fileCountLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${options.fileCountLimit} files.`);
806
+ if (options.fileSizeLimit !== void 0 && size > options.fileSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent file"} file exceeds ${formatSize(options.fileSizeLimit)}: ${target}`);
807
+ totalSize += size;
808
+ if (options.totalSizeLimit !== void 0 && totalSize > options.totalSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${formatSize(options.totalSizeLimit)}.`);
809
+ const content = readFileSync(file);
810
+ if (content.byteLength !== size) {
811
+ if (options.fileSizeLimit !== void 0 && content.byteLength > options.fileSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent file"} file exceeds ${formatSize(options.fileSizeLimit)}: ${target}`);
812
+ totalSize += content.byteLength - size;
813
+ if (options.totalSizeLimit !== void 0 && totalSize > options.totalSizeLimit) throw new Error(`[vitehub] ${options.label || "Colocated Agent files"} exceeds ${formatSize(options.totalSizeLimit)}.`);
814
+ }
815
+ files[target] = {
816
+ content: content.toString("base64"),
817
+ encoding: "base64"
818
+ };
819
+ }
263
820
  };
821
+ visit(root);
822
+ return Object.keys(files).length ? files : void 0;
264
823
  }
265
- function isServerEnvironment(name, config) {
266
- return name === "ssr" || config.consumer === "server";
824
+ //#endregion
825
+ //#region ../internal/src/build/paths.ts
826
+ function generatedDirSegments(productName) {
827
+ return [".vitehub", productName];
828
+ }
829
+ function ensureGeneratedDir(rootDir, productName) {
830
+ return resolve$1(rootDir, ...generatedDirSegments(productName));
831
+ }
832
+ function computePackageDir(importMetaUrl) {
833
+ const currentFileDir = dirname$1(fileURLToPath(importMetaUrl));
834
+ return resolve$1(currentFileDir, basename$1(currentFileDir) === "internal" ? "../.." : "..");
835
+ }
836
+ function resolveRuntimeModule$1(packageDir, modulePath) {
837
+ const distFile = resolve$1(packageDir, "dist", `${modulePath}.js`);
838
+ return existsSync(distFile) ? distFile : resolve$1(packageDir, "src", `${modulePath}.ts`);
839
+ }
840
+ function createImportPath(fromFile, targetFile) {
841
+ const importPath = relative$1(realpathIfExists(dirname$1(fromFile)), realpathIfExists(targetFile));
842
+ return importPath.startsWith(".") ? importPath : `./${importPath}`;
843
+ }
844
+ function realpathIfExists(path) {
845
+ try {
846
+ return realpathSync.native(path);
847
+ } catch {
848
+ return resolve$1(path);
849
+ }
267
850
  }
268
851
  //#endregion
269
- //#region ../internal/src/build/cloudflare.ts
270
- const defaultCloudflareCompatibilityDate = "2026-04-20";
852
+ //#region ../internal/src/definition-catalog.ts
853
+ const sourceFilePattern$1 = /\.(?:c|m)?[jt]sx?$/i;
854
+ const declarationFilePattern$1 = /\.d\.(?:c|m)?[jt]sx?$/i;
855
+ const ignoredDirs = new Set([
856
+ "node_modules",
857
+ "dist",
858
+ ".output",
859
+ ".nuxt",
860
+ ".vercel",
861
+ ".git",
862
+ ".vitehub"
863
+ ]);
864
+ function resolveDefinitionScanRoots(rootDir, scanDirs = []) {
865
+ return [...new Set([rootDir, ...scanDirs].filter(Boolean))];
866
+ }
867
+ function createDirectoryDefinitionSource(source, scanDirs, subdir, options = {}) {
868
+ return {
869
+ ...options,
870
+ kind: "directory",
871
+ scanDirs,
872
+ source,
873
+ subdir
874
+ };
875
+ }
876
+ function createSuffixDefinitionSource(source, roots, pattern, normalizeName, options = {}) {
877
+ return {
878
+ ...options,
879
+ kind: "suffix",
880
+ normalizeName,
881
+ pattern,
882
+ roots,
883
+ source
884
+ };
885
+ }
886
+ function readDirEntries$1(root) {
887
+ try {
888
+ return readdirSync(root, { withFileTypes: true });
889
+ } catch (error) {
890
+ if (error.code === "ENOENT") return [];
891
+ throw error;
892
+ }
893
+ }
894
+ function listMatchingFiles(root, predicate, options = {}) {
895
+ const files = [];
896
+ for (const entry of readDirEntries$1(root)) {
897
+ const absolute = resolve$1(root, entry.name);
898
+ if (entry.isDirectory() && !entry.isSymbolicLink()) {
899
+ if (entry.name.startsWith(".")) continue;
900
+ if (ignoredDirs.has(entry.name)) continue;
901
+ files.push(...listMatchingFiles(absolute, predicate, options));
902
+ continue;
903
+ }
904
+ if (entry.name.startsWith(".") && !options.includeHidden) continue;
905
+ if (entry.isFile() && predicate(entry.name)) files.push(absolute);
906
+ }
907
+ return files.sort();
908
+ }
909
+ function listSourceFiles(root, options = {}) {
910
+ return listMatchingFiles(root, (name) => sourceFilePattern$1.test(name) && !declarationFilePattern$1.test(name), options);
911
+ }
912
+ function normalizePathDefinitionName(rootDir, file) {
913
+ return relative$1(rootDir, file).replace(sourceFilePattern$1, "").replace(/\/index$/i, "");
914
+ }
915
+ function normalizeSuffixDefinitionName(rootDir, file, pattern, options = {}) {
916
+ const normalized = relative$1(rootDir, file).replace(pattern, "");
917
+ if (options.stripPrefix && normalized.startsWith(options.stripPrefix)) return normalized.slice(options.stripPrefix.length);
918
+ return normalized;
919
+ }
920
+ function sortDefinitions(definitions) {
921
+ return [...definitions.values()].sort((left, right) => left.name.localeCompare(right.name));
922
+ }
923
+ function registerDefinition(definitions, definition, sourceLabel) {
924
+ const existing = definitions.get(definition.name);
925
+ if (existing) throw new Error(`Duplicate ${sourceLabel} name "${definition.name}":\n - ${existing.handler}\n - ${definition.handler}`);
926
+ definitions.set(definition.name, definition);
927
+ }
928
+ function mergeDefinitions(feature, ...sources) {
929
+ const definitions = /* @__PURE__ */ new Map();
930
+ for (const source of sources) {
931
+ if (!source) continue;
932
+ for (const definition of source) {
933
+ const existing = definitions.get(definition.name);
934
+ if (existing && existing.handler !== definition.handler) throw new Error(`Duplicate ${feature} name "${definition.name}" from multiple discovery sources:\n - ${existing.handler} (${existing.source ?? "unknown"})\n - ${definition.handler} (${definition.source ?? "unknown"})`);
935
+ if (!existing) definitions.set(definition.name, definition);
936
+ }
937
+ }
938
+ return sortDefinitions(definitions);
939
+ }
940
+ function createDefinition(source, file, name) {
941
+ if (source.createDefinition) return source.createDefinition({
942
+ file,
943
+ name
944
+ });
945
+ return {
946
+ handler: file,
947
+ name,
948
+ source: source.source
949
+ };
950
+ }
951
+ function scanSuffixDefinitions(feature, source) {
952
+ const definitions = /* @__PURE__ */ new Map();
953
+ for (const root of source.roots) for (const file of listMatchingFiles(root, (name) => source.pattern.test(name), { includeHidden: source.includeHidden })) {
954
+ const name = source.normalizeName(root, file);
955
+ if (!name) continue;
956
+ registerDefinition(definitions, createDefinition(source, file, name), feature);
957
+ }
958
+ return sortDefinitions(definitions);
959
+ }
960
+ function scanDirectoryDefinitions(feature, source) {
961
+ const definitions = /* @__PURE__ */ new Map();
962
+ for (const scanDir of source.scanDirs) {
963
+ const directory = resolve$1(scanDir, source.subdir);
964
+ for (const file of listSourceFiles(directory, { includeHidden: source.includeHidden })) {
965
+ const name = source.normalizeName ? source.normalizeName(directory, file) : normalizePathDefinitionName(directory, file);
966
+ if (!name) continue;
967
+ registerDefinition(definitions, createDefinition(source, file, name), feature);
968
+ }
969
+ }
970
+ return sortDefinitions(definitions);
971
+ }
972
+ function discoverDefinitions(feature, sources) {
973
+ return mergeDefinitions(feature, ...sources.map((source) => source.kind === "suffix" ? scanSuffixDefinitions(feature, source) : scanDirectoryDefinitions(feature, source)));
974
+ }
975
+ //#endregion
976
+ //#region ../internal/src/source-scanner.ts
977
+ function isQuote(char) {
978
+ return char === "\"" || char === "'" || char === "`";
979
+ }
980
+ function skipQuoted(source, index, controlFlowRegexes = /* @__PURE__ */ new Map()) {
981
+ const quote = source[index];
982
+ if (quote === "`") return skipTemplateLiteral(source, index, controlFlowRegexes);
983
+ index += 1;
984
+ while (index < source.length) {
985
+ if (source[index] === "\\") {
986
+ index += 2;
987
+ continue;
988
+ }
989
+ if (source[index] === quote) return index + 1;
990
+ index += 1;
991
+ }
992
+ return index;
993
+ }
994
+ function skipTemplateLiteral(source, index, controlFlowRegexes) {
995
+ index += 1;
996
+ let expressionDepth = 0;
997
+ let previousSignificant = "";
998
+ while (index < source.length) {
999
+ const char = source[index];
1000
+ const next = source[index + 1];
1001
+ if (char === "\\") {
1002
+ index += 2;
1003
+ continue;
1004
+ }
1005
+ if (expressionDepth === 0) {
1006
+ if (char === "`") return index + 1;
1007
+ if (char === "$" && next === "{") {
1008
+ expressionDepth = 1;
1009
+ previousSignificant = "{";
1010
+ index += 2;
1011
+ continue;
1012
+ }
1013
+ index += 1;
1014
+ continue;
1015
+ }
1016
+ if (char === "\"" || char === "'") {
1017
+ index = skipQuoted(source, index, controlFlowRegexes);
1018
+ previousSignificant = "literal";
1019
+ continue;
1020
+ }
1021
+ if (char === "`") {
1022
+ index = skipTemplateLiteral(source, index, controlFlowRegexes);
1023
+ previousSignificant = "literal";
1024
+ continue;
1025
+ }
1026
+ if (char === "/" && next === "/") {
1027
+ index = skipLineComment(source, index);
1028
+ continue;
1029
+ }
1030
+ if (char === "/" && next === "*") {
1031
+ index = skipBlockComment(source, index);
1032
+ continue;
1033
+ }
1034
+ if (char === "/" && (isRegexLiteralStart(previousSignificant) || isControlFlowRegexStart(source, index, controlFlowRegexes))) {
1035
+ index = skipRegexLiteral(source, index);
1036
+ previousSignificant = "/";
1037
+ continue;
1038
+ }
1039
+ if (char === "{") expressionDepth += 1;
1040
+ if (char === "}") expressionDepth -= 1;
1041
+ previousSignificant = trackSignificant(previousSignificant, char);
1042
+ index += 1;
1043
+ }
1044
+ return index;
1045
+ }
1046
+ function skipLineComment(source, index) {
1047
+ const end = source.indexOf("\n", index + 2);
1048
+ return end === -1 ? source.length : end + 1;
1049
+ }
1050
+ function skipBlockComment(source, index) {
1051
+ const end = source.indexOf("*/", index + 2);
1052
+ return end === -1 ? source.length : end + 2;
1053
+ }
1054
+ function isRegexLiteralStart(previousSignificant) {
1055
+ const token = previousSignificant.trimEnd();
1056
+ if (/^\.[\w$]+$/.test(token)) return false;
1057
+ return !token || /[({[=,:!&|?;>+\-*%^~]/.test(token) || /\b(?:await|case|delete|do|else|in|instanceof|return|throw|typeof|void|yield)$/.test(token);
1058
+ }
1059
+ function findLineCommentStart(source, start, end, controlFlowRegexes) {
1060
+ for (let index = start; index <= end;) {
1061
+ const char = source[index];
1062
+ const next = source[index + 1];
1063
+ if (isQuote(char)) {
1064
+ index = skipQuoted(source, index, controlFlowRegexes);
1065
+ continue;
1066
+ }
1067
+ if (char === "/" && next === "*") {
1068
+ index = skipBlockComment(source, index);
1069
+ continue;
1070
+ }
1071
+ if (char === "/" && next === "/") return index;
1072
+ index += 1;
1073
+ }
1074
+ return -1;
1075
+ }
1076
+ function previousCodeIndex(source, index, controlFlowRegexes) {
1077
+ let current = index;
1078
+ while (current >= 0) {
1079
+ while (/\s/.test(source[current] ?? "")) current--;
1080
+ if (source[current] === "/" && source[current - 1] === "*") {
1081
+ const start = source.lastIndexOf("/*", current - 2);
1082
+ if (start === -1) return current;
1083
+ current = start - 1;
1084
+ continue;
1085
+ }
1086
+ const lineStart = source.lastIndexOf("\n", current) + 1;
1087
+ const lineComment = findLineCommentStart(source, lineStart, current, controlFlowRegexes);
1088
+ if (lineComment !== -1 && lineComment <= current) {
1089
+ current = lineStart - 1;
1090
+ continue;
1091
+ }
1092
+ return current;
1093
+ }
1094
+ return current;
1095
+ }
1096
+ function isControlFlowRegexStart(source, index, controlFlowRegexes = /* @__PURE__ */ new Map()) {
1097
+ const cached = controlFlowRegexes.get(index);
1098
+ if (cached !== void 0) return cached;
1099
+ if (controlFlowRegexes.has(index)) return true;
1100
+ controlFlowRegexes.set(index, void 0);
1101
+ try {
1102
+ const closeParen = previousCodeIndex(source, index - 1, controlFlowRegexes);
1103
+ if (source[closeParen] !== ")") {
1104
+ controlFlowRegexes.set(index, false);
1105
+ return false;
1106
+ }
1107
+ for (let current = closeParen; current >= 0; current--) {
1108
+ if (source[current] !== "(") continue;
1109
+ if (findMatching(source, current, "(", ")", controlFlowRegexes) !== closeParen) continue;
1110
+ const head = source.slice(0, current).replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, " ");
1111
+ const result = /(?:^|[^\w$])(?:catch|for|if|while|with)\s*$/.test(head);
1112
+ controlFlowRegexes.set(index, result);
1113
+ return result;
1114
+ }
1115
+ controlFlowRegexes.set(index, false);
1116
+ return false;
1117
+ } catch (error) {
1118
+ controlFlowRegexes.delete(index);
1119
+ throw error;
1120
+ }
1121
+ }
1122
+ function skipRegexLiteral(source, index) {
1123
+ index += 1;
1124
+ while (index < source.length) {
1125
+ const char = source[index];
1126
+ if (char === "\\") {
1127
+ index += 2;
1128
+ continue;
1129
+ }
1130
+ if (char === "[") {
1131
+ index += 1;
1132
+ while (index < source.length) {
1133
+ if (source[index] === "\\") {
1134
+ index += 2;
1135
+ continue;
1136
+ }
1137
+ if (source[index] === "]") break;
1138
+ index += 1;
1139
+ }
1140
+ }
1141
+ if (char === "/") {
1142
+ index += 1;
1143
+ while (/[a-z]/i.test(source[index] ?? "")) index += 1;
1144
+ return index;
1145
+ }
1146
+ index += 1;
1147
+ }
1148
+ return index;
1149
+ }
1150
+ function trackSignificant(previousSignificant, char) {
1151
+ if (/[a-z$]/i.test(char ?? "")) return /[\w$]$/.test(previousSignificant) || previousSignificant === "." ? previousSignificant + char : char ?? "";
1152
+ if (/\s/.test(char ?? "")) return /[\w$]$/.test(previousSignificant) ? `${previousSignificant} ` : previousSignificant;
1153
+ if (!/\s/.test(char ?? "")) return char ?? "";
1154
+ return previousSignificant;
1155
+ }
1156
+ function maskSourceLiterals(source) {
1157
+ const output = source.split("");
1158
+ let previousSignificant = "";
1159
+ const mask = (start, end) => {
1160
+ for (let index = start; index < end; index++) if (output[index] !== "\n" && output[index] !== "\r") output[index] = " ";
1161
+ };
1162
+ for (let index = 0; index < source.length;) {
1163
+ const char = source[index];
1164
+ const next = source[index + 1];
1165
+ let end;
1166
+ if (isQuote(char)) {
1167
+ end = skipQuoted(source, index);
1168
+ previousSignificant = "literal";
1169
+ } else if (char === "/" && next === "/") end = skipLineComment(source, index);
1170
+ else if (char === "/" && next === "*") end = skipBlockComment(source, index);
1171
+ else if (char === "/" && (isRegexLiteralStart(previousSignificant) || isControlFlowRegexStart(source, index))) {
1172
+ end = skipRegexLiteral(source, index);
1173
+ previousSignificant = "/";
1174
+ }
1175
+ if (end !== void 0) {
1176
+ mask(index, end);
1177
+ index = end;
1178
+ continue;
1179
+ }
1180
+ previousSignificant = trackSignificant(previousSignificant, char);
1181
+ index += 1;
1182
+ }
1183
+ return output.join("");
1184
+ }
1185
+ function findMatching(source, index, open, close, controlFlowRegexes = /* @__PURE__ */ new Map()) {
1186
+ let depth = 0;
1187
+ let previousSignificant = "";
1188
+ for (let current = index; current < source.length; current++) {
1189
+ const char = source[current];
1190
+ const next = source[current + 1];
1191
+ if (isQuote(char)) {
1192
+ current = skipQuoted(source, current, controlFlowRegexes) - 1;
1193
+ previousSignificant = "literal";
1194
+ continue;
1195
+ }
1196
+ if (char === "/" && next === "/") {
1197
+ current = skipLineComment(source, current) - 1;
1198
+ continue;
1199
+ }
1200
+ if (char === "/" && next === "*") {
1201
+ current = skipBlockComment(source, current) - 1;
1202
+ continue;
1203
+ }
1204
+ if (char === "/" && (isRegexLiteralStart(previousSignificant) || isControlFlowRegexStart(source, current, controlFlowRegexes))) {
1205
+ current = skipRegexLiteral(source, current) - 1;
1206
+ previousSignificant = "/";
1207
+ continue;
1208
+ }
1209
+ if (char === open) {
1210
+ depth += 1;
1211
+ previousSignificant = char;
1212
+ continue;
1213
+ }
1214
+ if (char === close && !(open === "<" && close === ">" && source[current - 1] === "=")) {
1215
+ depth -= 1;
1216
+ if (depth === 0) return current;
1217
+ previousSignificant = char;
1218
+ continue;
1219
+ }
1220
+ previousSignificant = trackSignificant(previousSignificant, char);
1221
+ }
1222
+ }
1223
+ //#endregion
1224
+ //#region src/discovery.ts
1225
+ const workflowSuffixPattern = /\.workflow\.(?:c|m)?[jt]s$/i;
1226
+ const agentSuffixPattern = /\.agent\.(?:c|m)?[jt]s$/i;
1227
+ const sourceFilePattern = /\.(?:c|m)?[jt]s$/i;
1228
+ const declarationFilePattern = /\.d\.(?:c|m)?[jt]s$/i;
1229
+ const stepFilePattern = /^\d+[.-].*\.(?:c|m)?[jt]s$/i;
1230
+ const folderAgentFilePattern = /^agent\.(?:c|m)?[jt]s$/i;
1231
+ const folderAgentIndexFilePattern = /^index\.(?:c|m)?[jt]s$/i;
1232
+ const legacyFolderAgentFilePattern = /^config\.(?:c|m)?[jt]s$/i;
1233
+ const agentEvalFilePattern = /\.eval\.(?:c|m)?[jt]s$/i;
1234
+ function normalizeSuffixWorkflowName(rootDir, file) {
1235
+ return normalizeSuffixDefinitionName(rootDir, file, workflowSuffixPattern, { stripPrefix: "src/" });
1236
+ }
1237
+ function normalizeSuffixAgentName(rootDir, file) {
1238
+ const name = normalizeSuffixDefinitionName(rootDir, file, agentSuffixPattern, { stripPrefix: "src/" });
1239
+ return name.startsWith("server/") ? void 0 : name;
1240
+ }
1241
+ function readDirEntries(root) {
1242
+ try {
1243
+ return readdirSync(root, { withFileTypes: true });
1244
+ } catch (error) {
1245
+ if (error.code === "ENOENT") return [];
1246
+ throw error;
1247
+ }
1248
+ }
1249
+ function isSourceFile(file) {
1250
+ return sourceFilePattern.test(file) && !declarationFilePattern.test(file);
1251
+ }
1252
+ function findDefineAgentObjectStart(masked, start) {
1253
+ let index = start;
1254
+ while (/\s/.test(masked[index] || "")) index++;
1255
+ if (masked[index] === "<") {
1256
+ let depth = 0;
1257
+ do {
1258
+ if (masked[index] === "<") depth++;
1259
+ else if (masked[index] === ">" && masked[index - 1] !== "=") depth--;
1260
+ index++;
1261
+ } while (index < masked.length && depth > 0);
1262
+ }
1263
+ while (/\s/.test(masked[index] || "")) index++;
1264
+ if (masked[index++] !== "(") return void 0;
1265
+ while (/\s/.test(masked[index] || "")) index++;
1266
+ if (masked[index] === "{") return index;
1267
+ const options = /^([A-Za-z_$][\w$]*)\b/.exec(masked.slice(index))?.[1];
1268
+ if (options) {
1269
+ const declaration = new RegExp(`\\b(?:const|let|var)\\s+${options}\\s*(?::(?:=>|[^=])*?)?=\\s*\\{`).exec(masked);
1270
+ if (declaration) return declaration.index + declaration[0].lastIndexOf("{");
1271
+ }
1272
+ }
1273
+ function agentFactoryNames(source) {
1274
+ const names = new Set(["defineAgent"]);
1275
+ for (const match of source.matchAll(/\bimport\s*\{([^}]+)\}\s*from\s*["']@vite-hub\/agent["']/g)) for (const specifier of match[1].split(",")) {
1276
+ const alias = /^\s*defineAgent\s+as\s+([A-Za-z_$][\w$]*)\s*$/.exec(specifier)?.[1];
1277
+ if (alias) names.add(alias);
1278
+ }
1279
+ return [...names];
1280
+ }
1281
+ function findAgentObjectStart(source, masked) {
1282
+ for (const factory of agentFactoryNames(source)) {
1283
+ const inline = new RegExp(`\\bexport\\s+default\\s+${factory}\\b`).exec(masked);
1284
+ if (inline) return findDefineAgentObjectStart(masked, inline.index + inline[0].length);
1285
+ }
1286
+ const exported = /\bexport\s+default\s+([A-Za-z_$][\w$]*)\b/.exec(masked);
1287
+ if (!exported) return void 0;
1288
+ for (const factory of agentFactoryNames(source)) {
1289
+ const declaration = new RegExp(`\\b(?:const|let|var)\\s+${exported[1]}\\s*(?::(?:=>|[^=])*?)?=\\s*${factory}\\b`).exec(masked);
1290
+ if (declaration) return findDefineAgentObjectStart(masked, declaration.index + declaration[0].length);
1291
+ }
1292
+ }
1293
+ function hasExportedDefineAgent(source, masked) {
1294
+ if (agentFactoryNames(source).some((factory) => new RegExp(`\\bexport\\s+default\\s+${factory}\\b`).test(masked))) return true;
1295
+ const exported = /\bexport\s+default\s+([A-Za-z_$][\w$]*)\b/.exec(masked);
1296
+ return Boolean(exported && agentFactoryNames(source).some((factory) => new RegExp(`\\b(?:const|let|var)\\s+${exported[1]}\\s*(?::(?:=>|[^=])*?)?=\\s*${factory}\\b`).test(masked)));
1297
+ }
1298
+ function findUnmaskedSourceMatch(source, masked, pattern, prefix) {
1299
+ return [...source.matchAll(pattern)].find((match) => prefix.test(masked.slice(match.index)));
1300
+ }
1301
+ function resolveAgentReExport(file, source, masked) {
1302
+ const direct = findUnmaskedSourceMatch(source, masked, /\bexport\s+\{\s*default\s*\}\s+from\s*(["'])([^"']+)\1/g, /^export\s+\{\s*default\s*\}\s+from\b/);
1303
+ const exported = /\bexport\s+default\s+([A-Za-z_$][\w$]*)\b/.exec(masked);
1304
+ const imported = exported && findUnmaskedSourceMatch(source, masked, new RegExp(`\\bimport\\s+${exported[1]}\\s+from\\s*(["'])([^"']+)\\1`, "g"), /^import\b/);
1305
+ const specifier = direct?.[2] || imported?.[2];
1306
+ if (!specifier?.startsWith(".")) return void 0;
1307
+ const target = resolve$1(file, "..", specifier);
1308
+ const extensions = [
1309
+ ".ts",
1310
+ ".mts",
1311
+ ".cts",
1312
+ ".js",
1313
+ ".mjs",
1314
+ ".cjs"
1315
+ ];
1316
+ const sourceTarget = target.replace(/\.(?:c|m)?js$/i, "");
1317
+ for (const candidate of [
1318
+ target,
1319
+ ...extensions.map((extension) => `${target}${extension}`),
1320
+ ...extensions.map((extension) => `${sourceTarget}${extension}`),
1321
+ ...extensions.map((extension) => resolve$1(target, `index${extension}`))
1322
+ ]) if (existsSync(candidate) && statSync(candidate).isFile()) return candidate;
1323
+ }
1324
+ function isFolderAgentImplementationTarget(file) {
1325
+ const fileName = normalize(file).split("/").pop();
1326
+ if (/^definition\.(?:c|m)?[jt]s$/i.test(fileName)) return true;
1327
+ return /^index\.(?:c|m)?[jt]s$/i.test(fileName) && normalize(resolve$1(file, "../..")).split("/").pop() === "definition";
1328
+ }
1329
+ function extractAgentRuntime(file, seen = /* @__PURE__ */ new Set()) {
1330
+ if (seen.has(file)) return void 0;
1331
+ seen.add(file);
1332
+ const source = readFileSync(file, "utf8");
1333
+ const masked = maskSourceLiterals(source);
1334
+ const start = findAgentObjectStart(source, masked);
1335
+ if (start === void 0) {
1336
+ const target = resolveAgentReExport(file, source, masked);
1337
+ if (target) return extractAgentRuntime(target, seen);
1338
+ if (hasExportedDefineAgent(source, masked)) return {};
1339
+ return /\bexport\s+default\s+[A-Za-z_$][\w$]*Agent\b/.test(masked) ? {} : void 0;
1340
+ }
1341
+ let depth = 0;
1342
+ for (let index = start; index < masked.length; index++) if (masked[index] === "{") depth++;
1343
+ else if (masked[index] === "}" && --depth === 0) return {};
1344
+ else if (depth === 1) {
1345
+ const previous = masked.slice(0, index).trimEnd().at(-1);
1346
+ if ((previous === "{" || previous === ",") && /^runtime\s*(?:,|})/.test(masked.slice(index))) return {
1347
+ masked: "runtime",
1348
+ raw: "runtime"
1349
+ };
1350
+ if (!(/^runtime\s*:/.test(masked.slice(index)) || (previous === "{" || previous === ",") && /^["']runtime["']\s*:/.test(source.slice(index)))) continue;
1351
+ const colon = source.indexOf(":", index + 7);
1352
+ let end = colon + 1;
1353
+ let nested = 0;
1354
+ for (; end < masked.length; end++) if ("([{".includes(masked[end] || "")) nested++;
1355
+ else if (")]}".includes(masked[end] || "")) {
1356
+ if (nested === 0) break;
1357
+ nested--;
1358
+ } else if (masked[end] === "," && nested === 0) break;
1359
+ return {
1360
+ masked: masked.slice(colon + 1, end).trim(),
1361
+ raw: source.slice(colon + 1, end).trim()
1362
+ };
1363
+ }
1364
+ return {};
1365
+ }
1366
+ function extractAgentWorkflowName(file, fallbackName) {
1367
+ const runtime = extractAgentRuntime(file);
1368
+ if (!runtime) return void 0;
1369
+ const workflowPattern = /^(?:(?:\/\*[\s\S]*?\*\/|\/\/[^\n]*(?:\n|$))\s*)*workflow\s*\(\s*(?:(?:\/\*[\s\S]*?\*\/|\/\/[^\n]*(?:\n|$))\s*)*(["'`])([^"'`]+)\1\s*(?:(?:\/\*[\s\S]*?\*\/|\/\/[^\n]*(?:\n|$))\s*)*\)(?:\s*(?:\/\*[\s\S]*?\*\/|\/\/[^\n]*(?:\n|$)))*\s*$/;
1370
+ const match = workflowPattern.exec(runtime.raw || "");
1371
+ if (match) return match[2] || fallbackName;
1372
+ if (/^false(?:\s+as\s+const)?$/.test(runtime.masked || "")) return void 0;
1373
+ const shorthand = /^([A-Za-z_$][\w$]*)$/.exec(runtime.masked || "")?.[1];
1374
+ if (shorthand) {
1375
+ const source = readFileSync(file, "utf8");
1376
+ const masked = maskSourceLiterals(source);
1377
+ const declaration = new RegExp(`\\b(?:const|let|var)\\s+${shorthand}\\s*(?::(?:=>|[^=])*?)?=\\s*`).exec(masked);
1378
+ if (declaration) {
1379
+ const start = declaration.index + declaration[0].length;
1380
+ let end = start;
1381
+ let depth = 0;
1382
+ for (; end < masked.length; end++) if ("([{".includes(masked[end] || "")) depth++;
1383
+ else if (")]}".includes(masked[end] || "")) depth--;
1384
+ else if (depth === 0 && (masked[end] === ";" || masked[end] === "\n")) break;
1385
+ const initializer = source.slice(start, end).trim();
1386
+ if (/^false(?:\s+as\s+const)?$/.test(masked.slice(start, end).trim())) return void 0;
1387
+ const shorthandWorkflow = workflowPattern.exec(initializer);
1388
+ if (shorthandWorkflow) return shorthandWorkflow[2] || fallbackName;
1389
+ }
1390
+ }
1391
+ return fallbackName;
1392
+ }
1393
+ function toAgentWorkflowDefinition(file, fallbackName) {
1394
+ const name = extractAgentWorkflowName(file, fallbackName);
1395
+ return name ? {
1396
+ agentIdentity: fallbackName,
1397
+ handler: file,
1398
+ name,
1399
+ source: "agent-workflow"
1400
+ } : void 0;
1401
+ }
1402
+ function isWorkflowFolder(directory) {
1403
+ return readDirEntries(directory).some((entry) => entry.isFile() && (entry.name.toLowerCase().startsWith("index.") || stepFilePattern.test(entry.name)) && isSourceFile(entry.name));
1404
+ }
1405
+ function findWorkflowFolders(workflowsDir) {
1406
+ const folders = [];
1407
+ for (const entry of readDirEntries(workflowsDir)) {
1408
+ if (!entry.isDirectory() || entry.isSymbolicLink() || entry.name.startsWith(".")) continue;
1409
+ const directory = resolve$1(workflowsDir, entry.name);
1410
+ if (isWorkflowFolder(directory)) {
1411
+ folders.push(directory);
1412
+ continue;
1413
+ }
1414
+ folders.push(...findWorkflowFolders(directory));
1415
+ }
1416
+ return folders.sort();
1417
+ }
1418
+ function hasFolderAgentDefinition(directory) {
1419
+ return readDirEntries(directory).some((entry) => entry.isFile() && (folderAgentFilePattern.test(entry.name) || folderAgentIndexFilePattern.test(entry.name)) && isSourceFile(entry.name));
1420
+ }
1421
+ function findFolderAgentFiles(agentsDir) {
1422
+ const files = [];
1423
+ for (const entry of readDirEntries(agentsDir)) {
1424
+ if (entry.name.startsWith(".")) continue;
1425
+ const absolute = resolve$1(agentsDir, entry.name);
1426
+ if (entry.isDirectory() && !entry.isSymbolicLink()) {
1427
+ if ((entry.name === "workspace" || entry.name === "skills") && hasFolderAgentDefinition(agentsDir)) continue;
1428
+ files.push(...findFolderAgentFiles(absolute));
1429
+ continue;
1430
+ }
1431
+ if (entry.isFile() && (folderAgentFilePattern.test(entry.name) || folderAgentIndexFilePattern.test(entry.name)) && !(folderAgentIndexFilePattern.test(entry.name) && readDirEntries(agentsDir).some((sibling) => sibling.isFile() && folderAgentFilePattern.test(sibling.name))) && isSourceFile(entry.name)) files.push(absolute);
1432
+ }
1433
+ return files.sort();
1434
+ }
1435
+ function discoverSuffixAgentWorkflowDefinitions(roots) {
1436
+ return discoverDefinitions("agent workflow", [createSuffixDefinitionSource("agent-workflow", roots, agentSuffixPattern, normalizeSuffixAgentName, { createDefinition: ({ file, name }) => ({
1437
+ handler: file,
1438
+ name,
1439
+ source: "agent-workflow"
1440
+ }) })]).flatMap((definition) => {
1441
+ const workflowDefinition = toAgentWorkflowDefinition(definition.handler, definition.name);
1442
+ return workflowDefinition ? [workflowDefinition] : [];
1443
+ });
1444
+ }
1445
+ function discoverFlatServerAgentWorkflowDefinitions(scanDirs) {
1446
+ const folderAgentFiles = scanDirs.flatMap((scanDir) => findFolderAgentFiles(resolve$1(scanDir, "agents")));
1447
+ const folderAgentDirs = new Set(folderAgentFiles.map((file) => normalize(resolve$1(file, ".."))));
1448
+ const folderAgentTargets = new Set(folderAgentFiles.flatMap((file) => {
1449
+ const source = readFileSync(file, "utf8");
1450
+ const target = resolveAgentReExport(file, source, maskSourceLiterals(source));
1451
+ const relativeTarget = target && normalize(relative(resolve$1(file, ".."), target));
1452
+ return target && relativeTarget && relativeTarget !== ".." && !relativeTarget.startsWith("../") && isFolderAgentImplementationTarget(target) ? [normalize(target)] : [];
1453
+ }));
1454
+ return discoverDefinitions("agent workflow", [createDirectoryDefinitionSource("agent-workflow", scanDirs, "agents", {
1455
+ normalizeName(directory, file) {
1456
+ const fileName = normalize(file).split("/").pop();
1457
+ const parent = normalize(resolve$1(file, ".."));
1458
+ const name = normalizePathDefinitionName(directory, file);
1459
+ if (folderAgentTargets.has(normalize(file))) return void 0;
1460
+ if ([...folderAgentDirs].some((agentDir) => {
1461
+ const path = normalize(relative(agentDir, file));
1462
+ return path === "workspace" || path.startsWith("workspace/") || path === "skills" || path.startsWith("skills/");
1463
+ })) return void 0;
1464
+ if (folderAgentFilePattern.test(fileName) && parent !== normalize(directory) || legacyFolderAgentFilePattern.test(fileName) || agentEvalFilePattern.test(fileName)) return;
1465
+ if (parent !== normalize(directory) && hasFolderAgentDefinition(parent) && extractAgentWorkflowName(file, "__vitehub_agent_workflow__") === void 0) return;
1466
+ if (/^index\.(?:c|m)?[jt]s$/i.test(fileName) && hasFolderAgentDefinition(resolve$1(file, ".."))) return;
1467
+ return name;
1468
+ },
1469
+ createDefinition: ({ file, name }) => ({
1470
+ handler: file,
1471
+ name,
1472
+ source: "agent-workflow"
1473
+ })
1474
+ })]).flatMap((definition) => {
1475
+ const workflowDefinition = toAgentWorkflowDefinition(definition.handler, definition.name);
1476
+ return workflowDefinition ? [workflowDefinition] : [];
1477
+ });
1478
+ }
1479
+ function discoverConfiguredServerAgentWorkflowDefinitions(scanDirs) {
1480
+ const definitions = /* @__PURE__ */ new Map();
1481
+ for (const scanDir of scanDirs) {
1482
+ const agentsDir = resolve$1(scanDir, "agents");
1483
+ const files = findFolderAgentFiles(agentsDir);
1484
+ const targets = new Set(files.flatMap((file) => {
1485
+ const source = readFileSync(file, "utf8");
1486
+ const target = resolveAgentReExport(file, source, maskSourceLiterals(source));
1487
+ const relativeTarget = target && normalize(relative(resolve$1(file, ".."), target));
1488
+ return target && relativeTarget && relativeTarget !== ".." && !relativeTarget.startsWith("../") ? [normalize(target)] : [];
1489
+ }));
1490
+ for (const file of files) {
1491
+ if (targets.has(normalize(file))) continue;
1492
+ const name = normalize(relative(agentsDir, resolve$1(file, "..")));
1493
+ if (!name || name === ".") continue;
1494
+ const definition = toAgentWorkflowDefinition(file, name);
1495
+ if (definition) registerDefinition(definitions, definition, "agent workflow");
1496
+ }
1497
+ }
1498
+ return sortDefinitions(definitions);
1499
+ }
1500
+ function discoverAgentWorkflowDefinitions(roots, serverScanDirs) {
1501
+ return mergeDefinitions("agent workflow", discoverSuffixAgentWorkflowDefinitions(roots), discoverFlatServerAgentWorkflowDefinitions(serverScanDirs), discoverConfiguredServerAgentWorkflowDefinitions(serverScanDirs));
1502
+ }
1503
+ function discoverWorkflowFolders(scanDirs, source) {
1504
+ const definitions = /* @__PURE__ */ new Map();
1505
+ for (const scanDir of scanDirs) {
1506
+ const workflowsDir = resolve$1(scanDir, "workflows");
1507
+ for (const directory of findWorkflowFolders(workflowsDir)) {
1508
+ const files = readDirEntries(directory).filter((entry) => entry.isFile() && isSourceFile(entry.name)).map((entry) => resolve$1(directory, entry.name)).sort();
1509
+ const index = files.find((file) => /\/index\.(?:c|m)?[jt]s$/i.test(normalize(file)));
1510
+ const steps = files.filter((file) => stepFilePattern.test(file.split("/").pop()));
1511
+ if (!index && steps.length === 0) continue;
1512
+ const relativeName = normalize(relative(workflowsDir, directory));
1513
+ registerDefinition(definitions, {
1514
+ handler: index || directory,
1515
+ name: relativeName,
1516
+ source,
1517
+ steps
1518
+ }, "workflow");
1519
+ }
1520
+ }
1521
+ return sortDefinitions(definitions);
1522
+ }
1523
+ function discoverFlatServerWorkflowDefinitions(scanDirs, source) {
1524
+ return discoverDefinitions("workflow", [createDirectoryDefinitionSource("server-workflows", scanDirs, "workflows", {
1525
+ normalizeName(directory, file) {
1526
+ const normalizedFile = normalize(file);
1527
+ const parent = normalize(resolve$1(file, ".."));
1528
+ if (parent !== normalize(directory) && statSync(parent).isDirectory() && isWorkflowFolder(parent)) return;
1529
+ const fileName = normalizedFile.split("/").pop();
1530
+ if (fileName.toLowerCase().startsWith("index.") || stepFilePattern.test(fileName)) return;
1531
+ return normalizePathDefinitionName(directory, file);
1532
+ },
1533
+ createDefinition: ({ file, name }) => ({
1534
+ handler: file,
1535
+ name,
1536
+ source
1537
+ })
1538
+ })]);
1539
+ }
1540
+ function discoverWorkflowDefinitions(options) {
1541
+ if (options.mode === "server-workflows") return mergeDefinitions("workflow", discoverFlatServerWorkflowDefinitions(options.scanDirs, "server-workflows"), discoverWorkflowFolders(options.scanDirs, "server-workflows"));
1542
+ const roots = resolveDefinitionScanRoots(options.rootDir, options.scanDirs);
1543
+ const serverScanDirs = options.serverDirs ?? roots.map((root) => resolve$1(root, "server"));
1544
+ const folderDefinitions = discoverWorkflowFolders(serverScanDirs, "server-workflows");
1545
+ return mergeDefinitions("workflow", discoverDefinitions("workflow", [createSuffixDefinitionSource("vite-suffix", roots, workflowSuffixPattern, normalizeSuffixWorkflowName, { createDefinition: ({ file, name }) => ({
1546
+ handler: file,
1547
+ name,
1548
+ source: "vite-suffix"
1549
+ }) })]), discoverFlatServerWorkflowDefinitions(serverScanDirs, "server-workflows"), folderDefinitions, discoverAgentWorkflowDefinitions(roots, serverScanDirs));
1550
+ }
271
1551
  //#endregion
272
1552
  //#region src/internal/vite-build.ts
273
1553
  const workflowPackageName = "@vite-hub/workflow";
274
1554
  const productName = "workflow";
275
1555
  const generatedRegistryFileName = "registry.mjs";
1556
+ const cloudflareWorkflowWranglerConfigKeys = [
1557
+ "compatibility_date",
1558
+ "compatibility_flags",
1559
+ "main",
1560
+ "observability",
1561
+ "workflows"
1562
+ ];
1563
+ const cloudflareWorkflowWrapperImport = `import worker, { runViteHubWorkflowDefinition } from "./worker.mjs"`;
276
1564
  const packageDir = computePackageDir(import.meta.url);
277
1565
  const resolveRuntimeModule = (modulePath) => resolveRuntimeModule$1(packageDir, modulePath);
1566
+ const nodeBuiltinExternals = [...new Set([
1567
+ "node:*",
1568
+ ...builtinModules,
1569
+ ...builtinModules.map((module) => `node:${module}`)
1570
+ ])];
1571
+ const optionalAgentRuntimeExternals = ["@vite-hub/workspace", "@vite-hub/workspace/*"];
278
1572
  const WORKFLOW_ENTRY_BASE_NAMES = [
279
1573
  "server.ts",
280
1574
  "server.mts",
@@ -291,6 +1585,114 @@ const WORKFLOW_PRIORITY_NAMES = [
291
1585
  "server-workflow.js",
292
1586
  "server-workflow.mjs"
293
1587
  ];
1588
+ async function loadVercelWorkflowBuilders() {
1589
+ try {
1590
+ const require = createRequire(import.meta.url);
1591
+ require.resolve("workflow");
1592
+ require.resolve("@workflow/builders");
1593
+ } catch (error) {
1594
+ if (error.code === "MODULE_NOT_FOUND") return void 0;
1595
+ throw error;
1596
+ }
1597
+ return await import("@workflow/builders");
1598
+ }
1599
+ async function createVercelWorkflowTransformPlugin(rootDir) {
1600
+ const builders = await loadVercelWorkflowBuilders();
1601
+ if (!builders) return void 0;
1602
+ return builders.createSwcPlugin({
1603
+ mode: "workflow",
1604
+ projectRoot: rootDir
1605
+ });
1606
+ }
1607
+ async function withVercelWorkflowPackageLink(rootDir, run) {
1608
+ const target = join(rootDir, "node_modules", "workflow");
1609
+ if (existsSync(target)) return await run();
1610
+ const source = dirname(dirname(dirname(createRequire(import.meta.url).resolve("workflow/internal/builtins"))));
1611
+ await mkdir(dirname(target), { recursive: true });
1612
+ let ownsLink = false;
1613
+ try {
1614
+ await symlink(source, target, process.platform === "win32" ? "junction" : "dir");
1615
+ ownsLink = true;
1616
+ } catch (error) {
1617
+ if (error.code !== "EEXIST") throw error;
1618
+ }
1619
+ try {
1620
+ return await run();
1621
+ } finally {
1622
+ if (ownsLink) await rm(target, { force: true });
1623
+ }
1624
+ }
1625
+ async function buildVercelNativeWorkflowOutput(rootDir, definitions, aliases = {}) {
1626
+ const builders = await loadVercelWorkflowBuilders();
1627
+ if (!definitions.length) return;
1628
+ const definitionDirs = [...new Set(definitions.map((definition) => dirname(definition.handler)))];
1629
+ let hasNativeEntry = false;
1630
+ const visited = /* @__PURE__ */ new Set();
1631
+ const visit = (file) => {
1632
+ if (visited.has(file)) return;
1633
+ visited.add(file);
1634
+ if (!existsSync(file)) return;
1635
+ if (statSync(file).isDirectory()) {
1636
+ for (const entry of readdirSync(file, { withFileTypes: true })) {
1637
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
1638
+ if (entry.isDirectory() || /\.(?:c|m)?[jt]sx?$/.test(entry.name)) visit(join(file, entry.name));
1639
+ }
1640
+ return;
1641
+ }
1642
+ const source = readFileSync(file, "utf8");
1643
+ if (/^\s*["']use workflow["'];?/m.test(source)) {
1644
+ if (!definitionDirs.some((definitionDir) => {
1645
+ const path = relative(definitionDir, file);
1646
+ return !path.startsWith("..") && !isAbsolute(path);
1647
+ })) throw new Error(`Native Vercel workflow entry ${JSON.stringify(relative(rootDir, file))} must be colocated with its discovered workflow definition.`);
1648
+ hasNativeEntry = true;
1649
+ }
1650
+ for (const match of source.matchAll(/(?:from\s*|import\s*(?:\(\s*)?)["']([^"']+)["']/g)) {
1651
+ const specifier = match[1];
1652
+ const alias = Object.entries(aliases).find(([find]) => specifier === find || specifier.startsWith(`${find}/`));
1653
+ const imported = specifier.startsWith(".") ? resolve(dirname(file), specifier) : alias ? resolve(rootDir, specifier.replace(alias[0], alias[1])) : void 0;
1654
+ if (!imported) continue;
1655
+ const extensions = [
1656
+ ".ts",
1657
+ ".tsx",
1658
+ ".mts",
1659
+ ".cts",
1660
+ ".js",
1661
+ ".jsx",
1662
+ ".mjs",
1663
+ ".cjs"
1664
+ ];
1665
+ const sourceBase = imported.replace(/\.(?:m|c)?js$/, "");
1666
+ const candidate = [
1667
+ imported,
1668
+ ...extensions.map((extension) => `${sourceBase}${extension}`),
1669
+ ...extensions.map((extension) => join(imported, `index${extension}`))
1670
+ ].find((path) => existsSync(path) && statSync(path).isFile());
1671
+ if (candidate) visit(candidate);
1672
+ }
1673
+ };
1674
+ for (const definition of definitions) visit(definition.handler);
1675
+ if (!hasNativeEntry) return;
1676
+ if (!builders) throw new Error("Native Vercel workflows require the optional workflow and @workflow/builders peer dependencies.");
1677
+ const outputConfigFile = resolve(rootDir, ".vercel", "output", "config.json");
1678
+ const viteHubConfig = JSON.parse(await readFile(outputConfigFile, "utf8"));
1679
+ const builder = new builders.VercelBuildOutputAPIBuilder({
1680
+ buildTarget: "vercel-build-output-api",
1681
+ dirs: definitionDirs,
1682
+ projectRoot: rootDir,
1683
+ stepsBundlePath: "./.well-known/workflow/v1/step.js",
1684
+ webhookBundlePath: "./.well-known/workflow/v1/webhook.js",
1685
+ workflowsBundlePath: "./.well-known/workflow/v1/flow.js",
1686
+ workingDir: rootDir
1687
+ });
1688
+ await withVercelWorkflowPackageLink(rootDir, async () => await builder.build());
1689
+ const workflowConfig = JSON.parse(await readFile(outputConfigFile, "utf8"));
1690
+ await writeFile(outputConfigFile, `${JSON.stringify({
1691
+ ...workflowConfig,
1692
+ ...viteHubConfig,
1693
+ routes: [...workflowConfig.routes ?? [], ...viteHubConfig.routes ?? []]
1694
+ }, null, 2)}\n`, "utf8");
1695
+ }
294
1696
  function resolveWorkflowUserAppEntry(rootDir) {
295
1697
  return resolveUserAppEntry(rootDir, { names: getViteMode() === VITEHUB_MODES.workflow ? [...WORKFLOW_PRIORITY_NAMES, ...WORKFLOW_ENTRY_BASE_NAMES] : [...WORKFLOW_ENTRY_BASE_NAMES] });
296
1698
  }
@@ -310,10 +1712,160 @@ const providerEntrySpecs = [{
310
1712
  function resolveWorkflowConfig(workflow, hosting) {
311
1713
  return normalizeWorkflowOptions(workflow, { hosting }) ?? false;
312
1714
  }
1715
+ function renderRegistryImport(registryFile, file) {
1716
+ return `import(${JSON.stringify(createImportPath(registryFile, file))})`;
1717
+ }
1718
+ function resolveAgentWorkspaceSourceRoot(file) {
1719
+ const workspaceDirectory = join(dirname(file), "workspace");
1720
+ return existsSync(workspaceDirectory) && statSync(workspaceDirectory).isDirectory() ? workspaceDirectory : dirname(file);
1721
+ }
1722
+ function resolveInstructionFile(file, seen) {
1723
+ if (seen.has(file)) throw new Error(`[vitehub] Circular instruction import: ${file}.`);
1724
+ seen.add(file);
1725
+ try {
1726
+ const replaceImports = (content) => content.replace(/@(\.\.?\/\S+)/g, (_token, rawSpecifier) => {
1727
+ const trailing = rawSpecifier.match(/[.,;:!?)]*$/)?.[0] || "";
1728
+ const specifier = rawSpecifier.slice(0, rawSpecifier.length - trailing.length);
1729
+ return `${resolveInstructionFile(resolve(dirname(file), specifier), seen)}${trailing}`;
1730
+ });
1731
+ let fence;
1732
+ return readFileSync(file, "utf8").split(/(?<=\n)/).map((line) => {
1733
+ const marker = line.match(/^\s*(```|~~~)/)?.[1];
1734
+ if (marker) {
1735
+ fence = fence === marker ? void 0 : fence || marker;
1736
+ return line;
1737
+ }
1738
+ if (fence) return line;
1739
+ if (/^(?: {4}|\t)/.test(line)) return line;
1740
+ return line.split(/(`+[^`]*`+)/g).map((segment, index) => index % 2 ? segment : replaceImports(segment)).join("");
1741
+ }).join("");
1742
+ } finally {
1743
+ seen.delete(file);
1744
+ }
1745
+ }
1746
+ function readAgentInstructions(file) {
1747
+ const instructions = join(dirname(file), "instructions.md");
1748
+ return existsSync(instructions) && statSync(instructions).isFile() ? resolveInstructionFile(instructions, /* @__PURE__ */ new Set()) : void 0;
1749
+ }
1750
+ function readAgentSkills(file) {
1751
+ const files = readColocatedAgentFiles(file, "skills");
1752
+ if (!files) return;
1753
+ return Object.fromEntries(Object.entries(files).map(([path, source]) => {
1754
+ const workspacePath = `skills/${path}`;
1755
+ return [`__vitehubAgentSkill:${workspacePath}`, {
1756
+ ...source,
1757
+ materialize: "build",
1758
+ mount: "",
1759
+ workspacePath
1760
+ }];
1761
+ }));
1762
+ }
1763
+ function readAgentHome(file) {
1764
+ const files = readColocatedAgentFiles(file, "home", {
1765
+ fileCountLimit: 1024,
1766
+ fileSizeLimit: 1024 * 1024,
1767
+ label: "Colocated Agent Home",
1768
+ rejectUnsupportedEntries: true,
1769
+ totalSizeLimit: 4 * 1024 * 1024
1770
+ });
1771
+ if (!files) return;
1772
+ return Object.fromEntries(Object.entries(files).map(([target, source]) => [target, {
1773
+ contents: source.content,
1774
+ encoding: source.encoding
1775
+ }]));
1776
+ }
1777
+ function renderAgentWorkflowRegistryEntry(registryFile, definition) {
1778
+ return [
1779
+ ` ${JSON.stringify(definition.name)}: async () => {`,
1780
+ ` const cached = registryEntryCache.get(${JSON.stringify(definition.name)})`,
1781
+ " if (cached) return cached",
1782
+ ` const loaded = await ${renderRegistryImport(registryFile, definition.handler)}`,
1783
+ ` const agent = agentWithColocatedHome(agentWithColocatedSkills(workspaceAgentWithSourceRoot("default" in loaded ? loaded.default : loaded, ${JSON.stringify(resolveAgentWorkspaceSourceRoot(definition.handler))}, ${JSON.stringify(readAgentInstructions(definition.handler))}), ${JSON.stringify(readAgentSkills(definition.handler))}), ${JSON.stringify(readAgentHome(definition.handler))})`,
1784
+ ` const entry = { handler: async (context) => await runAgentWorkflowDefinition(agent, { ...context, payload: { ...context.payload, agentIdentity: context.payload?.agentIdentity || { name: ${JSON.stringify(definition.agentIdentity || definition.name)} } } }, runAgentInline) }`,
1785
+ ` registryEntryCache.set(${JSON.stringify(definition.name)}, entry)`,
1786
+ " return entry",
1787
+ " },"
1788
+ ].join("\n");
1789
+ }
1790
+ function renderWorkflowRegistryEntry(registryFile, definition) {
1791
+ if (definition.source === "agent-workflow") return renderAgentWorkflowRegistryEntry(registryFile, definition);
1792
+ if (!definition.steps?.length) return ` ${JSON.stringify(definition.name)}: async () => ${renderRegistryImport(registryFile, definition.handler)},`;
1793
+ const workflowDirectory = /\.(?:c|m)?[jt]s$/i.test(definition.handler) ? dirname(definition.handler) : definition.handler;
1794
+ const stepImports = definition.steps.map((step) => {
1795
+ const stepName = relative(workflowDirectory, step);
1796
+ return `{ name: ${JSON.stringify(stepName)}, run: (await ${renderRegistryImport(registryFile, step)}).default }`;
1797
+ });
1798
+ const hasIndex = /\.(?:c|m)?[jt]s$/i.test(definition.handler);
1799
+ const indexImport = hasIndex ? `const index = await ${renderRegistryImport(registryFile, definition.handler)}` : "";
1800
+ const handler = hasIndex ? `index.default?.handler ? index.default : takeInlineWorkflowDefinitionForModule(${JSON.stringify(definition.name)}, index) || { handler: index.default }` : "{ handler: async (context) => { let value = context.payload; for (const step of Object.values(context.steps || {})) value = await step(value); return value } }";
1801
+ return [
1802
+ ` ${JSON.stringify(definition.name)}: async () => {`,
1803
+ ` const cached = registryEntryCache.get(${JSON.stringify(definition.name)})`,
1804
+ " if (cached) return cached",
1805
+ indexImport ? ` ${indexImport}` : "",
1806
+ ` const steps = [${stepImports.join(", ")}]`,
1807
+ ` const definition = ${handler}`,
1808
+ " const entry = {",
1809
+ " ...definition,",
1810
+ " options: { ...definition.options, rootStep: false },",
1811
+ " handler: async (context) => {",
1812
+ " const workflowSteps = createWorkflowSteps(context, steps)",
1813
+ " return await definition.handler({ ...context, steps: workflowSteps })",
1814
+ " },",
1815
+ " }",
1816
+ ` registryEntryCache.set(${JSON.stringify(definition.name)}, entry)`,
1817
+ " return entry",
1818
+ " },"
1819
+ ].filter(Boolean).join("\n");
1820
+ }
1821
+ function createWorkflowRegistryContents(registryFile, definitions, importBases = {}) {
1822
+ const agentImportBase = importBases.agent ?? "@vite-hub/agent";
1823
+ const workflowImportBase = importBases.workflow ?? "@vite-hub/workflow";
1824
+ const needsWorkflowRuntime = definitions.some((definition) => definition.steps?.length);
1825
+ const needsAgentRuntime = definitions.some((definition) => definition.source === "agent-workflow");
1826
+ const needsRegistryEntryCache = needsWorkflowRuntime || needsAgentRuntime;
1827
+ const installAgentWorkflowRuntime = needsAgentRuntime && importBases.workflow;
1828
+ const workspaceDependencyRuntimeImports = importBases.workspace ? importBases.workspaceDependencies : void 0;
1829
+ const imports = [
1830
+ ...needsAgentRuntime ? [
1831
+ `import { runAgentInline } from ${JSON.stringify(agentImportBase)}`,
1832
+ `import { agentWithColocatedHome, agentWithColocatedSkills, runAgentWorkflowDefinition, workspaceAgentWithSourceRoot } from ${JSON.stringify(`${agentImportBase}/runtime/workflow`)}`,
1833
+ ...installAgentWorkflowRuntime ? [`import { setAgentWorkflowRuntimeLoaders } from ${JSON.stringify(`${agentImportBase}/server/internal`)}`] : []
1834
+ ] : [],
1835
+ ...needsWorkflowRuntime ? [`import { createWorkflowSteps } from ${JSON.stringify(`${workflowImportBase}/runtime/execute`)}`, `import { takeInlineWorkflowDefinitionForModule } from ${JSON.stringify(`${workflowImportBase}/runtime/state`)}`] : [],
1836
+ ...workspaceDependencyRuntimeImports ? [`import { setWorkspaceDependencyRuntimeLoaders } from ${JSON.stringify(`${importBases.workspace}/runtime`)}`] : []
1837
+ ];
1838
+ return [
1839
+ ...imports,
1840
+ imports.length ? "" : "",
1841
+ ...installAgentWorkflowRuntime ? [
1842
+ "setAgentWorkflowRuntimeLoaders({",
1843
+ ` state: () => import(${JSON.stringify(`${importBases.workflow}/runtime/state`)}),`,
1844
+ ` workflow: () => import(${JSON.stringify(importBases.workflow)}),`,
1845
+ "})",
1846
+ ""
1847
+ ] : [],
1848
+ ...workspaceDependencyRuntimeImports ? [
1849
+ "setWorkspaceDependencyRuntimeLoaders({",
1850
+ ...workspaceDependencyRuntimeImports.sandbox ? [` sandbox: () => import(${JSON.stringify(workspaceDependencyRuntimeImports.sandbox)}),`] : [],
1851
+ ...workspaceDependencyRuntimeImports.sandboxRuntimeState ? [` sandboxRuntimeState: () => import(${JSON.stringify(workspaceDependencyRuntimeImports.sandboxRuntimeState)}),`] : [],
1852
+ ...workspaceDependencyRuntimeImports.shellWorkspace ? [` shellWorkspace: () => import(${JSON.stringify(workspaceDependencyRuntimeImports.shellWorkspace)}),`] : [],
1853
+ "})",
1854
+ ""
1855
+ ] : [],
1856
+ ...needsRegistryEntryCache ? ["const registryEntryCache = new Map()", ""] : [],
1857
+ "const registry = {",
1858
+ ...definitions.map((definition) => renderWorkflowRegistryEntry(registryFile, definition)),
1859
+ "}",
1860
+ "",
1861
+ "export default registry",
1862
+ ""
1863
+ ].join("\n");
1864
+ }
313
1865
  function renderCloudflareWorkerWrapper(definitions) {
314
1866
  return [
315
1867
  definitions.length ? `import { WorkflowEntrypoint, waitUntil as viteHubWaitUntil } from "cloudflare:workers"` : `import { waitUntil as viteHubWaitUntil } from "cloudflare:workers"`,
316
- `import worker, { runViteHubWorkflowDefinition } from "./worker.mjs"`,
1868
+ cloudflareWorkflowWrapperImport,
317
1869
  "",
318
1870
  ...definitions.map((definition) => {
319
1871
  return [
@@ -336,8 +1888,13 @@ function renderCloudflareWorkerWrapper(definitions) {
336
1888
  ""
337
1889
  ].join("\n");
338
1890
  }
339
- function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowConfig) {
340
- const imports = [`import { ${spec.factory} } from ${JSON.stringify(createImportPath(entryFile, resolveRuntimeModule(spec.runtimeModule)))}`, `import workflowRegistry from ${JSON.stringify(`./${generatedRegistryFileName}`)}`];
1891
+ function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowConfig, framework) {
1892
+ const installVercelWorkflowRuntime = spec.name === "vercel" && framework;
1893
+ const imports = [
1894
+ `import { ${spec.factory}${installVercelWorkflowRuntime ? ", setVercelWorkflowRuntimeModules" : ""} } from ${JSON.stringify(createImportPath(entryFile, resolveRuntimeModule(spec.runtimeModule)))}`,
1895
+ `import workflowRegistry from ${JSON.stringify(`./${generatedRegistryFileName}`)}`,
1896
+ ...installVercelWorkflowRuntime ? [`import * as workflowApi from "workflow/api"`, `import * as workflowRuntime from "workflow/runtime"`] : []
1897
+ ];
341
1898
  if (spec.name === "cloudflare") imports.push(`import { runCloudflareWorkflow } from ${JSON.stringify(createImportPath(entryFile, resolveRuntimeModule("runtime/cloudflare-runner")))}`);
342
1899
  if (userAppEntry) imports.push(`import workflowApp from ${JSON.stringify(createImportPath(entryFile, userAppEntry))}`);
343
1900
  const cloudflareDispatcher = spec.name === "cloudflare" ? [
@@ -349,6 +1906,7 @@ function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowCo
349
1906
  return [
350
1907
  ...imports,
351
1908
  "",
1909
+ installVercelWorkflowRuntime ? "setVercelWorkflowRuntimeModules(workflowApi, workflowRuntime)" : "",
352
1910
  `const workflowConfig = ${serializedWorkflowConfig}`,
353
1911
  ...cloudflareDispatcher,
354
1912
  "",
@@ -360,15 +1918,18 @@ function renderProviderEntry(spec, entryFile, userAppEntry, serializedWorkflowCo
360
1918
  ""
361
1919
  ].filter(Boolean).join("\n");
362
1920
  }
363
- async function writeProviderEntries(rootDir, workflow) {
1921
+ async function writeProviderEntries(rootDir, workflow, importBases = {}, serverDirs) {
364
1922
  const generatedDir = ensureGeneratedDir(rootDir, productName);
365
1923
  await mkdir(generatedDir, { recursive: true });
366
1924
  const registryFile = resolve(generatedDir, generatedRegistryFileName);
367
- const definitions = discoverWorkflowDefinitions({ rootDir });
1925
+ const definitions = discoverWorkflowDefinitions({
1926
+ rootDir,
1927
+ serverDirs
1928
+ });
368
1929
  const providerDefinitions = definitions;
369
1930
  const userAppEntry = resolveWorkflowUserAppEntry(rootDir);
370
1931
  const cloudflareWorkflowConfig = resolveWorkflowConfig(workflow, "cloudflare");
371
- await writeFile(registryFile, createRuntimeRegistryContents(registryFile, definitions), "utf8");
1932
+ await writeFile(registryFile, createWorkflowRegistryContents(registryFile, definitions, importBases), "utf8");
372
1933
  const entryFiles = {
373
1934
  cloudflare: "",
374
1935
  openworkflow: "",
@@ -377,7 +1938,7 @@ async function writeProviderEntries(rootDir, workflow) {
377
1938
  await Promise.all(providerEntrySpecs.map(async (spec) => {
378
1939
  const entryFile = resolve(generatedDir, spec.entryFile);
379
1940
  const workflowConfig = spec.name === "cloudflare" ? cloudflareWorkflowConfig : resolveWorkflowConfig(workflow, spec.hosting);
380
- await writeFile(entryFile, renderProviderEntry(spec, entryFile, userAppEntry, JSON.stringify(workflowConfig, null, 2)), "utf8");
1941
+ await writeFile(entryFile, renderProviderEntry(spec, entryFile, userAppEntry, JSON.stringify(workflowConfig, null, 2), Boolean(importBases.workflow)), "utf8");
381
1942
  entryFiles[spec.name] = entryFile;
382
1943
  }));
383
1944
  return {
@@ -390,7 +1951,7 @@ async function writeProviderEntries(rootDir, workflow) {
390
1951
  vercelServerFile: entryFiles.vercel
391
1952
  };
392
1953
  }
393
- function createCloudflareOutput(rootDir, artifacts) {
1954
+ function createCloudflareOutput(rootDir, artifacts, providerImportAliases) {
394
1955
  const workflowConfig = artifacts.cloudflareWorkflowConfig && artifacts.cloudflareWorkflowConfig.provider === "cloudflare" ? artifacts.cloudflareWorkflowConfig : false;
395
1956
  const workflows = createCloudflareWorkflowBindings(workflowConfig ? artifacts.providerDefinitions : [], workflowConfig);
396
1957
  const wranglerConfig = {
@@ -403,6 +1964,7 @@ function createCloudflareOutput(rootDir, artifacts) {
403
1964
  return {
404
1965
  bundleEntry: artifacts.cloudflareWorkerFile,
405
1966
  bundleOptions: {
1967
+ alias: providerImportAliases,
406
1968
  conditions: [
407
1969
  "workerd",
408
1970
  "worker",
@@ -416,7 +1978,7 @@ function createCloudflareOutput(rootDir, artifacts) {
416
1978
  "@vercel/queue",
417
1979
  "@vercel/sandbox",
418
1980
  "cloudflare:workers",
419
- "node:async_hooks",
1981
+ ...nodeBuiltinExternals,
420
1982
  "workflow",
421
1983
  "workflow/api",
422
1984
  "workflow/runtime"
@@ -425,61 +1987,99 @@ function createCloudflareOutput(rootDir, artifacts) {
425
1987
  platform: "neutral"
426
1988
  },
427
1989
  bundleOutfileName: "worker.mjs",
1990
+ files: { "index.js": createCloudflareWorkflowWrapper(artifacts) },
428
1991
  outputRoot: createDefaultCloudflareOutputRoot(rootDir),
429
- wranglerConfigKeys: ["workflows"],
1992
+ wranglerConfigKeys: cloudflareWorkflowWranglerConfigKeys,
430
1993
  wranglerConfig
431
1994
  };
432
1995
  }
433
- async function writeCloudflareWorkflowWrapper(rootDir, artifacts) {
1996
+ function createCloudflareWorkflowWrapper(artifacts) {
1997
+ return renderCloudflareWorkerWrapper((artifacts.cloudflareWorkflowConfig && artifacts.cloudflareWorkflowConfig.provider === "cloudflare" ? artifacts.cloudflareWorkflowConfig : false) ? artifacts.providerDefinitions : []);
1998
+ }
1999
+ async function createCloudflareWorkflowCleanup(rootDir) {
434
2000
  const outputRoot = createDefaultCloudflareOutputRoot(rootDir);
435
- const workflowDefinitions = (artifacts.cloudflareWorkflowConfig && artifacts.cloudflareWorkflowConfig.provider === "cloudflare" ? artifacts.cloudflareWorkflowConfig : false) ? artifacts.providerDefinitions : [];
436
- await writeFile(resolve(outputRoot, "index.js"), renderCloudflareWorkerWrapper(workflowDefinitions), "utf8");
2001
+ let ownsWrapper = false;
2002
+ try {
2003
+ ownsWrapper = (await readFile(resolve(outputRoot, "index.js"), "utf8")).includes(cloudflareWorkflowWrapperImport);
2004
+ } catch (error) {
2005
+ if (error.code !== "ENOENT") throw error;
2006
+ }
2007
+ return {
2008
+ fileNames: ownsWrapper ? ["index.js", "worker.mjs"] : ["worker.mjs"],
2009
+ outputRoot,
2010
+ wranglerConfigOwnership: { keys: ownsWrapper ? cloudflareWorkflowWranglerConfigKeys : ["workflows"] }
2011
+ };
437
2012
  }
438
- function createVercelOutput(artifacts) {
2013
+ function createVercelOutput(artifacts, workflowTransformPlugin, frameworkImportBase, providerImportAliases, serverFunctionName) {
439
2014
  return {
440
2015
  bundleEntry: artifacts.vercelServerFile,
441
2016
  bundleOptions: {
2017
+ alias: providerImportAliases,
442
2018
  external: [
443
2019
  "@cloudflare/sandbox",
2020
+ ...frameworkImportBase ? [] : optionalAgentRuntimeExternals,
444
2021
  "cloudflare:workers",
445
- "workflow",
446
- "workflow/api",
447
- "workflow/runtime"
2022
+ ...nodeBuiltinExternals,
2023
+ ...!frameworkImportBase ? [
2024
+ "workflow",
2025
+ "workflow/api",
2026
+ "workflow/runtime"
2027
+ ] : []
448
2028
  ],
449
2029
  format: "esm",
450
- platform: "node"
451
- }
2030
+ platform: "node",
2031
+ plugins: workflowTransformPlugin ? [workflowTransformPlugin] : []
2032
+ },
2033
+ ...serverFunctionName ? { function: {
2034
+ kind: "isolated",
2035
+ name: serverFunctionName
2036
+ } } : {}
452
2037
  };
453
2038
  }
454
2039
  async function generateProviderOutputs(options) {
455
- const artifacts = await writeProviderEntries(options.rootDir, options.workflow);
2040
+ const artifacts = await writeProviderEntries(options.rootDir, options.workflow, {
2041
+ agent: options.agentImportBase,
2042
+ workflow: options.importBase,
2043
+ workspace: options.workspaceImportBase,
2044
+ workspaceDependencies: options.workspaceDependencyRuntimeImports
2045
+ }, options.serverDirs);
456
2046
  const cloudflareWorkflowConfig = resolveWorkflowConfig(options.workflow, "cloudflare");
457
2047
  const vercelWorkflowConfig = resolveWorkflowConfig(options.workflow, "vercel");
458
- await writeProviderDeploymentOutputs({
459
- clientOutDir: options.clientOutDir,
460
- ...cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare" ? { cloudflare: createCloudflareOutput(options.rootDir, artifacts) } : {},
461
- cleanup: { cloudflare: {
462
- bundleOutfileName: "worker.mjs",
463
- outputRoot: createDefaultCloudflareOutputRoot(options.rootDir),
464
- wranglerConfigKeys: ["workflows"]
465
- } },
466
- rootDir: options.rootDir,
467
- ...vercelWorkflowConfig && vercelWorkflowConfig.provider === "vercel" ? { vercel: createVercelOutput(artifacts) } : {}
468
- });
469
- if (cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare") await writeCloudflareWorkflowWrapper(options.rootDir, artifacts);
2048
+ const cloudflareOutput = cloudflareWorkflowConfig && cloudflareWorkflowConfig.provider === "cloudflare" ? createCloudflareOutput(options.rootDir, artifacts, options.providerImportAliases) : void 0;
2049
+ const workflowTransformPlugin = vercelWorkflowConfig && vercelWorkflowConfig.provider === "vercel" ? await createVercelWorkflowTransformPlugin(options.rootDir) : void 0;
2050
+ const vercelOutput = vercelWorkflowConfig && vercelWorkflowConfig.provider === "vercel" ? createVercelOutput(artifacts, workflowTransformPlugin, options.importBase, options.providerImportAliases, options.serverFunctionName) : void 0;
2051
+ const writeOutputs = async () => {
2052
+ await writeProviderDeploymentOutputs({
2053
+ clientOutDir: options.clientOutDir,
2054
+ cloudflare: cloudflareOutput,
2055
+ cleanup: { cloudflare: cloudflareOutput ? void 0 : () => createCloudflareWorkflowCleanup(options.rootDir) },
2056
+ rootDir: options.rootDir,
2057
+ ...vercelOutput ? { vercel: vercelOutput } : {}
2058
+ });
2059
+ if (vercelOutput) await buildVercelNativeWorkflowOutput(options.rootDir, artifacts.providerDefinitions, options.providerImportAliases);
2060
+ };
2061
+ if (workflowTransformPlugin && options.importBase) await withVercelWorkflowPackageLink(options.rootDir, writeOutputs);
2062
+ else await writeOutputs();
470
2063
  return artifacts;
471
2064
  }
472
2065
  //#endregion
473
2066
  //#region src/vite.ts
474
2067
  const mergeNoExternal = createNoExternalMerger(workflowPackageName);
2068
+ function resolveStringAliases(config) {
2069
+ const aliases = {};
2070
+ for (const alias of config.resolve.alias) if (typeof alias.find === "string" && typeof alias.replacement === "string") aliases[alias.find] = alias.replacement;
2071
+ return aliases;
2072
+ }
475
2073
  function hubWorkflow(options) {
2074
+ const internalOptions = options;
476
2075
  let resolved;
477
2076
  let workflow = options;
2077
+ let serverDirs;
478
2078
  return {
479
2079
  name: "@vite-hub/workflow/vite",
480
- nitro: workflowNitroModule,
481
2080
  config(config) {
482
2081
  workflow = config.workflow ?? workflow;
2082
+ serverDirs = config["__vitehubServerDirs"] ?? serverDirs;
483
2083
  },
484
2084
  configResolved(config) {
485
2085
  resolved = config;
@@ -492,9 +2092,19 @@ function hubWorkflow(options) {
492
2092
  async closeBundle() {
493
2093
  if (!resolved || shouldSkipViteProviderBuild(resolved.command, getViteMode())) return;
494
2094
  await generateProviderOutputs({
2095
+ agentImportBase: internalOptions?.agentImportBase,
495
2096
  clientOutDir: resolved.build.outDir,
2097
+ importBase: internalOptions?.importBase,
2098
+ providerImportAliases: {
2099
+ ...resolveStringAliases(resolved),
2100
+ ...internalOptions?.providerImportAliases
2101
+ },
496
2102
  rootDir: resolved.root,
497
- workflow
2103
+ serverDirs,
2104
+ serverFunctionName: resolveNitroVercelFunctionName(resolved, "workflow"),
2105
+ workflow,
2106
+ workspaceDependencyRuntimeImports: internalOptions?.workspaceDependencyRuntimeImports,
2107
+ workspaceImportBase: internalOptions?.workspaceImportBase
498
2108
  });
499
2109
  }
500
2110
  };