@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.
- package/README.md +56 -6
- package/dist/{cloudflare-env-BVUMOgFK.d.ts → cloudflare-env-CIjdFTv6.d.ts} +2 -1
- package/dist/{cloudflare-env-g0Rf3ClH.js → cloudflare-env-mFp2Uj6Z.js} +7 -3
- package/dist/{cloudflare-vite-DcM5YVTP.js → cloudflare-vite-B0zel2Do.js} +4 -5
- package/dist/{config-DkgsQuXz.js → config-BDqB6I4E.js} +43 -5
- package/dist/index.d.ts +43 -18
- package/dist/index.js +99 -111
- package/dist/provider-operation-CWIV4k42.js +62 -0
- package/dist/runtime/cloudflare-runner.d.ts +2 -2
- package/dist/runtime/cloudflare-runner.js +15 -14
- package/dist/runtime/cloudflare-shared.d.ts +2 -2
- package/dist/runtime/cloudflare-shared.js +2 -2
- package/dist/runtime/cloudflare-vite.d.ts +3 -3
- package/dist/runtime/cloudflare-vite.js +1 -1
- package/dist/runtime/execute.d.ts +1 -1
- package/dist/runtime/openworkflow-worker.d.ts +4 -2
- package/dist/runtime/openworkflow-worker.js +63 -6
- package/dist/runtime/openworkflow.d.ts +22 -1
- package/dist/runtime/openworkflow.js +110 -37
- package/dist/runtime/state.d.ts +1 -1
- package/dist/runtime/vercel-vite.d.ts +58 -3
- package/dist/runtime/vercel-vite.js +3 -2
- package/dist/{types-ThDitg7Z.d.ts → types-BUlYBZwH.d.ts} +48 -6
- package/dist/vercel-D2_J5D_Y.js +217 -0
- package/dist/vite.d.ts +2 -5
- package/dist/vite.js +1753 -143
- package/package.json +45 -48
- package/dist/module-UYEnVfxy.js +0 -1546
- package/dist/nitro.d.ts +0 -19
- package/dist/nitro.js +0 -2
- package/dist/openworkflow-amN7IkGO.d.ts +0 -24
- package/dist/runtime/nitro-plugin.d.ts +0 -6
- package/dist/runtime/nitro-plugin.js +0 -14
- /package/dist/{_app-BVWpnNHo.d.ts → _app-DgwN4ulW.d.ts} +0 -0
- /package/dist/{app-BE3EYOWn.js → app-BZpq2cwC.js} +0 -0
- /package/dist/{cloudflare-CeHVSHoN.js → cloudflare-Cds1VIWa.js} +0 -0
- /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-
|
|
2
|
-
import { r as getCloudflareWorkflowClassName, t as createCloudflareWorkflowBindings } from "./cloudflare-
|
|
3
|
-
import {
|
|
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/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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
|
|
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(
|
|
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(
|
|
718
|
+
writes.push(cleanProviderOutputConfig(resolve(outputRoot, "config.json"), { keys: cleanup.configKeys }));
|
|
237
719
|
await Promise.all(writes);
|
|
238
720
|
}
|
|
239
|
-
async function
|
|
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)
|
|
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/
|
|
257
|
-
function
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
266
|
-
|
|
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/
|
|
270
|
-
const
|
|
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
|
-
|
|
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
|
|
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({
|
|
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,
|
|
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
|
-
|
|
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:
|
|
1992
|
+
wranglerConfigKeys: cloudflareWorkflowWranglerConfigKeys,
|
|
430
1993
|
wranglerConfig
|
|
431
1994
|
};
|
|
432
1995
|
}
|
|
433
|
-
|
|
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
|
-
|
|
436
|
-
|
|
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
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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
|
-
|
|
2103
|
+
serverDirs,
|
|
2104
|
+
serverFunctionName: resolveNitroVercelFunctionName(resolved, "workflow"),
|
|
2105
|
+
workflow,
|
|
2106
|
+
workspaceDependencyRuntimeImports: internalOptions?.workspaceDependencyRuntimeImports,
|
|
2107
|
+
workspaceImportBase: internalOptions?.workspaceImportBase
|
|
498
2108
|
});
|
|
499
2109
|
}
|
|
500
2110
|
};
|